rizin/librz/include/rz_util/rz_str.h

347 lines
18 KiB
C

#ifndef RZ_STR_H
#define RZ_STR_H
#include <wchar.h>
#include "rz_assert.h"
#include "rz_str_util.h"
#include "rz_list.h"
#include <rz_vector.h>
#include "rz_types.h"
#include "rz_strbuf.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
RZ_STRING_TYPE_RAW, ///< The raw sequence of bytes without any marker of beginning or end
RZ_STRING_TYPE_ZERO, ///< C-style strings (ASCII or UTF-8) with zero as the end marker
RZ_STRING_TYPE_SIZED, ///< Pascal-style strings with the first byte marking the size of the string
} RzStrType;
/**
* \brief String character encodings.
*/
typedef enum {
/**
* \brief Unknown 8bit encoding but with ASCII from 0 to 0x7f.
* It is also used everywhere like it is ASCII.
*/
RZ_STRING_ENC_8BIT = 'b',
RZ_STRING_ENC_UTF8 = '8',
/**
* \brief Modified UTF-8 from Android:
* https://source.android.com/docs/core/runtime/dex-format#mutf-8
*/
RZ_STRING_ENC_MUTF8 = 'm',
RZ_STRING_ENC_UTF16LE = 'u',
RZ_STRING_ENC_UTF32LE = 'U',
RZ_STRING_ENC_UTF16BE = 'n',
RZ_STRING_ENC_UTF32BE = 'N',
RZ_STRING_ENC_IBM037 = 'c',
RZ_STRING_ENC_IBM290 = 'd',
RZ_STRING_ENC_EBCDIC_UK = 'k',
RZ_STRING_ENC_EBCDIC_US = 's',
RZ_STRING_ENC_EBCDIC_ES = 't',
RZ_STRING_ENC_GUESS = 'g',
RZ_STRING_ENC_SETTINGS = 'S', ///< Use str.encoding.
} RzStrEnc;
/**
* \brief Group together some common options used by string escaping functions
*/
typedef struct {
bool show_asciidot; ///< When true, dots `.` are placed instead of unprintable ASCII characters.
bool esc_bslash; ///< When true, backslashes `\` are quoted with `\\`
bool esc_double_quotes; ///< When true, double quotes `"` are quoted with `\"`
bool dot_nl; ///< When true, \n is converted into the graphiz-compatible newline \l
bool keep_printable; ///< Keep all printable characters (excludes \n, \t etc.).
} RzStrEscOptions;
/**
* \brief Convenience macro for local temporary strings
* \param buf Target buffer, **must** be an array type, not a pointer.
*
* This eases the common pattern where a stack-allocated string of a fixed
* size is created and filled with `snprintf()` to be used as a temporary string.
*
* Example:
*
* char k[32];
* char v[32];
* sdb_set(db, rz_strf(k, "key.%d", 42), rz_strf(v, "val.%d", 123));
*/
#define rz_strf(buf, ...) ( \
snprintf(buf, sizeof(buf), __VA_ARGS__) < 0 \
? rz_assert_log(RZ_LOGLVL_FATAL, "rz_strf error while using snprintf"), \
NULL \
: buf)
typedef int (*RzStrRangeCallback)(void *, int);
#define RZ_STR_ISEMPTY(x) (!(x) || !*(x))
#define RZ_STR_ISNOTEMPTY(x) ((x) && *(x))
#define RZ_STR_DUP(x) ((x) ? strdup((x)) : NULL)
#define RZ_STR_EQ(x, y) (rz_str_cmp((x), (y), -1) == 0)
#define RZ_STR_NE(x, y) (rz_str_cmp((x), (y), -1) != 0)
#define rz_str_array(x, y) ((y >= 0 && y < (sizeof(x) / sizeof(*x))) ? x[y] : "")
RZ_API const char *rz_str_enc_as_string(RzStrEnc enc);
RZ_API RzStrEnc rz_str_enc_string_as_type(RZ_NULLABLE const char *enc);
RZ_API RZ_OWN char *rz_str_repeat(const char *str, ut16 times);
RZ_API RZ_OWN char *rz_str_pad(const char ch, ssize_t len);
RZ_API const char *rz_str_rstr(const char *base, const char *p);
RZ_API const char *rz_strstr_ansi(RZ_NONNULL const char *a, RZ_NONNULL const char *b, bool icase);
RZ_API const char *rz_str_rchr(const char *base, const char *p, int ch);
RZ_API const char *rz_str_closer_chr(const char *b, const char *s);
RZ_API int rz_str_bounds(const char *str, int *h);
RZ_API char *rz_str_crop(const char *str, unsigned int x, unsigned int y, unsigned int x2, unsigned int y2);
RZ_API char *rz_str_scale(const char *r, int w, int h);
RZ_API bool rz_str_range_in(const char *r, ut64 addr);
RZ_API size_t rz_str_utf8_cols(const char *s);
RZ_API size_t rz_str_utf8_num_ucp(RZ_NONNULL const char *str);
RZ_API size_t rz_str_utf8_get_width_utf16(RZ_NONNULL const char *str);
RZ_API size_t rz_str_utf8_ansi_cols(const char *str);
RZ_API size_t rz_str_len_utf8char(const char *s, int left);
RZ_API size_t rz_str_utf8_charsize(const char *str);
RZ_API size_t rz_str_utf8_charsize_prev(const char *str, int prev_len);
RZ_API size_t rz_str_utf8_charsize_last(const char *str);
RZ_API void rz_str_filter_zeroline(char *str, int len);
RZ_API size_t rz_str_utf8_codepoint(const char *s, size_t left);
RZ_API bool rz_str_char_fullwidth(const char *s, size_t left);
RZ_API int rz_str_write(int fd, const char *b);
RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t n);
RZ_API size_t rz_str_ncat(RZ_NONNULL RZ_OUT char *dst, RZ_NONNULL const char *src, size_t n);
RZ_API void rz_str_sanitize(char *c);
RZ_API char *rz_str_sanitize_sdb_key(const char *s);
RZ_API const char *rz_str_casestr(const char *a, const char *b);
RZ_API const char *rz_str_firstbut(const char *s, char ch, const char *but);
RZ_API const char *rz_str_lastbut(const char *s, char ch, const char *but);
RZ_API size_t rz_str_split(char *str, char ch);
RZ_API RzList /*<char *>*/ *rz_str_split_list(char *str, const char *c, int n);
RZ_API RZ_OWN RzList /*<char *>*/ *rz_str_split_list_regex(RZ_NONNULL char *str, RZ_NONNULL const char *r, int n);
RZ_API RzList /*<char *>*/ *rz_str_split_duplist(const char *str, const char *c, bool trim);
RZ_API RzList /*<char *>*/ *rz_str_split_duplist_n(const char *str, const char *c, int n, bool trim);
RZ_API RZ_OWN RzList /*<char *>*/ *rz_str_split_duplist_n_regex(RZ_NONNULL const char *_str, RZ_NONNULL const char *r, int n, bool trim);
RZ_API size_t *rz_str_split_lines(char *str, size_t *count);
RZ_API RZ_OWN char *rz_str_replace(RZ_OWN char *str, const char *key, const char *val, int g);
RZ_API RZ_OWN char *rz_str_replace_regex(const char *str, const char *pattern, const char *val, bool global, bool icase);
RZ_API char *rz_str_replace_icase(char *str, const char *key, const char *val, int g, int keep_case);
RZ_API char *rz_str_replace_in(char *str, ut32 sz, const char *key, const char *val, int g);
#define rz_str_cpy(x, y) memmove((x), (y), strlen(y) + 1);
#define rz_str_cat(x, y) memmove((x) + strlen(x), (y), strlen(y) + 1);
RZ_API int rz_str_bits(char *strout, const ut8 *buf, int len, const char *bitz);
RZ_API int rz_str_bits64(char *strout, ut64 in);
RZ_API ut64 rz_str_bits_from_string(const char *buf, const char *bitz);
RZ_API int rz_str_rwx(const char *str);
RZ_API int rz_str_replace_ch(char *s, char a, char b, bool g);
RZ_API int rz_str_replace_char(char *s, int a, int b);
RZ_API int rz_str_replace_char_once(char *s, int a, int b);
RZ_API void rz_str_remove_char(char *str, char c);
RZ_API const char *rz_str_rwx_i(int rwx);
RZ_API int rz_str_fmtargs(const char *fmt);
RZ_API char *rz_str_arg_escape(const char *arg);
RZ_API int rz_str_arg_unescape(char *arg);
RZ_API char **rz_str_argv(const char *str, int *_argc);
RZ_API void rz_str_argv_free(char **argv);
RZ_API int rz_snprintf(char *string, int len, const char *fmt, ...) RZ_PRINTF_CHECK(3, 4);
RZ_API bool rz_str_is_whitespace(RZ_NONNULL const char *str);
RZ_API bool rz_str_is_ascii(const char *str);
RZ_API bool rz_str_is_utf8(RZ_NONNULL const char *str);
RZ_API char *rz_str_nextword(char *s, char ch);
RZ_API bool rz_str_is_printable(const char *str);
RZ_API bool rz_str_is_printable_limited(RZ_NONNULL const char *str, size_t size);
RZ_API bool rz_str_is_printable_incl_newlines(const char *str);
RZ_API char *rz_str_appendlen(char *ptr, const char *string, int slen);
RZ_API char *rz_str_newf(const char *fmt, ...) RZ_PRINTF_CHECK(1, 2);
RZ_API char *rz_str_newlen(const char *str, int len);
RZ_API const char *rz_str_sysbits(const int v);
RZ_API char *rz_str_trunc_ellipsis(const char *str, int len);
RZ_API const char *rz_str_bool(int b);
RZ_API bool rz_str_is_true(const char *s);
RZ_API bool rz_str_is_false(RZ_NULLABLE const char *s);
RZ_API bool rz_str_is_bool(const char *val);
RZ_API const char *rz_str_ansi_chrn(const char *str, size_t n);
RZ_API size_t rz_str_ansi_len(const char *str);
RZ_API size_t rz_str_ansi_nlen(const char *str, size_t len);
RZ_API int rz_str_ansi_trim(char *str, int str_len, int n);
RZ_API int rz_str_ansi_filter(char *str, char **out, int **cposs, int len);
RZ_API char *rz_str_ansi_crop(const char *str, unsigned int x, unsigned int y, unsigned int x2, unsigned int y2);
RZ_API int rz_str_word_count(const char *string);
RZ_API int rz_str_char_count(const char *string, char ch);
RZ_API int rz_str_word_set0(char *str);
static inline const char *rz_str_word_get_next0(const char *str) {
return str + strlen(str) + 1;
}
RZ_API const char *rz_str_word_get0(const char *str, int idx);
RZ_API RZ_OWN char *rz_str_skip_separator_chars(RZ_NONNULL const char *string);
RZ_API void rz_str_trim(RZ_NONNULL RZ_INOUT char *str);
RZ_API void rz_str_trim_char(RZ_NONNULL RZ_INOUT char *str, const char c);
RZ_API char *rz_str_trim_dup(const char *str);
RZ_API char *rz_str_trim_lines(char *str);
RZ_API void rz_str_trim_head(RZ_NONNULL RZ_INOUT char *str);
RZ_API void rz_str_trim_head_char(RZ_NONNULL RZ_INOUT char *str, const char c);
RZ_API const char *rz_str_trim_head_ro(RZ_NONNULL const char *str);
RZ_API const char *rz_str_trim_head_wp(RZ_NONNULL const char *str);
RZ_API RZ_INOUT char *rz_str_trim_tail(RZ_NONNULL RZ_INOUT char *str);
RZ_API void rz_str_trim_tail_char(RZ_NONNULL RZ_INOUT char *str, const char c);
RZ_API ut64 rz_str_djb2_hash(const char *str);
RZ_API char *rz_str_trim_nc(char *str);
RZ_API bool rz_str_is2utf8(RZ_NONNULL const char *c);
RZ_API bool rz_str_is3utf8(RZ_NONNULL const char *c);
RZ_API bool rz_str_is4utf8(RZ_NONNULL const char *c);
RZ_API bool rz_str_isXutf8(RZ_NONNULL const char *c, ut8 x);
RZ_API const char *rz_str_strchr(RZ_NONNULL const char *str, RZ_NONNULL const char *c);
RZ_API const char *rz_str_nstr(const char *from, const char *to, int size);
RZ_API const char *rz_str_case_nstr(RZ_NONNULL const char *from, RZ_NONNULL const char *to, int size);
RZ_API const char *rz_str_lchr(const char *str, char chr);
RZ_API const char *rz_sub_str_lchr(RZ_NONNULL const char *str, int start, int end, char chr);
RZ_API const char *rz_sub_str_rchr(RZ_NONNULL const char *str, int start, int end, char chr);
RZ_API RZ_OWN char *rz_sub_str_ptr(RZ_NONNULL const char *str, RZ_NONNULL const char *start, RZ_NONNULL const char *end);
RZ_API char *rz_str_ichr(char *str, char chr);
RZ_API bool rz_str_ccmp(const char *dst, const char *orig, int ch);
RZ_API bool rz_str_cmp_list(const char *list, const char *item, char sep);
RZ_API int rz_str_cmp(RZ_NULLABLE const char *dst, RZ_NULLABLE const char *orig, int len);
RZ_API int rz_str_casecmp(const char *dst, const char *orig);
RZ_API int rz_str_ncasecmp(const char *dst, const char *orig, size_t n);
RZ_API int rz_str_ccpy(char *dst, const char *orig, int ch);
static inline const char *rz_str_get(const char *str) {
return str ? str : "";
}
static inline const char *rz_str_get_null(const char *str) {
return str ? str : "(null)";
}
RZ_API char *rz_str_ndup(RZ_NULLABLE const char *ptr, int len);
RZ_API RZ_OWN char *rz_str_dup(RZ_NULLABLE const char *str);
RZ_API int rz_str_delta(char *p, char a, char b);
RZ_API void rz_str_filter(char *str);
RZ_API const char *rz_str_tok(const char *str1, const char b, size_t len);
RZ_API const char *rz_str_str_xy(const char *s, const char *word, const char *prev, int *x, int *y);
typedef void (*str_operation)(char *c);
RZ_API int rz_str_do_until_token(str_operation op, char *str, const char tok);
RZ_API void rz_str_reverse(char *str);
RZ_API int rz_str_path_unescape(char *path);
RZ_API char *rz_str_path_escape(const char *path);
RZ_API int rz_str_unescape(char *buf);
RZ_DEPRECATE RZ_API RZ_OWN char *rz_str_escape(RZ_NONNULL const char *buf);
RZ_API char *rz_str_escape_sh(const char *buf);
RZ_API bool rz_str_escape_code_point(ut32 /* RzCodePoint */ cp, size_t ch_bytes, RZ_NONNULL const RzStrEscOptions *opts);
RZ_DEPRECATE RZ_API char *rz_str_escape_dot(const char *buf);
RZ_DEPRECATE RZ_API char *rz_str_escape_8bit(const char *buf, bool colors, RzStrEscOptions *opt);
RZ_API RZ_OWN char *rz_str_escape_utf8(RZ_NONNULL const char *buf, RZ_NONNULL const RzStrEscOptions *opt);
RZ_API RZ_OWN char *rz_str_escape_utf16le(RZ_NONNULL const char *buf, size_t buf_size, RZ_NONNULL const RzStrEscOptions *opt);
RZ_API RZ_OWN char *rz_str_escape_utf32le(RZ_NONNULL const char *buf, size_t buf_size, RZ_NONNULL const RzStrEscOptions *opt);
RZ_API RZ_OWN char *rz_str_escape_utf16be(RZ_NONNULL const char *buf, size_t buf_size, RZ_NONNULL const RzStrEscOptions *opt);
RZ_API RZ_OWN char *rz_str_escape_utf32be(RZ_NONNULL const char *buf, size_t buf_size, RZ_NONNULL const RzStrEscOptions *opt);
RZ_API RZ_OWN char *rz_str_format_msvc_argv(size_t argc, const char **argv);
RZ_API void rz_str_uri_decode(char *buf);
RZ_API char *rz_str_uri_encode(const char *buf);
RZ_API char *rz_str_utf16_decode(const ut8 *s, int len);
RZ_DEPRECATE RZ_API char *rz_str_utf16_encode(const char *s, int len);
RZ_API RZ_OWN ut16 *rz_str_utf8_to_utf16(RZ_NONNULL const char *utf8_str, bool big_endian);
RZ_API RZ_OWN ut32 *rz_str_utf8_to_utf32(RZ_NONNULL const char *utf8_str, bool big_endian);
RZ_API char *rz_str_escape_utf8_for_json(const char *s, int len);
RZ_API char *rz_str_escape_mutf8_for_json(const char *s, int len);
RZ_API char *rz_str_home(const char *str);
RZ_API size_t rz_str_nlen(const char *s, size_t n);
RZ_API size_t rz_str_nlen_w(const char *s, int n);
RZ_API size_t rz_wstr_clen(const char *s);
RZ_API char *rz_str_prepend(char *ptr, const char *string);
RZ_API char *rz_str_prefix_all(const char *s, const char *pfx);
RZ_API RZ_OWN char *rz_str_append(RZ_OWN RZ_NULLABLE char *ptr, const char *string);
RZ_API char *rz_str_append_owned(char *ptr, char *string);
RZ_API RZ_OWN char *rz_str_appendf(RZ_OWN RZ_NULLABLE char *ptr, const char *fmt, ...) RZ_PRINTF_CHECK(2, 3);
RZ_API char *rz_str_appendch(char *x, char y);
RZ_API bool rz_str_append_num_subscript(RZ_NONNULL RzStrBuf *sb, ut32 n);
RZ_API bool rz_str_append_num_superscript(RZ_NONNULL RzStrBuf *sb, ut32 n);
RZ_API RZ_OWN char *rz_str_num_subscript(ut32 n);
RZ_API void rz_str_case(char *str, bool up);
RZ_API void rz_str_trim_path(char *s);
RZ_API ut8 rz_str_contains_macro(const char *input_value);
RZ_API void rz_str_truncate_cmd(char *string);
RZ_API char *rz_str_replace_thunked(char *str, char *clean, int *thunk, int clen,
const char *key, const char *val, int g);
RZ_API bool rz_str_glob(const char *str, const char *glob);
RZ_API int rz_str_binstr2bin(const char *str, ut8 *out, int outlen);
RZ_API char *rz_str_between(const char *str, const char *prefix, const char *suffix);
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle);
RZ_API bool rz_str_startswith_icase(RZ_NONNULL const char *str, RZ_NONNULL const char *needle);
RZ_API bool rz_str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle);
RZ_API bool rz_str_endswith_icase(RZ_NONNULL const char *str, RZ_NONNULL const char *needle);
RZ_API bool rz_str_isnumber(const char *str);
RZ_API const char *rz_str_last(const char *in, const char *ch);
RZ_API char *rz_str_highlight(char *str, const char *word, const char *color, const char *color_reset);
RZ_API char *rz_str_from_ut64(ut64 val);
RZ_API char *rz_str_list_join(RzList /*<char *>*/ *str, const char *sep);
RZ_API char *rz_str_array_join(const char **a, size_t n, const char *sep);
RZ_API RzList /*<char *>*/ *rz_str_wrap(char *str, size_t width);
RZ_API const char *rz_str_sep(const char *base, const char *sep);
RZ_API const char *rz_str_rsep(const char *base, const char *p, const char *sep);
typedef struct rz_str_stringify_opt_t {
const ut8 *buffer; ///< String buffer (cannot be NULL).
ut32 length; ///< String buffer length.
RzStrEnc encoding; ///< String encoding type (cannot be RZ_STRING_ENC_GUESS)
ut32 wrap_at; ///< Adds a new line the output when it exceeds this value.
bool escape_nl; ///< When enabled escapes new lines (\n).
bool json; ///< Encodes the output as a JSON string.
bool stop_at_nil; ///< When enabled stops printing when '\0' is found.
bool stop_at_unprintable; ///< When enabled stops printing at first non-printable character.
bool urlencode; ///< Encodes the output following RFC 3986.
const RzVector /*<RzCodePoint>*/ *user_unprintable; ///< Borrowed vector of user-defined non-printable code points.
} RzStrStringifyOpt;
RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, ut32 length);
RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NULLABLE RZ_OUT ut32 *length);
RZ_API const char *rz_str_indent(int indent);
/**
* \brief Returns true if the given encoding has the same byte character width as UTF-8.
* This is only true for UTF-8 and ASCII.
*
* Examples:
*
* ```c
* // IBM290 character width is always one byte, but the equivalent Japanese
* // characters in UTF-8 are 3 bytes.
* assert(rz_string_enc_same_char_width_as_utf8(RZ_STR_ENC_IBM290) == false);
*
* // ASCII character width is always one byte, and the equivalent
* // UTF-8 characters are also always 1 byte.
* assert(rz_string_enc_same_char_width_as_utf8(RZ_STR_ENC_8BIT) == true);
* ```
*/
static inline bool rz_string_enc_same_char_width_as_utf8(RzStrEnc enc) {
return enc == RZ_STRING_ENC_UTF8 || enc == RZ_STRING_ENC_8BIT;
}
RZ_API bool rz_string_enc_is_utf(RzStrEnc enc);
RZ_API bool rz_string_enc_is_utf_native_endian(RzStrEnc enc);
RZ_API size_t rz_string_enc_code_point_width(RzStrEnc enc);
RZ_API bool rz_string_enc_requires_scanning(RzStrEnc enc);
static inline bool rz_string_code_points_align(RzStrEnc enc, size_t memory_alignment) {
rz_return_val_if_fail(memory_alignment, false);
if (rz_string_enc_code_point_width(enc) == memory_alignment) {
return true;
}
switch (enc) {
case RZ_STRING_ENC_SETTINGS:
rz_warn_if_reached();
return false;
case RZ_STRING_ENC_GUESS:
return false;
default:
return memory_alignment % rz_string_enc_code_point_width(enc) == 0;
}
}
#ifdef __cplusplus
}
#endif
#endif // RZ_STR_H