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:
João Valverde 2022-06-18 10:43:24 +01:00 committed by A Wireshark GitLab Utility
parent d372ed3483
commit 47348ae598
26 changed files with 351 additions and 224 deletions

View File

@ -135,6 +135,9 @@ They previously shipped with Qt 5.12.2.
** The display filter engine now uses PCRE2 instead of GRegex (GLibs 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`.

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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 = {

View File

@ -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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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 *

View File

@ -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);

View File

@ -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):

View File

@ -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)
{

View File

@ -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

View File

@ -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)
{

View File

@ -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.
*

View File

@ -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);
}
/*

View File

@ -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

View File

@ -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
*

View File

@ -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);
/** @}
* @} */