diff --git a/inotify.c b/inotify.c index 6d04c10..c3dc3f3 100644 --- a/inotify.c +++ b/inotify.c @@ -688,7 +688,7 @@ start_inotify() i += EVENT_SIZE + event->len; continue; } - esc_name = modifyString(strdup(event->name), "&", "&amp;", 0); + esc_name = modifyString(strdup(event->name), "&", "&amp;"); sprintf(path_buf, "%s/%s", get_path_from_wd(event->wd), event->name); if ( event->mask & IN_ISDIR && (event->mask & (IN_CREATE|IN_MOVED_TO)) ) { diff --git a/metadata.h b/metadata.h index 6c62a5d..96364dc 100644 --- a/metadata.h +++ b/metadata.h @@ -82,9 +82,6 @@ typedef enum { int ends_with(const char *haystack, const char *needle); -char * -modifyString(char *string, const char *before, const char *after, short like); - void check_for_captions(const char *path, int64_t detailID); diff --git a/playlist.c b/playlist.c index 7f89d5a..c12222f 100644 --- a/playlist.c +++ b/playlist.c @@ -233,7 +233,7 @@ found: DPRINTF(E_DEBUG, L_SCANNER, "- %s not found in db\n", fname); if( strchr(fname, '\\') ) { - fname = modifyString(fname, "\\", "/", 0); + fname = modifyString(fname, "\\", "/"); goto retry; } else if( (fname = strchr(fname, '/')) ) diff --git a/tivo_commands.c b/tivo_commands.c index 739b5dc..8b7d97c 100644 --- a/tivo_commands.c +++ b/tivo_commands.c @@ -96,11 +96,11 @@ SendRootContainer(struct upnphttp *h) static char * unescape_tag(char *tag) { - modifyString(tag, "&amp;", "&", 0); - modifyString(tag, "&amp;lt;", "<", 0); - modifyString(tag, "&lt;", "<", 0); - modifyString(tag, "&amp;gt;", ">", 0); - modifyString(tag, "&gt;", ">", 0); + modifyString(tag, "&amp;", "&"); + modifyString(tag, "&amp;lt;", "<"); + modifyString(tag, "&lt;", "<"); + modifyString(tag, "&amp;gt;", ">"); + modifyString(tag, "&gt;", ">"); return tag; } diff --git a/upnpsoap.c b/upnpsoap.c index c2acbe0..89fb764 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -1333,6 +1333,254 @@ browse_error: free(str.data); } +inline void +charcat(struct string_s *str, char c) +{ + if (str->size <= str->off) + { + str->data[str->size-1] = '\0'; + return; + } + str->data[str->off] = c; + str->off += 1; +} + +static inline char * +parse_search_criteria(const char *str) +{ + struct string_s criteria; + int len; + int literal = 0, like = 0; + const char *s; + + if (!str) + return strdup("1 = 1"); + + len = strlen(str) + 32; + criteria.data = malloc(len); + criteria.size = len; + criteria.off = 0; + + s = str; + + while (isspace(*s)) + s++; + + while (*s) + { + if (literal) + { + switch (*s) { + case '&': + if (strncmp(s, """, 6) == 0) + s += 5; + else if (strncmp(s, "'", 6) == 0) + { + strcatf(&criteria, "'"); + s += 6; + continue; + } + else + break; + case '"': + literal = 0; + if (like) + { + charcat(&criteria, '%'); + like--; + } + charcat(&criteria, '"'); + break; + case '\\': + if (strncmp(s, "\\"", 7) == 0) + { + strcatf(&criteria, "&quot;"); + s += 7; + continue; + } + break; + case 'o': + if (strncmp(s, "object.", 7) == 0) + s += 7; + default: + charcat(&criteria, *s); + break; + } + } + else + { + switch (*s) { + case '\\': + if (strncmp(s, "\\"", 7) == 0) + { + strcatf(&criteria, "&quot;"); + s += 7; + continue; + } + else + charcat(&criteria, *s); + break; + case '"': + literal = 1; + charcat(&criteria, *s); + if (like == 2) + { + charcat(&criteria, '%'); + like--; + } + break; + case '&': + if (strncmp(s, """, 6) == 0) + { + literal = 1; + strcatf(&criteria, "\""); + if (like == 2) + { + charcat(&criteria, '%'); + like--; + } + s += 5; + } + else if (strncmp(s, "'", 6) == 0) + { + strcatf(&criteria, "'"); + s += 5; + } + else if (strncmp(s, "<", 4) == 0) + { + strcatf(&criteria, "<"); + s += 3; + } + else if (strncmp(s, ">", 4) == 0) + { + strcatf(&criteria, ">"); + s += 3; + } + else + charcat(&criteria, *s); + break; + case '@': + if (strncmp(s, "@refID", 6) == 0) + { + strcatf(&criteria, "REF_ID"); + s += 6; + continue; + } + else if (strncmp(s, "@id", 3) == 0) + { + strcatf(&criteria, "OBJECT_ID"); + s += 3; + continue; + } + else + charcat(&criteria, *s); + break; + case 'c': + if (strncmp(s, "contains", 8) == 0) + { + strcatf(&criteria, "like"); + s += 8; + like = 2; + continue; + } + else + charcat(&criteria, *s); + break; + case 'd': + if (strncmp(s, "derivedfrom", 11) == 0) + { + strcatf(&criteria, "like"); + s += 11; + like = 1; + continue; + } + else if (strncmp(s, "dc:date", 7) == 0) + { + strcatf(&criteria, "d.DATE"); + s += 7; + continue; + } + else if (strncmp(s, "dc:title", 8) == 0) + { + strcatf(&criteria, "d.TITLE"); + s += 8; + continue; + } + else if (strncmp(s, "dc:creator", 10) == 0) + { + strcatf(&criteria, "d.CREATOR"); + s += 10; + continue; + } + else + charcat(&criteria, *s); + break; + case 'e': + if (strncmp(s, "exists", 6) == 0) + { + s += 6; + while (isspace(*s)) + s++; + if (strncmp(s, "true", 4) == 0) + { + strcatf(&criteria, "is not NULL"); + s += 3; + } + else if (strncmp(s, "false", 5) == 0) + { + strcatf(&criteria, "is NULL"); + s += 4; + } + } + else + charcat(&criteria, *s); + break; + case 'u': + if (strncmp(s, "upnp:class", 10) == 0) + { + strcatf(&criteria, "o.CLASS"); + s += 10; + continue; + } + else if (strncmp(s, "upnp:actor", 10) == 0) + { + strcatf(&criteria, "d.ARTIST"); + s += 10; + continue; + } + else if (strncmp(s, "upnp:artist", 11) == 0) + { + strcatf(&criteria, "d.ARTIST"); + s += 11; + continue; + } + else if (strncmp(s, "upnp:album", 10) == 0) + { + strcatf(&criteria, "d.ALBUM"); + s += 10; + continue; + } + else if (strncmp(s, "upnp:genre", 10) == 0) + { + strcatf(&criteria, "d.GENRE"); + s += 10; + continue; + } + else + charcat(&criteria, *s); + break; + default: + charcat(&criteria, *s); + break; + } + } + s++; + } + charcat(&criteria, '\0'); + + return criteria.data; +} + static void SearchContentDirectory(struct upnphttp * h, const char * action) { @@ -1349,7 +1597,7 @@ SearchContentDirectory(struct upnphttp * h, const char * action) int totalMatches; int ret; char *ContainerID, *Filter, *SearchCriteria, *SortCriteria; - char *newSearchCriteria = NULL, *orderBy = NULL; + char *orderBy = NULL; char groupBy[] = "group by DETAIL_ID"; struct NameValueParserData data; int RequestedCount = 0; @@ -1426,49 +1674,8 @@ SearchContentDirectory(struct upnphttp * h, const char * action) *ContainerID = '*'; else if( strcmp(ContainerID, MUSIC_ALL_ID) == 0 ) groupBy[0] = '\0'; - if( !SearchCriteria ) - { - newSearchCriteria = strdup("1 = 1"); - SearchCriteria = newSearchCriteria; - } - else - { - SearchCriteria = modifyString(SearchCriteria, """, "\"", 0); - SearchCriteria = modifyString(SearchCriteria, "'", "'", 0); - SearchCriteria = modifyString(SearchCriteria, "<", "<", 0); - SearchCriteria = modifyString(SearchCriteria, ">", ">", 0); - SearchCriteria = modifyString(SearchCriteria, "object.", "", 0); - SearchCriteria = modifyString(SearchCriteria, "derivedfrom", "like", 1); - SearchCriteria = modifyString(SearchCriteria, "contains", "like", 2); - SearchCriteria = modifyString(SearchCriteria, "dc:date", "d.DATE", 0); - SearchCriteria = modifyString(SearchCriteria, "dc:title", "d.TITLE", 0); - SearchCriteria = modifyString(SearchCriteria, "dc:creator", "d.CREATOR", 0); - SearchCriteria = modifyString(SearchCriteria, "upnp:class", "o.CLASS", 0); - SearchCriteria = modifyString(SearchCriteria, "upnp:actor", "d.ARTIST", 0); - SearchCriteria = modifyString(SearchCriteria, "upnp:artist", "d.ARTIST", 0); - SearchCriteria = modifyString(SearchCriteria, "upnp:album", "d.ALBUM", 0); - SearchCriteria = modifyString(SearchCriteria, "upnp:genre", "d.GENRE", 0); - SearchCriteria = modifyString(SearchCriteria, "exists true", "is not NULL", 0); - SearchCriteria = modifyString(SearchCriteria, "exists false", "is NULL", 0); - SearchCriteria = modifyString(SearchCriteria, "@refID", "REF_ID", 0); - if( strstr(SearchCriteria, "@id") ) - { - newSearchCriteria = strdup(SearchCriteria); - SearchCriteria = newSearchCriteria = modifyString(newSearchCriteria, "@id", "OBJECT_ID", 0); - } - if( strstr(SearchCriteria, "res is ") ) - { - if( !newSearchCriteria ) - newSearchCriteria = strdup(SearchCriteria); - SearchCriteria = newSearchCriteria = modifyString(newSearchCriteria, "res is ", "MIME is ", 0); - } - if( strstr(SearchCriteria, "\\\"") ) - { - if( !newSearchCriteria ) - newSearchCriteria = strdup(SearchCriteria); - SearchCriteria = newSearchCriteria = modifyString(newSearchCriteria, "\\\"", "&quot;", 0); - } - } + + SearchCriteria = parse_search_criteria(SearchCriteria); DPRINTF(E_DEBUG, L_HTTP, "Translated SearchCriteria: %s\n", SearchCriteria); totalMatches = sql_get_int_field(db, "SELECT (select count(distinct DETAIL_ID)" @@ -1538,7 +1745,7 @@ search_error: if( args.flags & FLAG_FREE_OBJECT_ID ) sqlite3_free(ContainerID); free(orderBy); - free(newSearchCriteria); + free(SearchCriteria); free(str.data); } diff --git a/utils.c b/utils.c index 76ddc51..38daad6 100644 --- a/utils.c +++ b/utils.c @@ -164,14 +164,14 @@ strcasestrc(const char *s, const char *p, const char t) } char * -modifyString(char * string, const char * before, const char * after, short like) +modifyString(char * string, const char * before, const char * after) { int oldlen, newlen, chgcnt = 0; - char *s, *p, *t; + char *s, *p; oldlen = strlen(before); newlen = strlen(after); - if( newlen+like > oldlen ) + if( newlen > oldlen ) { s = string; while( (p = strstr(s, before)) ) @@ -179,7 +179,7 @@ modifyString(char * string, const char * before, const char * after, short like) chgcnt++; s = p+oldlen; } - s = realloc(string, strlen(string)+((newlen-oldlen)*chgcnt)+1+like); + s = realloc(string, strlen(string)+((newlen-oldlen)*chgcnt)+1); /* If we failed to realloc, return the original alloc'd string */ if( s ) string = s; @@ -195,24 +195,6 @@ modifyString(char * string, const char * before, const char * after, short like) return string; memmove(p + newlen, p + oldlen, strlen(p + oldlen) + 1); memcpy(p, after, newlen); - if( like ) - { - t = p+newlen; - while( isspace(*t) ) - t++; - if( *t == '"' ) - { - if( like == 2 ) - { - memmove(t+2, t+1, strlen(t+1)+1); - *++t = '%'; - } - while( *++t != '"' ) - continue; - memmove(t+1, t, strlen(t)+1); - *t = '%'; - } - } s = p + newlen; } @@ -227,10 +209,10 @@ escape_tag(const char *tag, int force_alloc) if( strchr(tag, '&') || strchr(tag, '<') || strchr(tag, '>') || strchr(tag, '"') ) { esc_tag = strdup(tag); - esc_tag = modifyString(esc_tag, "&", "&amp;", 0); - esc_tag = modifyString(esc_tag, "<", "&lt;", 0); - esc_tag = modifyString(esc_tag, ">", "&gt;", 0); - esc_tag = modifyString(esc_tag, "\"", "&quot;", 0); + esc_tag = modifyString(esc_tag, "&", "&amp;"); + esc_tag = modifyString(esc_tag, "<", "&lt;"); + esc_tag = modifyString(esc_tag, ">", "&gt;"); + esc_tag = modifyString(esc_tag, "\"", "&quot;"); } else if( force_alloc ) esc_tag = strdup(tag); diff --git a/utils.h b/utils.h index 4eb4d32..7bf22a8 100644 --- a/utils.h +++ b/utils.h @@ -48,7 +48,7 @@ char * strcasestrc(const char *s, const char *p, const char t); char * -modifyString(char * string, const char * before, const char * after, short like); +modifyString(char * string, const char * before, const char * after); char * escape_tag(const char *tag, int force_alloc);