Skip to content

Commit

Permalink
add gf_strmemstr (close to the non-portable memmem()) to use instead …
Browse files Browse the repository at this point in the history
…of strstr when buffer may not be null terminated

improves 826a40d
  • Loading branch information
aureliendavid committed Mar 6, 2024
1 parent 12d7665 commit d9da11e
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 47 deletions.
13 changes: 11 additions & 2 deletions include/gpac/tools.h
Expand Up @@ -296,6 +296,16 @@ Search a substring in a string without checking for case
*/
Bool gf_strnistr(const char *text, const char *subtext, u32 subtext_len);

/*!
\brief search string in buffer
Search for a substring in a memory buffer of characters that may not be null-terminated
\param data buffer of chars in which to search
\param data_size size of data buffer
\param pat pattern to search for as a null-terminated string
\return a pointer to the first occurrence of pat in data, or null if not found (may not be null-terminated)
*/
const char* gf_strmemstr(const char *data, u32 data_size, const char *pat);

/*!
\brief safe timestamp rescale
Expand Down Expand Up @@ -2308,7 +2318,7 @@ Bool gf_creds_check_membership(const char *username, const char *users, const ch

/*to call whenever the OpenGL library is opened - this function is needed to bind OpenGL and remotery, and to load
OpenGL extensions on windows
not exported, and not included in src/compositor/gl_inc.h since it may be needed even when no OpenGL
not exported, and not included in src/compositor/gl_inc.h since it may be needed even when no OpenGL
calls are made by the caller*/
void gf_opengl_init();

Expand Down Expand Up @@ -2373,4 +2383,3 @@ void gf_gl_txw_reset(GF_GLTextureWrapper *tx);


#endif /*_GF_CORE_H_*/

43 changes: 12 additions & 31 deletions src/filters/load_bt_xmt.c
Expand Up @@ -825,23 +825,6 @@ static void ctxload_finalize(GF_Filter *filter)
}
}

