forked from osmocom/wireshark
dfilter: Add support for literal strings with null bytes
Before: Filter: frame matches "abc\x00def" dftest: \x00 (NUL byte) cannot be used with a regular string. frame matches "abc\x00def" ^~~~ Filter: _ws.ftypes.string == "a string with a \0 byte" dftest: \0 (NUL byte) cannot be used with a regular string. _ws.ftypes.string == "a string with a \0 byte" ^~ After: Filter: frame matches "abc\x00def" Syntax tree: 0 TEST_MATCHES: 1 FIELD(frame) 1 PCRE(abc\0def) Instructions: 00000 READ_TREE frame -> reg#0 00001 IF_FALSE_GOTO 3 00002 ANY_MATCHES reg#0 matches abc\0def 00003 RETURN Filter: _ws.ftypes.string == "a string with a \0 byte" Syntax tree: 0 TEST_ANY_EQ: 1 FIELD(_ws.ftypes.string) 1 FVALUE("a string with a \0 byte" <FT_STRING>) Instructions: 00000 READ_TREE _ws.ftypes.string -> reg#0 00001 IF_FALSE_GOTO 3 00002 ANY_EQ reg#0 == "a string with a \0 byte" <FT_STRING> 00003 RETURN Fixes issue #16156.
This commit is contained in:
parent
d372ed3483
commit
47348ae598
|
@ -135,6 +135,9 @@ They previously shipped with Qt 5.12.2.
|
|||
** The display filter engine now uses PCRE2 instead of GRegex (GLib’s bindings to the older and end-of-life PCRE library).
|
||||
PCRE2 is compatible with PCRE so any user-visible changes should be minimal.
|
||||
Some exotic patterns may now be invalid and require rewriting.
|
||||
** Literal strings can handle embedded null bytes (the value '\0') correctly. This includes regular expression patterns.
|
||||
For example the double-quoted string "\0 is a null byte" is a legal literal value.
|
||||
This may be useful to match byte patterns but note that in general protocol fields with a string type still cannot contain embedded null bytes.
|
||||
|
||||
* The `text2pcap` command and the “Import from Hex Dump” feature have been updated and enhanced:
|
||||
** `text2pcap` supports writing the output file in all the capture file formats that wiretap library supports, using the same `-F` option as `editcap`, `mergecap`, and `tshark`.
|
||||
|
|
|
@ -31,7 +31,8 @@ string_walk(GSList *args, guint32 arg_count, GSList **retval, gchar(*conv_func)(
|
|||
GSList *arg1;
|
||||
fvalue_t *arg_fvalue;
|
||||
fvalue_t *new_ft_string;
|
||||
char *s, *c;
|
||||
const wmem_strbuf_t *src;
|
||||
wmem_strbuf_t *dst;
|
||||
|
||||
ws_assert(arg_count == 1);
|
||||
arg1 = args->data;
|
||||
|
@ -42,14 +43,14 @@ string_walk(GSList *args, guint32 arg_count, GSList **retval, gchar(*conv_func)(
|
|||
arg_fvalue = (fvalue_t *)arg1->data;
|
||||
/* XXX - it would be nice to handle FT_TVBUFF, too */
|
||||
if (IS_FT_STRING(fvalue_type_ftenum(arg_fvalue))) {
|
||||
s = wmem_strdup(NULL, fvalue_get_string(arg_fvalue));
|
||||
for (c = s; *c; c++) {
|
||||
*c = conv_func(*c);
|
||||
src = fvalue_get_strbuf(arg_fvalue);
|
||||
dst = wmem_strbuf_sized_new(NULL, src->len, 0);
|
||||
for (size_t i = 0; i < src->len; i++) {
|
||||
wmem_strbuf_append_c(dst, conv_func(src->str[i]));
|
||||
}
|
||||
|
||||
new_ft_string = fvalue_new(FT_STRING);
|
||||
fvalue_set_string(new_ft_string, s);
|
||||
wmem_free(NULL, s);
|
||||
fvalue_set_strbuf(new_ft_string, dst);
|
||||
*retval = g_slist_prepend(*retval, new_ft_string);
|
||||
}
|
||||
arg1 = arg1->next;
|
||||
|
|
|
@ -250,7 +250,7 @@ hyphen-bytes {hex2}(-{hex2})+
|
|||
update_location(yyextra, yytext);
|
||||
yyextra->string_loc = yyextra->location;
|
||||
|
||||
yyextra->quoted_string = g_string_new("\"");
|
||||
yyextra->quoted_string = g_string_new(NULL);
|
||||
|
||||
if (yytext[0] == 'r' || yytext[0] == 'R') {
|
||||
/*
|
||||
|
@ -282,7 +282,6 @@ hyphen-bytes {hex2}(-{hex2})+
|
|||
/* end quote */
|
||||
BEGIN(INITIAL);
|
||||
update_string_loc(yyextra, yytext);
|
||||
g_string_append_c(yyextra->quoted_string, '"');
|
||||
int token = set_lval_quoted_string(yyextra, TOKEN_STRING, yyextra->quoted_string);
|
||||
yyextra->quoted_string = NULL;
|
||||
yyextra->string_loc.col_start = -1;
|
||||
|
@ -298,12 +297,6 @@ hyphen-bytes {hex2}(-{hex2})+
|
|||
else {
|
||||
unsigned long result;
|
||||
result = strtoul(yytext + 1, NULL, 8);
|
||||
if (result == 0) {
|
||||
g_string_free(yyextra->quoted_string, TRUE);
|
||||
yyextra->quoted_string = NULL;
|
||||
FAIL("%s (NUL byte) cannot be used with a regular string.", yytext);
|
||||
return SCAN_FAILED;
|
||||
}
|
||||
if (result > 0xff) {
|
||||
g_string_free(yyextra->quoted_string, TRUE);
|
||||
yyextra->quoted_string = NULL;
|
||||
|
@ -327,12 +320,6 @@ hyphen-bytes {hex2}(-{hex2})+
|
|||
else {
|
||||
unsigned long result;
|
||||
result = strtoul(yytext + 2, NULL, 16);
|
||||
if (result == 0) {
|
||||
g_string_free(yyextra->quoted_string, TRUE);
|
||||
yyextra->quoted_string = NULL;
|
||||
FAIL("%s (NUL byte) cannot be used with a regular string.", yytext);
|
||||
return SCAN_FAILED;
|
||||
}
|
||||
g_string_append_c(yyextra->quoted_string, (gchar) result);
|
||||
}
|
||||
}
|
||||
|
@ -528,12 +515,9 @@ static int
|
|||
set_lval_quoted_string(df_scanner_state_t *state, int token, GString *quoted_string)
|
||||
{
|
||||
ws_assert(token == TOKEN_STRING);
|
||||
char *token_value = g_string_free(quoted_string, FALSE);
|
||||
char *token_value = ws_escape_string_len(NULL, quoted_string->str, quoted_string->len, true);
|
||||
|
||||
/* Strip start and end quote. */
|
||||
char *data = g_strndup(token_value + 1, strlen(token_value + 1) - 1);
|
||||
|
||||
stnode_init(df_lval, STTYPE_STRING, data, token_value, &state->string_loc);
|
||||
stnode_init(df_lval, STTYPE_STRING, quoted_string, token_value, &state->string_loc);
|
||||
return token;
|
||||
}
|
||||
|
||||
|
|
|
@ -241,12 +241,12 @@ dfilter_fvalue_from_string(dfwork_t *dfw, ftenum_t ftype, stnode_t *st,
|
|||
header_field_info *hfinfo_value_string)
|
||||
{
|
||||
fvalue_t *fv;
|
||||
const char *s = stnode_data(st);
|
||||
const GString *gs = stnode_string(st);
|
||||
|
||||
fv = fvalue_from_string(ftype, s,
|
||||
fv = fvalue_from_string(ftype, gs->str, gs->len,
|
||||
dfw->error_message == NULL ? &dfw->error_message : NULL);
|
||||
if (fv == NULL && hfinfo_value_string) {
|
||||
fv = mk_fvalue_from_val_string(dfw, hfinfo_value_string, s);
|
||||
fv = mk_fvalue_from_val_string(dfw, hfinfo_value_string, gs->str);
|
||||
/*
|
||||
* Ignore previous errors if this can be mapped
|
||||
* to an item from value_string.
|
||||
|
@ -1135,7 +1135,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
|
|||
{
|
||||
ws_regex_t *pcre;
|
||||
char *errmsg = NULL;
|
||||
const char *patt;
|
||||
GString *patt;
|
||||
|
||||
LOG_NODE(st_node);
|
||||
|
||||
|
@ -1145,10 +1145,10 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
|
|||
FAIL(dfw, st_arg2, "Matches requires a double quoted string on the right side.");
|
||||
}
|
||||
|
||||
patt = stnode_data(st_arg2);
|
||||
ws_debug("Compile regex pattern: %s", patt);
|
||||
patt = stnode_string(st_arg2);
|
||||
ws_debug("Compile regex pattern: %s", stnode_token(st_arg2));
|
||||
|
||||
pcre = ws_regex_compile_ex(patt, &errmsg, WS_REGEX_CASELESS|WS_REGEX_NEVER_UTF);
|
||||
pcre = ws_regex_compile_ex(patt->str, patt->len, &errmsg, WS_REGEX_CASELESS|WS_REGEX_NEVER_UTF);
|
||||
if (errmsg) {
|
||||
dfilter_fail(dfw, NULL, "Regex compilation error: %s.", errmsg);
|
||||
g_free(errmsg);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include "syntax-tree.h"
|
||||
#include <wsutil/str_util.h>
|
||||
|
||||
static gpointer
|
||||
string_dup(gconstpointer string)
|
||||
|
@ -27,6 +28,26 @@ string_tostr(const void *data, gboolean pretty _U_)
|
|||
return g_strdup(data);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gstring_dup(gconstpointer value)
|
||||
{
|
||||
const GString *gs = value;
|
||||
return g_string_new_len(gs->str, gs->len);
|
||||
}
|
||||
|
||||
static void
|
||||
gstring_free(gpointer value)
|
||||
{
|
||||
g_string_free(value, TRUE);
|
||||
}
|
||||
|
||||
static char *
|
||||
gstring_tostr(const void *value, gboolean pretty _U_)
|
||||
{
|
||||
const GString *gs = value;
|
||||
return ws_escape_string_len(NULL, gs->str, gs->len, false);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sttype_register_string(void)
|
||||
|
@ -35,9 +56,9 @@ sttype_register_string(void)
|
|||
STTYPE_STRING,
|
||||
"STRING",
|
||||
NULL,
|
||||
string_free,
|
||||
string_dup,
|
||||
string_tostr
|
||||
gstring_free,
|
||||
gstring_dup,
|
||||
gstring_tostr
|
||||
};
|
||||
|
||||
static sttype_t unparsed_type = {
|
||||
|
|
|
@ -219,6 +219,13 @@ stnode_data(stnode_t *node)
|
|||
return node->data;
|
||||
}
|
||||
|
||||
GString *
|
||||
stnode_string(stnode_t *node)
|
||||
{
|
||||
ws_assert(stnode_type_id(node) == STTYPE_STRING);
|
||||
return stnode_data(node);
|
||||
}
|
||||
|
||||
gpointer
|
||||
stnode_steal_data(stnode_t *node)
|
||||
{
|
||||
|
|
|
@ -148,6 +148,9 @@ stnode_type_id(stnode_t *node);
|
|||
gpointer
|
||||
stnode_data(stnode_t *node);
|
||||
|
||||
GString *
|
||||
stnode_string(stnode_t *node);
|
||||
|
||||
gpointer
|
||||
stnode_steal_data(stnode_t *node);
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ samr_query_dispinfo(void *dummy _U_, packet_info *pinfo, epan_dissect_t *edt, co
|
|||
(void) g_strlcpy(sid_name_str, sid, 256);
|
||||
sid_name_str[len++]='-';
|
||||
snprintf(sid_name_str+len, 256-len, "%d",fi_rid->value.value.sinteger);
|
||||
add_sid_name_mapping(sid_name_str, fi_name->value.value.string);
|
||||
add_sid_name_mapping(sid_name_str, fvalue_get_string(&fi_name->value));
|
||||
}
|
||||
return TAP_PACKET_REDRAW;
|
||||
}
|
||||
|
@ -194,8 +194,8 @@ lsa_policy_information(void *dummy _U_, packet_info *pinfo _U_, epan_dissect_t *
|
|||
{
|
||||
GPtrArray *gp;
|
||||
field_info *fi;
|
||||
char *domain;
|
||||
char *sid;
|
||||
const char *domain;
|
||||
const char *sid;
|
||||
int info_level;
|
||||
|
||||
gp=proto_get_finfo_ptr_array(edt->tree, hf_lsa_info_level);
|
||||
|
@ -214,14 +214,14 @@ lsa_policy_information(void *dummy _U_, packet_info *pinfo _U_, epan_dissect_t *
|
|||
return TAP_PACKET_DONT_REDRAW;
|
||||
}
|
||||
fi=(field_info *)gp->pdata[0];
|
||||
domain=fi->value.value.string;
|
||||
domain=fvalue_get_string(&fi->value);
|
||||
|
||||
gp=proto_get_finfo_ptr_array(edt->tree, hf_nt_domain_sid);
|
||||
if(!gp || gp->len!=1){
|
||||
return TAP_PACKET_DONT_REDRAW;
|
||||
}
|
||||
fi=(field_info *)gp->pdata[0];
|
||||
sid=fi->value.value.string;
|
||||
sid=fvalue_get_string(&fi->value);
|
||||
|
||||
add_sid_name_mapping(sid, domain);
|
||||
break;
|
||||
|
|
|
@ -1089,7 +1089,7 @@ static const char *get_user_comment_string(proto_tree *tree)
|
|||
for (i=0; i< items->len; i++) {
|
||||
field_info *field = (field_info *)g_ptr_array_index(items,i);
|
||||
if (strcmp(field->hfinfo->abbrev, "frame.comment") == 0) {
|
||||
value = field->value.value.string;
|
||||
value = fvalue_get_string(&field->value);
|
||||
break;
|
||||
}
|
||||
/* This is the only item that can come before "frame.comment", so otherwise break out */
|
||||
|
|
|
@ -161,13 +161,16 @@ bytes_fvalue_get(fvalue_t *fv)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
bytes_from_string(fvalue_t *fv, const char *s, gchar **err_msg _U_)
|
||||
bytes_from_string(fvalue_t *fv, const char *s, size_t len, gchar **err_msg _U_)
|
||||
{
|
||||
GByteArray *bytes;
|
||||
|
||||
bytes = g_byte_array_new();
|
||||
|
||||
g_byte_array_append(bytes, (const guint8 *)s, (guint)strlen(s));
|
||||
if (len == 0)
|
||||
len = strlen(s);
|
||||
|
||||
g_byte_array_append(bytes, (const guint8 *)s, (guint)len);
|
||||
|
||||
/* Free up the old value, if we have one */
|
||||
bytes_fvalue_free(fv);
|
||||
|
|
|
@ -1164,7 +1164,7 @@ ftype_register_integers(void)
|
|||
static ftype_t char_type = {
|
||||
FT_CHAR, /* ftype */
|
||||
"FT_CHAR", /* name */
|
||||
"Character, 1 byte", /* pretty name */
|
||||
"Character (1 byte)", /* pretty name */
|
||||
1, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1196,7 +1196,7 @@ ftype_register_integers(void)
|
|||
static ftype_t uint8_type = {
|
||||
FT_UINT8, /* ftype */
|
||||
"FT_UINT8", /* name */
|
||||
"Unsigned integer, 1 byte", /* pretty name */
|
||||
"Unsigned integer (1 byte)", /* pretty name */
|
||||
1, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1228,7 +1228,7 @@ ftype_register_integers(void)
|
|||
static ftype_t uint16_type = {
|
||||
FT_UINT16, /* ftype */
|
||||
"FT_UINT16", /* name */
|
||||
"Unsigned integer, 2 bytes", /* pretty_name */
|
||||
"Unsigned integer (2 bytes)", /* pretty_name */
|
||||
2, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1260,7 +1260,7 @@ ftype_register_integers(void)
|
|||
static ftype_t uint24_type = {
|
||||
FT_UINT24, /* ftype */
|
||||
"FT_UINT24", /* name */
|
||||
"Unsigned integer, 3 bytes", /* pretty_name */
|
||||
"Unsigned integer (3 bytes)", /* pretty_name */
|
||||
3, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1292,7 +1292,7 @@ ftype_register_integers(void)
|
|||
static ftype_t uint32_type = {
|
||||
FT_UINT32, /* ftype */
|
||||
"FT_UINT32", /* name */
|
||||
"Unsigned integer, 4 bytes", /* pretty_name */
|
||||
"Unsigned integer (4 bytes)", /* pretty_name */
|
||||
4, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1324,7 +1324,7 @@ ftype_register_integers(void)
|
|||
static ftype_t uint40_type = {
|
||||
FT_UINT40, /* ftype */
|
||||
"FT_UINT40", /* name */
|
||||
"Unsigned integer, 5 bytes", /* pretty_name */
|
||||
"Unsigned integer (5 bytes)", /* pretty_name */
|
||||
5, /* wire_size */
|
||||
int64_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1356,7 +1356,7 @@ ftype_register_integers(void)
|
|||
static ftype_t uint48_type = {
|
||||
FT_UINT48, /* ftype */
|
||||
"FT_UINT48", /* name */
|
||||
"Unsigned integer, 6 bytes", /* pretty_name */
|
||||
"Unsigned integer (6 bytes)", /* pretty_name */
|
||||
6, /* wire_size */
|
||||
int64_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1388,7 +1388,7 @@ ftype_register_integers(void)
|
|||
static ftype_t uint56_type = {
|
||||
FT_UINT56, /* ftype */
|
||||
"FT_UINT56", /* name */
|
||||
"Unsigned integer, 7 bytes", /* pretty_name */
|
||||
"Unsigned integer (7 bytes)", /* pretty_name */
|
||||
7, /* wire_size */
|
||||
int64_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1420,7 +1420,7 @@ ftype_register_integers(void)
|
|||
static ftype_t uint64_type = {
|
||||
FT_UINT64, /* ftype */
|
||||
"FT_UINT64", /* name */
|
||||
"Unsigned integer, 8 bytes", /* pretty_name */
|
||||
"Unsigned integer (8 bytes)", /* pretty_name */
|
||||
8, /* wire_size */
|
||||
int64_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1452,7 +1452,7 @@ ftype_register_integers(void)
|
|||
static ftype_t int8_type = {
|
||||
FT_INT8, /* ftype */
|
||||
"FT_INT8", /* name */
|
||||
"Signed integer, 1 byte", /* pretty_name */
|
||||
"Signed integer (1 byte)", /* pretty_name */
|
||||
1, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1484,7 +1484,7 @@ ftype_register_integers(void)
|
|||
static ftype_t int16_type = {
|
||||
FT_INT16, /* ftype */
|
||||
"FT_INT16", /* name */
|
||||
"Signed integer, 2 bytes", /* pretty_name */
|
||||
"Signed integer (2 bytes)", /* pretty_name */
|
||||
2, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1516,7 +1516,7 @@ ftype_register_integers(void)
|
|||
static ftype_t int24_type = {
|
||||
FT_INT24, /* ftype */
|
||||
"FT_INT24", /* name */
|
||||
"Signed integer, 3 bytes", /* pretty_name */
|
||||
"Signed integer (3 bytes)", /* pretty_name */
|
||||
3, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1548,7 +1548,7 @@ ftype_register_integers(void)
|
|||
static ftype_t int32_type = {
|
||||
FT_INT32, /* ftype */
|
||||
"FT_INT32", /* name */
|
||||
"Signed integer, 4 bytes", /* pretty_name */
|
||||
"Signed integer (4 bytes)", /* pretty_name */
|
||||
4, /* wire_size */
|
||||
int_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1580,7 +1580,7 @@ ftype_register_integers(void)
|
|||
static ftype_t int40_type = {
|
||||
FT_INT40, /* ftype */
|
||||
"FT_INT40", /* name */
|
||||
"Signed integer, 5 bytes", /* pretty_name */
|
||||
"Signed integer (5 bytes)", /* pretty_name */
|
||||
5, /* wire_size */
|
||||
int64_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1612,7 +1612,7 @@ ftype_register_integers(void)
|
|||
static ftype_t int48_type = {
|
||||
FT_INT48, /* ftype */
|
||||
"FT_INT48", /* name */
|
||||
"Signed integer, 6 bytes", /* pretty_name */
|
||||
"Signed integer (6 bytes)", /* pretty_name */
|
||||
6, /* wire_size */
|
||||
int64_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1644,7 +1644,7 @@ ftype_register_integers(void)
|
|||
static ftype_t int56_type = {
|
||||
FT_INT56, /* ftype */
|
||||
"FT_INT56", /* name */
|
||||
"Signed integer, 7 bytes", /* pretty_name */
|
||||
"Signed integer (7 bytes)", /* pretty_name */
|
||||
7, /* wire_size */
|
||||
int64_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
@ -1676,7 +1676,7 @@ ftype_register_integers(void)
|
|||
static ftype_t int64_type = {
|
||||
FT_INT64, /* ftype */
|
||||
"FT_INT64", /* name */
|
||||
"Signed integer, 8 bytes", /* pretty_name */
|
||||
"Signed integer (8 bytes)", /* pretty_name */
|
||||
8, /* wire_size */
|
||||
int64_fvalue_new, /* new_value */
|
||||
NULL, /* copy_value */
|
||||
|
|
|
@ -59,7 +59,7 @@ value_set(fvalue_t *fv, tvbuff_t *value, const gchar *name, int length)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
val_from_string(fvalue_t *fv, const char *s, gchar **err_msg _U_)
|
||||
val_from_string(fvalue_t *fv, const char *s, size_t len, gchar **err_msg _U_)
|
||||
{
|
||||
tvbuff_t *new_tvb;
|
||||
guint8 *private_data;
|
||||
|
@ -67,11 +67,14 @@ val_from_string(fvalue_t *fv, const char *s, gchar **err_msg _U_)
|
|||
/* Free up the old value, if we have one */
|
||||
value_free(fv);
|
||||
|
||||
if (len == 0)
|
||||
len = strlen(s);
|
||||
|
||||
/* Make a tvbuff from the string. We can drop the
|
||||
* terminating NUL. */
|
||||
private_data = (guint8 *)g_memdup2(s, (guint)strlen(s));
|
||||
private_data = (guint8 *)g_memdup2(s, (guint)len);
|
||||
new_tvb = tvb_new_real_data(private_data,
|
||||
(guint)strlen(s), (gint)strlen(s));
|
||||
(guint)len, (gint)len);
|
||||
|
||||
/* Let the tvbuff know how to delete the data. */
|
||||
tvb_set_free_cb(new_tvb, g_free);
|
||||
|
|
|
@ -18,69 +18,75 @@
|
|||
static void
|
||||
string_fvalue_new(fvalue_t *fv)
|
||||
{
|
||||
fv->value.string = NULL;
|
||||
fv->value.strbuf = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
string_fvalue_copy(fvalue_t *dst, const fvalue_t *src)
|
||||
{
|
||||
dst->value.string = g_strdup(src->value.string);
|
||||
dst->value.strbuf = wmem_strbuf_dup(NULL, src->value.strbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
string_fvalue_free(fvalue_t *fv)
|
||||
{
|
||||
g_free(fv->value.string);
|
||||
wmem_strbuf_destroy(fv->value.strbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
string_fvalue_set_string(fvalue_t *fv, const gchar *value)
|
||||
string_fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value)
|
||||
{
|
||||
DISSECTOR_ASSERT(value != NULL);
|
||||
|
||||
/* Free up the old value, if we have one */
|
||||
string_fvalue_free(fv);
|
||||
|
||||
fv->value.string = (gchar *)g_strdup(value);
|
||||
fv->value.strbuf = value;
|
||||
}
|
||||
|
||||
static char *
|
||||
string_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
|
||||
string_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
|
||||
{
|
||||
if (rtype == FTREPR_DISPLAY) {
|
||||
return wmem_strdup(scope, fv->value.string);
|
||||
return ws_escape_null(scope, fv->value.strbuf->str, fv->value.strbuf->len, false);
|
||||
}
|
||||
if (rtype == FTREPR_DFILTER) {
|
||||
return ws_escape_string(scope, fv->value.string, TRUE);
|
||||
return ws_escape_string_len(scope, fv->value.strbuf->str, fv->value.strbuf->len, true);
|
||||
}
|
||||
ws_assert_not_reached();
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
static const wmem_strbuf_t *
|
||||
value_get(fvalue_t *fv)
|
||||
{
|
||||
return fv->value.string;
|
||||
return fv->value.strbuf;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
val_from_string(fvalue_t *fv, const char *s, gchar **err_msg _U_)
|
||||
val_from_string(fvalue_t *fv, const char *s, size_t len, gchar **err_msg _U_)
|
||||
{
|
||||
/* Free up the old value, if we have one */
|
||||
string_fvalue_free(fv);
|
||||
|
||||
fv->value.string = g_strdup(s);
|
||||
if (len > 0)
|
||||
fv->value.strbuf = wmem_strbuf_new_len(NULL, s, len);
|
||||
else
|
||||
fv->value.strbuf = wmem_strbuf_new(NULL, s);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
val_from_literal(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
|
||||
val_from_literal(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg _U_)
|
||||
{
|
||||
/* Just turn it into a string */
|
||||
/* XXX Should probably be a syntax error instead. It's more user-friendly to ask the
|
||||
* user to be explicit about the meaning of an unquoted literal than them trying to figure out
|
||||
* why a valid filter expression is giving wrong results. */
|
||||
return val_from_string(fv, s, err_msg);
|
||||
string_fvalue_free(fv);
|
||||
|
||||
fv->value.strbuf = wmem_strbuf_new(NULL, s);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -90,7 +96,7 @@ val_from_charconst(fvalue_t *fv, unsigned long num, gchar **err_msg)
|
|||
|
||||
/* Free up the old value, if we have one */
|
||||
string_fvalue_free(fv);
|
||||
fv->value.string = NULL;
|
||||
fv->value.strbuf = NULL;
|
||||
|
||||
if (num > UINT8_MAX) {
|
||||
if (err_msg) {
|
||||
|
@ -100,9 +106,8 @@ val_from_charconst(fvalue_t *fv, unsigned long num, gchar **err_msg)
|
|||
}
|
||||
|
||||
char c = (char)num;
|
||||
fv->value.string = g_malloc(2);
|
||||
fv->value.string[0] = c;
|
||||
fv->value.string[1] = '\0';
|
||||
fv->value.strbuf = wmem_strbuf_new(NULL, NULL);
|
||||
wmem_strbuf_append_c(fv->value.strbuf, c);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -110,13 +115,13 @@ val_from_charconst(fvalue_t *fv, unsigned long num, gchar **err_msg)
|
|||
static gboolean
|
||||
string_is_zero(const fvalue_t *fv)
|
||||
{
|
||||
return fv->value.string == NULL || strlen(fv->value.string) == 0;
|
||||
return fv->value.strbuf == NULL || fv->value.strbuf->len == 0;
|
||||
}
|
||||
|
||||
static guint
|
||||
len(fvalue_t *fv)
|
||||
{
|
||||
return (guint)strlen(fv->value.string);
|
||||
return (guint)fv->value.strbuf->len;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -124,7 +129,7 @@ slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
|
|||
{
|
||||
guint8* data;
|
||||
|
||||
data = fv->value.ustring + offset;
|
||||
data = (guint8*)fv->value.strbuf->str + offset;
|
||||
|
||||
g_byte_array_append(bytes, data, length);
|
||||
}
|
||||
|
@ -132,7 +137,7 @@ slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
|
|||
static int
|
||||
cmp_order(const fvalue_t *a, const fvalue_t *b)
|
||||
{
|
||||
return strcmp(a->value.string, b->value.string);
|
||||
return wmem_strbuf_strcmp(a->value.strbuf, b->value.strbuf);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -142,11 +147,11 @@ cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b)
|
|||
* http://www.introl.com/introl-demo/Libraries/C/ANSI_C/string/strstr.html
|
||||
* strstr() returns a non-NULL value if needle is an empty
|
||||
* string. We don't that behavior for cmp_contains. */
|
||||
if (strlen(fv_b->value.string) == 0) {
|
||||
if (fv_b->value.strbuf->len == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (strstr(fv_a->value.string, fv_b->value.string)) {
|
||||
if (wmem_strbuf_strstr(fv_a->value.strbuf, fv_b->value.strbuf)) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
|
@ -157,12 +162,12 @@ cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b)
|
|||
static gboolean
|
||||
cmp_matches(const fvalue_t *fv, const ws_regex_t *regex)
|
||||
{
|
||||
char *str = fv->value.string;
|
||||
wmem_strbuf_t *buf = fv->value.strbuf;
|
||||
|
||||
if (! regex) {
|
||||
if (regex == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
return ws_regex_matches(regex, str);
|
||||
return ws_regex_matches_length(regex, buf->str, buf->len);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -182,8 +187,8 @@ ftype_register_string(void)
|
|||
val_from_charconst, /* val_from_charconst */
|
||||
string_to_repr, /* val_to_string_repr */
|
||||
|
||||
{ .set_value_string = string_fvalue_set_string }, /* union set_value */
|
||||
{ .get_value_string = value_get }, /* union get_value */
|
||||
{ .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
|
||||
{ .get_value_strbuf = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_contains,
|
||||
|
@ -214,8 +219,8 @@ ftype_register_string(void)
|
|||
val_from_charconst, /* val_from_charconst */
|
||||
string_to_repr, /* val_to_string_repr */
|
||||
|
||||
{ .set_value_string = string_fvalue_set_string }, /* union set_value */
|
||||
{ .get_value_string = value_get }, /* union get_value */
|
||||
{ .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
|
||||
{ .get_value_strbuf = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_contains, /* cmp_contains */
|
||||
|
@ -246,8 +251,8 @@ ftype_register_string(void)
|
|||
val_from_charconst, /* val_from_charconst */
|
||||
string_to_repr, /* val_to_string_repr */
|
||||
|
||||
{ .set_value_string = string_fvalue_set_string }, /* union set_value */
|
||||
{ .get_value_string = value_get }, /* union get_value */
|
||||
{ .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
|
||||
{ .get_value_strbuf = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_contains, /* cmp_contains */
|
||||
|
@ -278,8 +283,8 @@ ftype_register_string(void)
|
|||
val_from_charconst, /* val_from_charconst */
|
||||
string_to_repr, /* val_to_string_repr */
|
||||
|
||||
{ .set_value_string = string_fvalue_set_string }, /* union set_value */
|
||||
{ .get_value_string = value_get }, /* union get_value */
|
||||
{ .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
|
||||
{ .get_value_strbuf = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_contains, /* cmp_contains */
|
||||
|
@ -310,8 +315,8 @@ ftype_register_string(void)
|
|||
val_from_charconst, /* val_from_charconst */
|
||||
string_to_repr, /* val_to_string_repr */
|
||||
|
||||
{ .set_value_string = string_fvalue_set_string }, /* union set_value */
|
||||
{ .get_value_string = value_get }, /* union get_value */
|
||||
{ .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
|
||||
{ .get_value_strbuf = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_contains, /* cmp_contains */
|
||||
|
|
|
@ -186,7 +186,7 @@ parse_month_name(const char *s, int *tm_mon)
|
|||
#define EXAMPLE "Example: \"Nov 12, 1999 08:55:44.123\" or \"2011-07-04 12:34:56\""
|
||||
|
||||
static gboolean
|
||||
absolute_val_from_string(fvalue_t *fv, const char *s, char **err_msg_ptr)
|
||||
absolute_val_from_string(fvalue_t *fv, const char *s, size_t len _U_, char **err_msg_ptr)
|
||||
{
|
||||
struct tm tm;
|
||||
const char *curptr = NULL;
|
||||
|
@ -310,7 +310,7 @@ fail:
|
|||
static gboolean
|
||||
absolute_val_from_literal(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
|
||||
{
|
||||
return absolute_val_from_string(fv, s, err_msg);
|
||||
return absolute_val_from_string(fv, s, 0, err_msg);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -32,7 +32,7 @@ typedef void (*FvalueCopyFunc)(fvalue_t*, const fvalue_t*);
|
|||
typedef void (*FvalueFreeFunc)(fvalue_t*);
|
||||
|
||||
typedef gboolean (*FvalueFromLiteral)(fvalue_t*, const char*, gboolean, gchar **);
|
||||
typedef gboolean (*FvalueFromString)(fvalue_t*, const char*, gchar **);
|
||||
typedef gboolean (*FvalueFromString)(fvalue_t*, const char*, size_t, gchar **);
|
||||
typedef gboolean (*FvalueFromCharConst)(fvalue_t*, unsigned long, gchar **);
|
||||
typedef char *(*FvalueToStringRepr)(wmem_allocator_t *, const fvalue_t*, ftrepr_t, int field_display);
|
||||
|
||||
|
@ -40,7 +40,7 @@ typedef void (*FvalueSetByteArrayFunc)(fvalue_t*, GByteArray *);
|
|||
typedef void (*FvalueSetBytesFunc)(fvalue_t*, const guint8 *);
|
||||
typedef void (*FvalueSetGuidFunc)(fvalue_t*, const e_guid_t *);
|
||||
typedef void (*FvalueSetTimeFunc)(fvalue_t*, const nstime_t *);
|
||||
typedef void (*FvalueSetStringFunc)(fvalue_t*, const gchar *value);
|
||||
typedef void (*FvalueSetStrbufFunc)(fvalue_t*, wmem_strbuf_t *);
|
||||
typedef void (*FvalueSetProtocolFunc)(fvalue_t*, tvbuff_t *value, const gchar *name, int length);
|
||||
typedef void (*FvalueSetUnsignedIntegerFunc)(fvalue_t*, guint32);
|
||||
typedef void (*FvalueSetSignedIntegerFunc)(fvalue_t*, gint32);
|
||||
|
@ -51,7 +51,7 @@ typedef void (*FvalueSetFloatingFunc)(fvalue_t*, gdouble);
|
|||
typedef const guint8 *(*FvalueGetBytesFunc)(fvalue_t*);
|
||||
typedef const e_guid_t *(*FvalueGetGuidFunc)(fvalue_t*);
|
||||
typedef const nstime_t *(*FvalueGetTimeFunc)(fvalue_t*);
|
||||
typedef const gchar *(*FvalueGetStringFunc)(fvalue_t*);
|
||||
typedef const wmem_strbuf_t *(*FvalueGetStrbufFunc)(fvalue_t*);
|
||||
typedef tvbuff_t *(*FvalueGetProtocolFunc)(fvalue_t*);
|
||||
typedef guint32 (*FvalueGetUnsignedIntegerFunc)(fvalue_t*);
|
||||
typedef gint32 (*FvalueGetSignedIntegerFunc)(fvalue_t*);
|
||||
|
@ -87,7 +87,7 @@ struct _ftype_t {
|
|||
FvalueSetBytesFunc set_value_bytes;
|
||||
FvalueSetGuidFunc set_value_guid;
|
||||
FvalueSetTimeFunc set_value_time;
|
||||
FvalueSetStringFunc set_value_string;
|
||||
FvalueSetStrbufFunc set_value_strbuf;
|
||||
FvalueSetProtocolFunc set_value_protocol;
|
||||
FvalueSetUnsignedIntegerFunc set_value_uinteger;
|
||||
FvalueSetSignedIntegerFunc set_value_sinteger;
|
||||
|
@ -100,7 +100,7 @@ struct _ftype_t {
|
|||
FvalueGetBytesFunc get_value_bytes;
|
||||
FvalueGetGuidFunc get_value_guid;
|
||||
FvalueGetTimeFunc get_value_time;
|
||||
FvalueGetStringFunc get_value_string;
|
||||
FvalueGetStrbufFunc get_value_strbuf;
|
||||
FvalueGetProtocolFunc get_value_protocol;
|
||||
FvalueGetUnsignedIntegerFunc get_value_uinteger;
|
||||
FvalueGetSignedIntegerFunc get_value_sinteger;
|
||||
|
|
|
@ -400,13 +400,13 @@ fvalue_from_literal(ftenum_t ftype, const char *s, gboolean allow_partial_value,
|
|||
}
|
||||
|
||||
fvalue_t*
|
||||
fvalue_from_string(ftenum_t ftype, const char *s, gchar **err_msg)
|
||||
fvalue_from_string(ftenum_t ftype, const char *str, size_t len, gchar **err_msg)
|
||||
{
|
||||
fvalue_t *fv;
|
||||
|
||||
fv = fvalue_new(ftype);
|
||||
if (fv->ftype->val_from_string) {
|
||||
if (fv->ftype->val_from_string(fv, s, err_msg)) {
|
||||
if (fv->ftype->val_from_string(fv, str, len, err_msg)) {
|
||||
/* Success */
|
||||
if (err_msg != NULL)
|
||||
*err_msg = NULL;
|
||||
|
@ -415,8 +415,8 @@ fvalue_from_string(ftenum_t ftype, const char *s, gchar **err_msg)
|
|||
}
|
||||
else {
|
||||
if (err_msg != NULL) {
|
||||
*err_msg = ws_strdup_printf("\"%s\" cannot be converted to %s.",
|
||||
s, ftype_pretty_name(ftype));
|
||||
*err_msg = ws_strdup_printf("%s cannot be converted from a string (\"%s\").",
|
||||
ftype_pretty_name(ftype), str);
|
||||
}
|
||||
}
|
||||
fvalue_free(fv);
|
||||
|
@ -629,9 +629,20 @@ fvalue_set_time(fvalue_t *fv, const nstime_t *value)
|
|||
void
|
||||
fvalue_set_string(fvalue_t *fv, const gchar *value)
|
||||
{
|
||||
wmem_strbuf_t *buf = wmem_strbuf_new(NULL, value);
|
||||
fvalue_set_strbuf(fv, buf);
|
||||
}
|
||||
|
||||
void
|
||||
fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value)
|
||||
{
|
||||
if (value->allocator != NULL) {
|
||||
/* XXX Can this condition be relaxed? */
|
||||
ws_critical("Fvalue strbuf allocator must be NULL");
|
||||
}
|
||||
ws_assert(IS_FT_STRING(fv->ftype->ftype));
|
||||
ws_assert(fv->ftype->set_value.set_value_string);
|
||||
fv->ftype->set_value.set_value_string(fv, value);
|
||||
ws_assert(fv->ftype->set_value.set_value_strbuf);
|
||||
fv->ftype->set_value.set_value_strbuf(fv, value);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -738,10 +749,16 @@ fvalue_get_time(fvalue_t *fv)
|
|||
|
||||
const char *
|
||||
fvalue_get_string(fvalue_t *fv)
|
||||
{
|
||||
return wmem_strbuf_get_str(fvalue_get_strbuf(fv));
|
||||
}
|
||||
|
||||
const wmem_strbuf_t *
|
||||
fvalue_get_strbuf(fvalue_t *fv)
|
||||
{
|
||||
ws_assert(IS_FT_STRING(fv->ftype->ftype));
|
||||
ws_assert(fv->ftype->get_value.get_value_string);
|
||||
return fv->ftype->get_value.get_value_string(fv);
|
||||
ws_assert(fv->ftype->get_value.get_value_strbuf);
|
||||
return fv->ftype->get_value.get_value_strbuf(fv);
|
||||
}
|
||||
|
||||
tvbuff_t *
|
||||
|
|
|
@ -253,8 +253,7 @@ typedef struct _fvalue_t {
|
|||
guint64 uinteger64;
|
||||
gint64 sinteger64;
|
||||
gdouble floating;
|
||||
gchar *string;
|
||||
guchar *ustring;
|
||||
wmem_strbuf_t *strbuf;
|
||||
GByteArray *bytes;
|
||||
ipv4_addr_and_mask ipv4;
|
||||
ipv6_addr_and_prefix ipv6;
|
||||
|
@ -285,8 +284,9 @@ WS_DLL_PUBLIC
|
|||
fvalue_t*
|
||||
fvalue_from_literal(ftenum_t ftype, const char *s, gboolean allow_partial_value, gchar **err_msg);
|
||||
|
||||
/* String *MUST* be null-terminated. Length is optional (pass zero) and does not include the null terminator. */
|
||||
fvalue_t*
|
||||
fvalue_from_string(ftenum_t ftype, const char *s, gchar **err_msg);
|
||||
fvalue_from_string(ftenum_t ftype, const char *s, size_t len, gchar **err_msg);
|
||||
|
||||
fvalue_t*
|
||||
fvalue_from_charconst(ftenum_t ftype, unsigned long number, gchar **err_msg);
|
||||
|
@ -326,6 +326,9 @@ fvalue_set_time(fvalue_t *fv, const nstime_t *value);
|
|||
void
|
||||
fvalue_set_string(fvalue_t *fv, const gchar *value);
|
||||
|
||||
void
|
||||
fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value);
|
||||
|
||||
void
|
||||
fvalue_set_protocol(fvalue_t *fv, tvbuff_t *value, const gchar *name, int length);
|
||||
|
||||
|
@ -360,6 +363,10 @@ WS_DLL_PUBLIC
|
|||
const char *
|
||||
fvalue_get_string(fvalue_t *fv);
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
const wmem_strbuf_t *
|
||||
fvalue_get_strbuf(fvalue_t *fv);
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
tvbuff_t *
|
||||
fvalue_get_protocol(fvalue_t *fv);
|
||||
|
|
|
@ -86,7 +86,7 @@ class case_membership(unittest.TestCase):
|
|||
|
||||
def test_membership_11_bad_rhs_string(self, checkDFilterFail):
|
||||
dfilter = 'frame.number in {1, "foo"}'
|
||||
error = '"foo" cannot be converted to Unsigned integer, 4 bytes.'
|
||||
error = 'Unsigned integer (4 bytes) cannot be converted from a string'
|
||||
checkDFilterFail(dfilter, error)
|
||||
|
||||
def test_membership_12_value_string(self, checkDFilterCount):
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "regex.h"
|
||||
|
||||
#include <wsutil/ws_return.h>
|
||||
#include <wsutil/str_util.h>
|
||||
#include <pcre2.h>
|
||||
|
||||
|
||||
|
@ -43,13 +44,19 @@ get_error_msg(int errorcode)
|
|||
|
||||
|
||||
static pcre2_code *
|
||||
compile_pcre2(const char *patt, char **errmsg, unsigned flags)
|
||||
compile_pcre2(const char *patt, ssize_t size, char **errmsg, unsigned flags)
|
||||
{
|
||||
pcre2_code *code;
|
||||
int errorcode;
|
||||
PCRE2_SIZE length;
|
||||
PCRE2_SIZE erroroffset;
|
||||
uint32_t options = 0;
|
||||
|
||||
if (size < 0)
|
||||
length = PCRE2_ZERO_TERMINATED;
|
||||
else
|
||||
length = (PCRE2_SIZE)size;
|
||||
|
||||
if (flags & WS_REGEX_NEVER_UTF)
|
||||
options |= PCRE2_NEVER_UTF;
|
||||
if (flags & WS_REGEX_CASELESS)
|
||||
|
@ -57,7 +64,7 @@ compile_pcre2(const char *patt, char **errmsg, unsigned flags)
|
|||
|
||||
/* By default UTF-8 is off. */
|
||||
code = pcre2_compile_8((PCRE2_SPTR)patt,
|
||||
PCRE2_ZERO_TERMINATED,
|
||||
length,
|
||||
options,
|
||||
&errorcode,
|
||||
&erroroffset,
|
||||
|
@ -73,27 +80,28 @@ compile_pcre2(const char *patt, char **errmsg, unsigned flags)
|
|||
|
||||
|
||||
ws_regex_t *
|
||||
ws_regex_compile(const char *patt, char **errmsg)
|
||||
{
|
||||
return ws_regex_compile_ex(patt, errmsg, 0);
|
||||
}
|
||||
|
||||
ws_regex_t *
|
||||
ws_regex_compile_ex(const char *patt, char **errmsg, unsigned flags)
|
||||
ws_regex_compile_ex(const char *patt, ssize_t size, char **errmsg, unsigned flags)
|
||||
{
|
||||
ws_return_val_if_null(patt, NULL);
|
||||
|
||||
pcre2_code *code = compile_pcre2(patt, errmsg, flags);
|
||||
pcre2_code *code = compile_pcre2(patt, size, errmsg, flags);
|
||||
if (code == NULL)
|
||||
return NULL;
|
||||
|
||||
ws_regex_t *re = g_new(ws_regex_t, 1);
|
||||
re->code = code;
|
||||
re->pattern = g_strdup(patt);
|
||||
re->pattern = ws_escape_string_len(NULL, patt, size, false);
|
||||
return re;
|
||||
}
|
||||
|
||||
|
||||
ws_regex_t *
|
||||
ws_regex_compile(const char *patt, char **errmsg)
|
||||
{
|
||||
return ws_regex_compile_ex(patt, -1, errmsg, 0);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
match_pcre2(pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length)
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ ws_regex_compile(const char *patt, char **errmsg);
|
|||
#define WS_REGEX_NEVER_UTF (1U << 1)
|
||||
|
||||
WS_DLL_PUBLIC ws_regex_t *
|
||||
ws_regex_compile_ex(const char *patt, char **errmsg, unsigned flags);
|
||||
ws_regex_compile_ex(const char *patt, ssize_t size, char **errmsg, unsigned flags);
|
||||
|
||||
/** Matches a null-terminated subject string. */
|
||||
WS_DLL_PUBLIC bool
|
||||
|
|
|
@ -314,42 +314,6 @@ isdigit_string(const guchar *str)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* Return the first occurrence of needle in haystack.
|
||||
* If not found, return NULL.
|
||||
* If either haystack or needle has 0 length, return NULL.*/
|
||||
const guint8 *
|
||||
ws_memmem(const void *_haystack, size_t haystack_len,
|
||||
const void *_needle, size_t needle_len)
|
||||
{
|
||||
#ifdef HAVE_MEMMEM
|
||||
return memmem(_haystack, haystack_len, _needle, needle_len);
|
||||
#else
|
||||
/* Algorithm copied from GNU's glibc 2.3.2 memmem() under LGPL 2.1+ */
|
||||
const guint8 *haystack = _haystack;
|
||||
const guint8 *needle = _needle;
|
||||
const guint8 *begin;
|
||||
const guint8 *const last_possible = haystack + haystack_len - needle_len;
|
||||
|
||||
if (needle_len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (needle_len > haystack_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (begin = haystack ; begin <= last_possible; ++begin) {
|
||||
if (begin[0] == needle[0] &&
|
||||
!memcmp(&begin[1], needle + 1,
|
||||
needle_len - 1)) {
|
||||
return begin;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif /* HAVE_MEMMEM */
|
||||
}
|
||||
|
||||
const char *
|
||||
ws_strcasestr(const char *haystack, const char *needle)
|
||||
{
|
||||
|
|
|
@ -151,21 +151,6 @@ gboolean isprint_utf8_string(const gchar *str, const guint length);
|
|||
WS_DLL_PUBLIC
|
||||
gboolean isdigit_string(const guchar *str);
|
||||
|
||||
/**
|
||||
* Return the first occurrence of needle in haystack.
|
||||
*
|
||||
* @param haystack The data to search
|
||||
* @param haystack_len The length of the search data
|
||||
* @param needle The string to look for
|
||||
* @param needle_len The length of the search string
|
||||
* @return A pointer to the first occurrence of "needle" in
|
||||
* "haystack". If "needle" isn't found or is NULL, or if
|
||||
* "needle_len" is 0, NULL is returned.
|
||||
*/
|
||||
WS_DLL_PUBLIC
|
||||
const guint8 *ws_memmem(const void *haystack, size_t haystack_len,
|
||||
const void *needle, size_t needle_len);
|
||||
|
||||
/** Finds the first occurrence of string 'needle' in string 'haystack'.
|
||||
* The matching is done in a case insensitive manner.
|
||||
*
|
||||
|
|
|
@ -10,38 +10,16 @@
|
|||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "wmem-int.h"
|
||||
#include "wmem_core.h"
|
||||
#include "wmem_strbuf.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "wmem-int.h"
|
||||
#include "wmem_strutl.h"
|
||||
|
||||
#define DEFAULT_MINIMUM_LEN 16
|
||||
|
||||
/* Holds a wmem-allocated string-buffer.
|
||||
* len is the length of the string (not counting the null-terminator) and
|
||||
* should be the same as strlen(str) unless the string contains embedded
|
||||
* nulls.
|
||||
* alloc_len is the length of the raw buffer pointed to by str, regardless of
|
||||
* what string is actually being stored (i.e. the buffer contents)
|
||||
* max_len is the maximum permitted alloc_len (NOT the maximum permitted len,
|
||||
* which must be one shorter than alloc_len to permit null-termination).
|
||||
* When max_len is 0 (the default), no maximum is enforced.
|
||||
*/
|
||||
struct _wmem_strbuf_t {
|
||||
wmem_allocator_t *allocator;
|
||||
|
||||
gchar *str;
|
||||
|
||||
gsize len;
|
||||
gsize alloc_len;
|
||||
gsize max_len;
|
||||
};
|
||||
|
||||
/* _ROOM accounts for the null-terminator, _RAW_ROOM does not.
|
||||
* Some functions need one, some functions need the other. */
|
||||
#define WMEM_STRBUF_ROOM(S) ((S)->alloc_len - (S)->len - 1)
|
||||
|
@ -69,12 +47,11 @@ wmem_strbuf_sized_new(wmem_allocator_t *allocator,
|
|||
}
|
||||
|
||||
wmem_strbuf_t *
|
||||
wmem_strbuf_new(wmem_allocator_t *allocator, const gchar *str)
|
||||
wmem_strbuf_new_len(wmem_allocator_t *allocator, const gchar *str, size_t len)
|
||||
{
|
||||
wmem_strbuf_t *strbuf;
|
||||
gsize len, alloc_len;
|
||||
gsize alloc_len;
|
||||
|
||||
len = str ? strlen(str) : 0;
|
||||
alloc_len = DEFAULT_MINIMUM_LEN;
|
||||
|
||||
/* +1 for the null-terminator */
|
||||
|
@ -85,13 +62,33 @@ wmem_strbuf_new(wmem_allocator_t *allocator, const gchar *str)
|
|||
strbuf = wmem_strbuf_sized_new(allocator, alloc_len, 0);
|
||||
|
||||
if (str && len > 0) {
|
||||
(void) g_strlcpy(strbuf->str, str, alloc_len);
|
||||
ASSERT(strbuf->alloc_len >= len + 1);
|
||||
memcpy(strbuf->str, str, len);
|
||||
strbuf->str[len] = '\0';
|
||||
strbuf->len = len;
|
||||
}
|
||||
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
wmem_strbuf_t *
|
||||
wmem_strbuf_new(wmem_allocator_t *allocator, const gchar *str)
|
||||
{
|
||||
return wmem_strbuf_new_len(allocator, str, str ? strlen(str) : 0);
|
||||
}
|
||||
|
||||
wmem_strbuf_t *
|
||||
wmem_strbuf_dup(wmem_allocator_t *allocator, const wmem_strbuf_t *src)
|
||||
{
|
||||
wmem_strbuf_t *new;
|
||||
|
||||
new = wmem_strbuf_sized_new(allocator, src->alloc_len, src->max_len);
|
||||
new->len = src->len;
|
||||
memcpy(new->str, src->str, new->len);
|
||||
new->str[new->len] = '\0';
|
||||
return new;
|
||||
}
|
||||
|
||||
/* grows the allocated size of the wmem_strbuf_t. If max_len is set, then
|
||||
* not guaranteed to grow by the full amount to_add */
|
||||
static inline void
|
||||
|
@ -267,17 +264,46 @@ wmem_strbuf_truncate(wmem_strbuf_t *strbuf, const gsize len)
|
|||
}
|
||||
|
||||
const gchar *
|
||||
wmem_strbuf_get_str(wmem_strbuf_t *strbuf)
|
||||
wmem_strbuf_get_str(const wmem_strbuf_t *strbuf)
|
||||
{
|
||||
return strbuf->str;
|
||||
}
|
||||
|
||||
gsize
|
||||
wmem_strbuf_get_len(wmem_strbuf_t *strbuf)
|
||||
wmem_strbuf_get_len(const wmem_strbuf_t *strbuf)
|
||||
{
|
||||
return strbuf->len;
|
||||
}
|
||||
|
||||
static inline int
|
||||
_memcmp_len(const void *s1, size_t s1_len, const void *s2, size_t s2_len)
|
||||
{
|
||||
size_t len;
|
||||
int cmp;
|
||||
|
||||
len = MIN(s1_len, s2_len);
|
||||
if ((cmp = memcmp(s1, s2, len)) != 0)
|
||||
return cmp;
|
||||
if (s1_len < s2_len)
|
||||
return -1;
|
||||
if (s1_len > s2_len)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
int
|
||||
wmem_strbuf_strcmp(const wmem_strbuf_t *sb1, const wmem_strbuf_t *sb2)
|
||||
{
|
||||
return _memcmp_len(sb1->str, sb1->len, sb2->str, sb2->len);
|
||||
}
|
||||
|
||||
const char *
|
||||
wmem_strbuf_strstr(const wmem_strbuf_t *haystack, const wmem_strbuf_t *needle)
|
||||
{
|
||||
return ws_memmem(haystack->str, haystack->len, needle->str, needle->len);
|
||||
}
|
||||
|
||||
/* Truncates the allocated memory down to the minimal amount, frees the header
|
||||
* structure, and returns a non-const pointer to the raw string. The
|
||||
* wmem_strbuf_t structure cannot be used after this is called.
|
||||
|
@ -285,9 +311,10 @@ wmem_strbuf_get_len(wmem_strbuf_t *strbuf)
|
|||
char *
|
||||
wmem_strbuf_finalize(wmem_strbuf_t *strbuf)
|
||||
{
|
||||
char *ret;
|
||||
if (strbuf == NULL)
|
||||
return NULL;
|
||||
|
||||
ret = (char *)wmem_realloc(strbuf->allocator, strbuf->str, strbuf->len+1);
|
||||
char *ret = (char *)wmem_realloc(strbuf->allocator, strbuf->str, strbuf->len+1);
|
||||
|
||||
wmem_free(strbuf->allocator, strbuf);
|
||||
|
||||
|
@ -297,10 +324,11 @@ wmem_strbuf_finalize(wmem_strbuf_t *strbuf)
|
|||
void
|
||||
wmem_strbuf_destroy(wmem_strbuf_t *strbuf)
|
||||
{
|
||||
wmem_allocator_t *allocator = strbuf->allocator;
|
||||
if (strbuf == NULL)
|
||||
return;
|
||||
|
||||
wmem_free(allocator, strbuf->str);
|
||||
wmem_free(allocator, strbuf);
|
||||
wmem_free(strbuf->allocator, strbuf->str);
|
||||
wmem_free(strbuf->allocator, strbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -30,7 +30,26 @@ extern "C" {
|
|||
* @{
|
||||
*/
|
||||
|
||||
struct _wmem_strbuf_t;
|
||||
/* Holds a wmem-allocated string-buffer.
|
||||
* len is the length of the string (not counting the null-terminator) and
|
||||
* should be the same as strlen(str) unless the string contains embedded
|
||||
* nulls.
|
||||
* alloc_len is the length of the raw buffer pointed to by str, regardless of
|
||||
* what string is actually being stored (i.e. the buffer contents)
|
||||
* max_len is the maximum permitted alloc_len (NOT the maximum permitted len,
|
||||
* which must be one shorter than alloc_len to permit null-termination).
|
||||
* When max_len is 0 (the default), no maximum is enforced.
|
||||
*/
|
||||
struct _wmem_strbuf_t {
|
||||
/* read-only fields */
|
||||
wmem_allocator_t *allocator;
|
||||
gchar *str;
|
||||
gsize len;
|
||||
|
||||
/* private fields */
|
||||
gsize alloc_len;
|
||||
gsize max_len;
|
||||
};
|
||||
|
||||
typedef struct _wmem_strbuf_t wmem_strbuf_t;
|
||||
|
||||
|
@ -48,6 +67,16 @@ wmem_strbuf_t *
|
|||
wmem_strbuf_new(wmem_allocator_t *allocator, const gchar *str)
|
||||
G_GNUC_MALLOC;
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
wmem_strbuf_t *
|
||||
wmem_strbuf_new_len(wmem_allocator_t *allocator, const gchar *str, size_t len)
|
||||
G_GNUC_MALLOC;
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
wmem_strbuf_t *
|
||||
wmem_strbuf_dup(wmem_allocator_t *allocator, const wmem_strbuf_t *strbuf)
|
||||
G_GNUC_MALLOC;
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
void
|
||||
wmem_strbuf_append(wmem_strbuf_t *strbuf, const gchar *str);
|
||||
|
@ -82,11 +111,19 @@ wmem_strbuf_truncate(wmem_strbuf_t *strbuf, const gsize len);
|
|||
|
||||
WS_DLL_PUBLIC
|
||||
const gchar *
|
||||
wmem_strbuf_get_str(wmem_strbuf_t *strbuf);
|
||||
wmem_strbuf_get_str(const wmem_strbuf_t *strbuf);
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
gsize
|
||||
wmem_strbuf_get_len(wmem_strbuf_t *strbuf);
|
||||
wmem_strbuf_get_len(const wmem_strbuf_t *strbuf);
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
int
|
||||
wmem_strbuf_strcmp(const wmem_strbuf_t *sb1, const wmem_strbuf_t *sb2);
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
const char *
|
||||
wmem_strbuf_strstr(const wmem_strbuf_t *haystack, const wmem_strbuf_t *needle);
|
||||
|
||||
/** Truncates the allocated memory down to the minimal amount, frees the header
|
||||
* structure, and returns a non-const pointer to the raw string. The
|
||||
|
|
|
@ -109,6 +109,42 @@ wmem_strdup_vprintf(wmem_allocator_t *allocator, const char *fmt, va_list ap)
|
|||
return new_buf;
|
||||
}
|
||||
|
||||
/* Return the first occurrence of needle in haystack.
|
||||
* If not found, return NULL.
|
||||
* If either haystack or needle has 0 length, return NULL.*/
|
||||
const guint8 *
|
||||
ws_memmem(const void *_haystack, size_t haystack_len,
|
||||
const void *_needle, size_t needle_len)
|
||||
{
|
||||
#ifdef HAVE_MEMMEM
|
||||
return memmem(_haystack, haystack_len, _needle, needle_len);
|
||||
#else
|
||||
/* Algorithm copied from GNU's glibc 2.3.2 memmem() under LGPL 2.1+ */
|
||||
const guint8 *haystack = _haystack;
|
||||
const guint8 *needle = _needle;
|
||||
const guint8 *begin;
|
||||
const guint8 *const last_possible = haystack + haystack_len - needle_len;
|
||||
|
||||
if (needle_len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (needle_len > haystack_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (begin = haystack ; begin <= last_possible; ++begin) {
|
||||
if (begin[0] == needle[0] &&
|
||||
!memcmp(&begin[1], needle + 1,
|
||||
needle_len - 1)) {
|
||||
return begin;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif /* HAVE_MEMMEM */
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
|
|
|
@ -57,6 +57,21 @@ G_GNUC_MALLOC;
|
|||
|
||||
#define ws_strdup_vprintf(fmt, ap) wmem_strdup_vprintf(NULL, fmt, ap)
|
||||
|
||||
/**
|
||||
* Return the first occurrence of needle in haystack.
|
||||
*
|
||||
* @param haystack The data to search
|
||||
* @param haystack_len The length of the search data
|
||||
* @param needle The string to look for
|
||||
* @param needle_len The length of the search string
|
||||
* @return A pointer to the first occurrence of "needle" in
|
||||
* "haystack". If "needle" isn't found or is NULL, or if
|
||||
* "needle_len" is 0, NULL is returned.
|
||||
*/
|
||||
WS_DLL_PUBLIC
|
||||
const guint8 *ws_memmem(const void *haystack, size_t haystack_len,
|
||||
const void *needle, size_t needle_len);
|
||||
|
||||
/** @}
|
||||
* @} */
|
||||
|
||||
|
|
Loading…
Reference in New Issue