static const char* my_strstr(const char *str, const char *pat, u32 str_len)
{
u32 len_pat = (u32) strlen(pat);
if (len_pat>str_len) return NULL;
//basically a memmem clone (we don't use for portability reasons)
while (1) {
char *next = memchr(str, pat[0], str_len);
if (!next) return NULL;
u32 left = str_len - (u32) (next-str);
if (left<len_pat) return NULL;
if (!memcmp(next, pat, len_pat)) return next;
//left is always at least 1
str_len = left-1;
str = next+1;
}
return NULL;
}
#include <gpac/utf.h>
static const char *ctxload_probe_data(const u8 *probe_data, u32 size, GF_FilterProbeScore *score)
{
Expand Down Expand Up @@ -882,7 +865,7 @@ static const char *ctxload_probe_data(const u8 *probe_data, u32 size, GF_FilterP
} else {
break;
}
const char *res = my_strstr(probe_data, search, probe_size);
const char *res = gf_strmemstr(probe_data, probe_size, search);
if (!res) goto exit;
res += strlen(search);
probe_size -= (u32) (res - (char*)probe_data);
Expand All @@ -895,24 +878,24 @@ static const char *ctxload_probe_data(const u8 *probe_data, u32 size, GF_FilterP
//probe_data is now the first element of the document, if XML
//we should refine by getting the xmlns attribute value rather than searching for its value...

if (my_strstr(probe_data, "http://www.w3.org/1999/XSL/Transform", probe_size)
if (gf_strmemstr(probe_data, probe_size, "http://www.w3.org/1999/XSL/Transform")
) {
} else if (!strncmp(probe_data, "<XMT-A", strlen("<XMT-A"))
|| my_strstr(probe_data, "urn:mpeg:mpeg4:xmta:schema:2002", probe_size)
|| gf_strmemstr(probe_data, probe_size, "urn:mpeg:mpeg4:xmta:schema:2002")
) {
mime_type = "application/x-xmt";
} else if (my_strstr(probe_data, "<X3D", probe_size)
|| my_strstr(probe_data, "http://www.web3d.org/specifications/x3d-3.0.xsd", probe_size)
} else if (gf_strmemstr(probe_data, probe_size, "<X3D")
|| gf_strmemstr(probe_data, probe_size, "http://www.web3d.org/specifications/x3d-3.0.xsd")
) {
mime_type = "model/x3d+xml";
} else if (my_strstr(probe_data, "<saf", probe_size)
|| my_strstr(probe_data, "urn:mpeg:mpeg4:SAF:2005", probe_size)
|| my_strstr(probe_data, "urn:mpeg:mpeg4:LASeR:2005", probe_size)
} else if (gf_strmemstr(probe_data, probe_size, "<saf")
|| gf_strmemstr(probe_data, probe_size, "urn:mpeg:mpeg4:SAF:2005")
|| gf_strmemstr(probe_data, probe_size, "urn:mpeg:mpeg4:LASeR:2005")
) {
mime_type = "application/x-LASeR+xml";
} else if (!strncmp(probe_data, "<DIMSStream", strlen("<DIMSStream") ) ) {
mime_type = "application/dims";
} else if (!strncmp(probe_data, "<svg", 4) || my_strstr(probe_data, "http://www.w3.org/2000/svg", probe_size) ) {
} else if (!strncmp(probe_data, "<svg", 4) || gf_strmemstr(probe_data, probe_size, "http://www.w3.org/2000/svg") ) {
mime_type = "image/svg+xml";
} else if (!strncmp(probe_data, "<widget", strlen("<widget") ) ) {
mime_type = "application/widget";
Expand Down Expand Up @@ -955,12 +938,12 @@ static const char *ctxload_probe_data(const u8 *probe_data, u32 size, GF_FilterP
break;
}
//skip line and go one
const char *next = my_strstr(probe_data, "\n", probe_size);
const char *next = gf_strmemstr(probe_data, probe_size, "\n");
if (!next) goto exit;
probe_size -= (u32) (next - (char*)probe_data);
probe_data = next;
}

if (!strncmp(probe_data, "InitialObjectDescriptor", strlen("InitialObjectDescriptor"))
|| !strncmp(probe_data, "EXTERNPROTO", strlen("EXTERNPROTO"))
|| !strncmp(probe_data, "PROTO", strlen("PROTO"))
Expand All @@ -969,7 +952,7 @@ static const char *ctxload_probe_data(const u8 *probe_data, u32 size, GF_FilterP
|| !strncmp(probe_data, "Layer2D", strlen("Layer2D"))
|| !strncmp(probe_data, "Layer3D", strlen("Layer3D"))
) {
if (my_strstr(probe_data, "children", probe_size))
if (gf_strmemstr(probe_data, probe_size, "children"))
mime_type = "application/x-bt";
}
}
Expand Down Expand Up @@ -1032,5 +1015,3 @@ const GF_FilterRegister *btplay_register(GF_FilterSession *session)
return NULL;
#endif
}


17 changes: 6 additions & 11 deletions src/filters/load_text.c
Expand Up @@ -4347,24 +4347,21 @@ static const char *txtin_probe_data(const u8 *data, u32 data_size, GF_FilterProb
GF_Err e = gf_utf_get_string_from_bom((char *)data, data_size, &dst, &res, &res_size);
if (e) return NULL;

u8 orig_end = res[res_size-1];
res[res_size-1] = 0;
data = res;
//strip all spaces and \r\n\t
while (data[0] && strchr("\n\r\t ", (char) data[0]))
data ++;

#define PROBE_OK(_score, _mime) \
*score = _score;\
res[res_size-1] = orig_end;\
if (dst) gf_free(dst);\
return _mime; \


if (!strncmp(data, "WEBVTT", 6)) {
PROBE_OK(GF_FPROBE_SUPPORTED, "subtitle/vtt")
}
if (strstr(data, " --> ")) {
if (gf_strmemstr(data, res_size, " --> ")) {
PROBE_OK(GF_FPROBE_MAYBE_SUPPORTED, "subtitle/srt")
}
if (!strncmp(data, "FWS", 3) || !strncmp(data, "CWS", 3)) {
Expand All @@ -4374,28 +4371,26 @@ static const char *txtin_probe_data(const u8 *data, u32 data_size, GF_FilterProb
PROBE_OK(GF_FPROBE_MAYBE_SUPPORTED, "subtitle/ssa")
}

if ((data[0]=='{') && strstr(data, "}{")) {
if ((data[0]=='{') && gf_strmemstr(data, res_size, "}{")) {
PROBE_OK(GF_FPROBE_MAYBE_SUPPORTED, "subtitle/sub")

}
/*XML formats*/
if (!strstr(data, "?>") ) {
res[res_size-1] = orig_end;
if (!gf_strmemstr(data, res_size, "?>") ) {
if (dst) gf_free(dst);
return NULL;
}

if (strstr(data, "<x-quicktime-tx3g") || strstr(data, "<text3GTrack")) {
if (gf_strmemstr(data, res_size, "<x-quicktime-tx3g") || gf_strmemstr(data, res_size, "<text3GTrack")) {
PROBE_OK(GF_FPROBE_MAYBE_SUPPORTED, "quicktime/text")
}
if (strstr(data, "TextStream")) {
if (gf_strmemstr(data, res_size, "TextStream")) {
PROBE_OK(GF_FPROBE_MAYBE_SUPPORTED, "subtitle/ttxt")
}
if (strstr(data, "<tt ") || strstr(data, ":tt ")) {
if (gf_strmemstr(data, res_size, "<tt ") || gf_strmemstr(data, res_size, ":tt ")) {
PROBE_OK(GF_FPROBE_MAYBE_SUPPORTED, "subtitle/ttml")
}

res[res_size-1] = orig_end;
if (dst) gf_free(dst);
return NULL;
}
Expand Down
26 changes: 24 additions & 2 deletions src/utils/error.c
Expand Up @@ -2172,6 +2172,28 @@ Bool gf_parse_frac(const char *value, GF_Fraction *frac)

Bool gf_strict_atoi(const char* str, int* ans) {
char* end_ptr = NULL;
*ans = strtol(str, &end_ptr, 10);
*ans = strtol(str, &end_ptr, 10);
return !isspace(*str) && end_ptr != str && *end_ptr == '\0';
}
}

const char* gf_strmemstr(const char *data, u32 data_size, const char *pat)
{
if (!pat || !data) return NULL;

u32 len_pat = (u32) strlen(pat);
if (len_pat==0) return data;
if (len_pat>data_size) return NULL;

//basically a memmem clone (we don't use for portability reasons)
while (1) {
char *next = memchr(data, pat[0], data_size);
if (!next) return NULL;
u32 left = data_size - (u32) (next-data);
if (left<len_pat) return NULL;
if (!memcmp(next, pat, len_pat)) return next;
//left is always at least 1
data_size = left-1;
data = next+1;
}
return NULL;
}

0 comments on commit d9da11e

Please sign in to comment.