diff --git a/upnpsoap.c b/upnpsoap.c
index af5992a..bd263a5 100644
--- a/upnpsoap.c
+++ b/upnpsoap.c
@@ -203,7 +203,80 @@ GetCurrentConnectionInfo(struct upnphttp * h, const char * action)
BuildSendAndCloseSoapResp(h, body, bodylen);
}
-static int callback(void *args, int argc, char **argv, char **azColName)
+#define FILTER_CHILDCOUNT 0x00000001
+#define FILTER_DC_CREATOR 0x00000002
+#define FILTER_DC_DATE 0x00000004
+#define FILTER_DC_DESCRIPTION 0x00000008
+#define FILTER_DLNA_NAMESPACE 0x00000010
+#define FILTER_REFID 0x00000020
+#define FILTER_RES 0x00000040
+#define FILTER_RES_BITRATE 0x00000080
+#define FILTER_RES_DURATION 0x00000100
+#define FILTER_RES_NRAUDIOCHANNELS 0x00000200
+#define FILTER_RES_RESOLUTION 0x00000400
+#define FILTER_RES_SAMPLEFREQUENCY 0x00000800
+#define FILTER_RES_SIZE 0x00001000
+#define FILTER_UPNP_ALBUM 0x00002000
+#define FILTER_UPNP_ALBUMARTURI 0x00004000
+#define FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID 0x00008000
+#define FILTER_UPNP_ARTIST 0x00010000
+#define FILTER_UPNP_GENRE 0x00020000
+#define FILTER_UPNP_ORIGINALTRACKNUMBER 0x00040000
+#define FILTER_UPNP_SEARCHCLASS 0x00080000
+
+static u_int32_t
+set_filter_flags(char * filter)
+{
+ u_int32_t flags = 0;
+
+ if( !filter || (strlen(filter) <= 1) )
+ return 0xFFFFFFFF;
+ if( strstr(filter, "@childCount") )
+ flags |= FILTER_CHILDCOUNT;
+ if( strstr(filter, "dc:creator") )
+ flags |= FILTER_DC_CREATOR;
+ if( strstr(filter, "dc:date") )
+ flags |= FILTER_DC_DATE;
+ if( strstr(filter, "dc:description") )
+ flags |= FILTER_DC_DESCRIPTION;
+ if( strstr(filter, "dlna") )
+ flags |= FILTER_DLNA_NAMESPACE;
+ if( strstr(filter, "@refID") )
+ flags |= FILTER_REFID;
+ if( strstr(filter, "res") )
+ flags |= FILTER_RES;
+ if( strstr(filter, "res@bitrate") )
+ flags |= FILTER_RES_BITRATE;
+ if( strstr(filter, "res@duration") )
+ flags |= FILTER_RES_DURATION;
+ if( strstr(filter, "res@nrAudioChannels") )
+ flags |= FILTER_RES_NRAUDIOCHANNELS;
+ if( strstr(filter, "res@resolution") )
+ flags |= FILTER_RES_RESOLUTION;
+ if( strstr(filter, "res@sampleFrequency") )
+ flags |= FILTER_RES_SAMPLEFREQUENCY;
+ if( strstr(filter, "res@size") )
+ flags |= FILTER_RES_SIZE;
+ if( strstr(filter, "upnp:album") )
+ flags |= FILTER_UPNP_ALBUM;
+ if( strstr(filter, "upnp:albumArtURI") )
+ flags |= FILTER_UPNP_ALBUMARTURI;
+ if( strstr(filter, "upnp:albumArtURI@dlna:profileID") )
+ flags |= FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID;
+ if( strstr(filter, "upnp:artist") )
+ flags |= FILTER_UPNP_ARTIST;
+ if( strstr(filter, "upnp:genre") )
+ flags |= FILTER_UPNP_GENRE;
+ if( strstr(filter, "upnp:originalTrackNumber") )
+ flags |= FILTER_UPNP_ORIGINALTRACKNUMBER;
+ if( strstr(filter, "upnp:searchClass") )
+ flags |= FILTER_UPNP_SEARCHCLASS;
+
+ return flags;
+}
+
+static int
+callback(void *args, int argc, char **argv, char **azColName)
{
struct Response *passed_args = (struct Response *)args;
char *id = argv[1], *parent = argv[2], *refID = argv[3], *class = argv[4], *detailID = argv[5], *size = argv[9], *title = argv[10],
@@ -211,14 +284,22 @@ static int callback(void *args, int argc, char **argv, char **azColName)
*genre = argv[16], *comment = argv[17], *nrAudioChannels = argv[18], *track = argv[19], *date = argv[20], *resolution = argv[21],
*tn = argv[22], *creator = argv[23], *dlna_pn = argv[24], *mime = argv[25], *album_art = argv[26], *art_dlna_pn = argv[27];
char dlna_buf[64];
- char str_buf[4096];
+ char str_buf[512];
char **result;
- int ret;
+ int children, ret = 0;
+ static int warned = 0;
passed_args->total++;
if( passed_args->requested && (passed_args->returned >= passed_args->requested) )
return 0;
+ /* Make sure we have at least 4KB left of allocated memory to finish the response. */
+ if( passed_args->size > 1044480 && !warned )
+ {
+ DPRINTF(E_ERROR, L_HTTP, "UPnP SOAP response is getting too big! [%d returned]\n", passed_args->returned);
+ warned = 1;
+ return 0;
+ }
passed_args->returned++;
if( dlna_pn )
@@ -238,92 +319,115 @@ static int callback(void *args, int argc, char **argv, char **azColName)
mime[9] = '\0';
}
}
- sprintf(str_buf, "<item id=\"%s\" parentID=\"%s\" restricted=\"1\"", id, parent);
- strcat(passed_args->resp, str_buf);
- if( refID && (!passed_args->filter || strstr(passed_args->filter, "@refID")) ) {
- sprintf(str_buf, " refID=\"%s\"", refID);
- strcat(passed_args->resp, str_buf);
+ ret = sprintf(str_buf, "<item id=\"%s\" parentID=\"%s\" restricted=\"1\"", id, parent);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ if( refID && (passed_args->filter & FILTER_REFID) ) {
+ ret = sprintf(str_buf, " refID=\"%s\"", refID);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- sprintf(str_buf, ">"
- "<dc:title>%s</dc:title>"
- "<upnp:class>object.%s</upnp:class>",
- title, class);
- strcat(passed_args->resp, str_buf);
- if( comment && (!passed_args->filter || strstr(passed_args->filter, "dc:description")) ) {
- sprintf(str_buf, "<dc:description>%s</dc:description>", comment);
- strcat(passed_args->resp, str_buf);
+ ret = sprintf(str_buf, ">"
+ "<dc:title>%s</dc:title>"
+ "<upnp:class>object.%s</upnp:class>",
+ title, class);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ if( comment && (passed_args->filter & FILTER_DC_DESCRIPTION) ) {
+ ret = sprintf(str_buf, "<dc:description>%s</dc:description>", comment);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( creator && (!passed_args->filter || strstr(passed_args->filter, "dc:creator")) ) {
- sprintf(str_buf, "<dc:creator>%s</dc:creator>", creator);
- strcat(passed_args->resp, str_buf);
+ if( creator && (passed_args->filter & FILTER_DC_CREATOR) ) {
+ ret = sprintf(str_buf, "<dc:creator>%s</dc:creator>", creator);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( date && (!passed_args->filter || strstr(passed_args->filter, "dc:date")) ) {
- sprintf(str_buf, "<dc:date>%s</dc:date>", date);
- strcat(passed_args->resp, str_buf);
+ if( date && (passed_args->filter & FILTER_DC_DATE) ) {
+ ret = sprintf(str_buf, "<dc:date>%s</dc:date>", date);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( artist && (!passed_args->filter || strstr(passed_args->filter, "upnp:artist")) ) {
- sprintf(str_buf, "<upnp:artist>%s</upnp:artist>", artist);
- strcat(passed_args->resp, str_buf);
+ if( artist && (passed_args->filter & FILTER_UPNP_ARTIST) ) {
+ ret = sprintf(str_buf, "<upnp:artist>%s</upnp:artist>", artist);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( album && (!passed_args->filter || strstr(passed_args->filter, "upnp:album")) ) {
- sprintf(str_buf, "<upnp:album>%s</upnp:album>", album);
- strcat(passed_args->resp, str_buf);
+ if( album && (passed_args->filter & FILTER_UPNP_ALBUM) ) {
+ ret = sprintf(str_buf, "<upnp:album>%s</upnp:album>", album);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( genre && (!passed_args->filter || strstr(passed_args->filter, "upnp:genre")) ) {
- sprintf(str_buf, "<upnp:genre>%s</upnp:genre>", genre);
- strcat(passed_args->resp, str_buf);
+ if( genre && (passed_args->filter & FILTER_UPNP_GENRE) ) {
+ ret = sprintf(str_buf, "<upnp:genre>%s</upnp:genre>", genre);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( track && atoi(track) && (!passed_args->filter || strstr(passed_args->filter, "upnp:originalTrackNumber")) ) {
- sprintf(str_buf, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", track);
- strcat(passed_args->resp, str_buf);
+ if( track && atoi(track) && (passed_args->filter & FILTER_UPNP_ORIGINALTRACKNUMBER) ) {
+ ret = sprintf(str_buf, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", track);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( album_art && atoi(album_art) && (!passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI")) ) {
- strcat(passed_args->resp, "<upnp:albumArtURI ");
- if( !passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI@dlna:profileID") ) {
- sprintf(str_buf, "dlna:profileID=\"%s\" xmlns:dlna=\"urn:schemas-dlnaorg:metadata-1-0/\"", art_dlna_pn);
- strcat(passed_args->resp, str_buf);
+ if( album_art && atoi(album_art) && (passed_args->filter & FILTER_UPNP_ALBUMARTURI) ) {
+ ret = sprintf(str_buf, "<upnp:albumArtURI ");
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ if( passed_args->filter & FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID ) {
+ ret = sprintf(str_buf, "dlna:profileID=\"%s\" xmlns:dlna=\"urn:schemas-dlnaorg:metadata-1-0/\"", art_dlna_pn);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- sprintf(str_buf, ">http://%s:%d/AlbumArt/%s.jpg</upnp:albumArtURI>",
+ ret = sprintf(str_buf, ">http://%s:%d/AlbumArt/%s.jpg</upnp:albumArtURI>",
lan_addr[0].str, runtime_vars.port, album_art);
- strcat(passed_args->resp, str_buf);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( !passed_args->filter || strstr(passed_args->filter, "res") ) {
- strcat(passed_args->resp, "<res ");
- if( size && (!passed_args->filter || strstr(passed_args->filter, "res@size")) ) {
- sprintf(str_buf, "size=\"%s\" ", size);
- strcat(passed_args->resp, str_buf);
+ if( passed_args->filter & FILTER_RES ) {
+ ret = sprintf(str_buf, "<res ");
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ if( size && (passed_args->filter & FILTER_RES_SIZE) ) {
+ ret = sprintf(str_buf, "size=\"%s\" ", size);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( duration && (!passed_args->filter || strstr(passed_args->filter, "res@duration")) ) {
- sprintf(str_buf, "duration=\"%s\" ", duration);
- strcat(passed_args->resp, str_buf);
+ if( duration && (passed_args->filter & FILTER_RES_DURATION) ) {
+ ret = sprintf(str_buf, "duration=\"%s\" ", duration);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( bitrate && (!passed_args->filter || strstr(passed_args->filter, "res@bitrate")) ) {
+ if( bitrate && (passed_args->filter & FILTER_RES_BITRATE) ) {
if( passed_args->client == EXbox )
- sprintf(str_buf, "bitrate=\"%d\" ", atoi(bitrate)/1024);
+ ret = sprintf(str_buf, "bitrate=\"%d\" ", atoi(bitrate)/1024);
else
- sprintf(str_buf, "bitrate=\"%s\" ", bitrate);
- strcat(passed_args->resp, str_buf);
+ ret = sprintf(str_buf, "bitrate=\"%s\" ", bitrate);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( sampleFrequency && (!passed_args->filter || strstr(passed_args->filter, "res@sampleFrequency")) ) {
- sprintf(str_buf, "sampleFrequency=\"%s\" ", sampleFrequency);
- strcat(passed_args->resp, str_buf);
+ if( sampleFrequency && (passed_args->filter & FILTER_RES_SAMPLEFREQUENCY) ) {
+ ret = sprintf(str_buf, "sampleFrequency=\"%s\" ", sampleFrequency);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( nrAudioChannels && (!passed_args->filter || strstr(passed_args->filter, "res@nrAudioChannels")) ) {
- sprintf(str_buf, "nrAudioChannels=\"%s\" ", nrAudioChannels);
- strcat(passed_args->resp, str_buf);
+ if( nrAudioChannels && (passed_args->filter & FILTER_RES_NRAUDIOCHANNELS) ) {
+ ret = sprintf(str_buf, "nrAudioChannels=\"%s\" ", nrAudioChannels);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( resolution && (!passed_args->filter || strstr(passed_args->filter, "res@resolution")) ) {
- sprintf(str_buf, "resolution=\"%s\" ", resolution);
- strcat(passed_args->resp, str_buf);
+ if( resolution && (passed_args->filter & FILTER_RES_RESOLUTION) ) {
+ ret = sprintf(str_buf, "resolution=\"%s\" ", resolution);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\">"
- "http://%s:%d/MediaItems/%s.dat"
- "</res>",
- mime, dlna_buf, lan_addr[0].str, runtime_vars.port, detailID);
+ ret = sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\">"
+ "http://%s:%d/MediaItems/%s.dat"
+ "</res>",
+ mime, dlna_buf, lan_addr[0].str, runtime_vars.port, detailID);
#if 0 //JPEG_RESIZE
if( dlna_pn && (strncmp(dlna_pn, "JPEG_LRG", 8) == 0) ) {
- strcat(passed_args->resp, str_buf);
- sprintf(str_buf, "<res "
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ ret = sprintf(str_buf, "<res "
"protocolInfo=\"http-get:*:%s:%s\">"
"http://%s:%d/Resized/%s"
"</res>",
@@ -331,70 +435,90 @@ static int callback(void *args, int argc, char **argv, char **azColName)
}
#endif
if( tn && atoi(tn) && dlna_pn ) {
- strcat(passed_args->resp, str_buf);
- strcat(passed_args->resp, "<res ");
- sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\">"
- "http://%s:%d/Thumbnails/%s.dat"
- "</res>",
- mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str, runtime_vars.port, detailID);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ ret = sprintf(str_buf, "<res protocolInfo=\"http-get:*:%s:%s\">"
+ "http://%s:%d/Thumbnails/%s.dat"
+ "</res>",
+ mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str, runtime_vars.port, detailID);
}
- strcat(passed_args->resp, str_buf);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- strcpy(str_buf, "</item>");
+ ret = sprintf(str_buf, "</item>");
}
else if( strncmp(class, "container", 9) == 0 )
{
- sprintf(str_buf, "SELECT count(ID) from OBJECTS where PARENT_ID = '%s';", id);
- ret = sql_get_table(db, str_buf, &result, NULL, NULL);
- sprintf(str_buf, "<container id=\"%s\" parentID=\"%s\" restricted=\"1\" ", id, parent);
- strcat(passed_args->resp, str_buf);
- if( !passed_args->filter || strstr(passed_args->filter, "@childCount"))
+ ret = sprintf(str_buf, "<container id=\"%s\" parentID=\"%s\" restricted=\"1\" ", id, parent);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ if( passed_args->filter & FILTER_CHILDCOUNT )
{
- sprintf(str_buf, "childCount=\"%s\"", result[1]);
- strcat(passed_args->resp, str_buf);
+ sprintf(str_buf, "SELECT count(ID) from OBJECTS where PARENT_ID = '%s';", id);
+ ret = sql_get_table(db, str_buf, &result, NULL, NULL);
+ if( ret == SQLITE_OK ) {
+ children = atoi(result[1]);
+ sqlite3_free_table(result);
+ }
+ else {
+ children = 0;
+ }
+ ret = sprintf(str_buf, "childCount=\"%d\"", children);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
/* If the client calls for BrowseMetadata on root, we have to include our "upnp:searchClass"'s, unless they're filtered out */
if( (passed_args->requested == 1) && (strcmp(id, "0") == 0) )
{
- if( !passed_args->filter || strstr(passed_args->filter, "upnp:searchClass") )
+ if( passed_args->filter & FILTER_UPNP_SEARCHCLASS )
{
- strcat(passed_args->resp, ">"
- "<upnp:searchClass includeDerived=\"1\">object.item.audioItem</upnp:searchClass>"
- "<upnp:searchClass includeDerived=\"1\">object.item.imageItem</upnp:searchClass>"
- "<upnp:searchClass includeDerived=\"1\">object.item.videoItem</upnp:searchClass");
+ ret = sprintf(str_buf, ">"
+ "<upnp:searchClass includeDerived=\"1\">object.item.audioItem</upnp:searchClass>"
+ "<upnp:searchClass includeDerived=\"1\">object.item.imageItem</upnp:searchClass>"
+ "<upnp:searchClass includeDerived=\"1\">object.item.videoItem</upnp:searchClass");
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
}
- sprintf(str_buf, ">"
- "<dc:title>%s</dc:title>"
- "<upnp:class>object.%s</upnp:class>",
- title, class);
- strcat(passed_args->resp, str_buf);
- if( creator && (!passed_args->filter || strstr(passed_args->filter, "dc:creator")) ) {
- sprintf(str_buf, "<dc:creator>%s</dc:creator>", creator);
- strcat(passed_args->resp, str_buf);
+ ret = sprintf(str_buf, ">"
+ "<dc:title>%s</dc:title>"
+ "<upnp:class>object.%s</upnp:class>",
+ title, class);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ if( creator && (passed_args->filter & FILTER_DC_CREATOR) ) {
+ ret = sprintf(str_buf, "<dc:creator>%s</dc:creator>", creator);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( genre && (!passed_args->filter || strstr(passed_args->filter, "upnp:genre")) ) {
- sprintf(str_buf, "<upnp:genre>%s</upnp:genre>", genre);
- strcat(passed_args->resp, str_buf);
+ if( genre && (passed_args->filter & FILTER_UPNP_GENRE) ) {
+ ret = sprintf(str_buf, "<upnp:genre>%s</upnp:genre>", genre);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( artist && (!passed_args->filter || strstr(passed_args->filter, "upnp:artist")) ) {
- sprintf(str_buf, "<upnp:artist>%s</upnp:artist>", artist);
- strcat(passed_args->resp, str_buf);
+ if( artist && (passed_args->filter & FILTER_UPNP_ARTIST) ) {
+ ret = sprintf(str_buf, "<upnp:artist>%s</upnp:artist>", artist);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- if( album_art && atoi(album_art) && (!passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI")) ) {
- strcat(passed_args->resp, "<upnp:albumArtURI ");
- if( !passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI@dlna:profileID") ) {
- sprintf(str_buf, "dlna:profileID=\"%s\" xmlns:dlna=\"urn:schemas-dlnaorg:metadata-1-0/\"", art_dlna_pn);
- strcat(passed_args->resp, str_buf);
+ if( album_art && atoi(album_art) && (passed_args->filter & FILTER_UPNP_ALBUMARTURI) ) {
+ ret = sprintf(str_buf, "<upnp:albumArtURI ");
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
+ if( passed_args->filter & FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID ) {
+ ret = sprintf(str_buf, "dlna:profileID=\"%s\" xmlns:dlna=\"urn:schemas-dlnaorg:metadata-1-0/\"", art_dlna_pn);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- sprintf(str_buf, ">http://%s:%d/AlbumArt/%s.jpg</upnp:albumArtURI>",
+ ret = sprintf(str_buf, ">http://%s:%d/AlbumArt/%s.jpg</upnp:albumArtURI>",
lan_addr[0].str, runtime_vars.port, album_art);
- strcat(passed_args->resp, str_buf);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
}
- sprintf(str_buf, "</container>");
- sqlite3_free_table(result);
+ ret = sprintf(str_buf, "</container>");
}
- strcat(passed_args->resp, str_buf);
+ memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
+ passed_args->size += ret;
return 0;
}
@@ -408,11 +532,9 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
""
"<DIDL-Lite"
CONTENT_DIRECTORY_SCHEMAS;
- static const char resp1[] = "</DIDL-Lite>";
- static const char resp2[] = "";
char *resp = malloc(1048576);
- char str_buf[4096];
+ char str_buf[512];
char *zErrMsg = 0;
char *sql;
int ret;
@@ -429,20 +551,25 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
if( !ObjectId )
ObjectId = GetValueFromNameValueList(&data, "ContainerID");
-
- memset(str_buf, '\0', sizeof(str_buf));
memset(&args, 0, sizeof(args));
- strcpy(resp, resp0);
+
+ args.resp = resp;
+ args.size = sprintf(resp, "%s", resp0);
/* See if we need to include DLNA namespace reference */
- if( Filter && ((strlen(Filter) <= 1) || strstr(Filter, "dlna")) )
- strcat(resp, DLNA_NAMESPACE);
- strcat(resp, ">\n");
+ args.filter = set_filter_flags(Filter);
+ if( args.filter & FILTER_DLNA_NAMESPACE )
+ {
+ ret = sprintf(str_buf, DLNA_NAMESPACE);
+ memcpy(resp+args.size, &str_buf, ret+1);
+ args.size += ret;
+ }
+ ret = sprintf(str_buf, ">\n");
+ memcpy(resp+args.size, &str_buf, ret+1);
+ args.size += ret;
args.total = StartingIndex;
args.returned = 0;
args.requested = RequestedCount;
- args.resp = NULL;
- args.filter = NULL;
args.client = h->req_client;
if( h->req_client == EXbox )
{
@@ -463,10 +590,6 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
ObjectId, RequestedCount, StartingIndex,
BrowseFlag, Filter, SortCriteria);
- if( Filter && (strlen(Filter) > 1) )
- args.filter = Filter;
-
- args.resp = resp;
if( strcmp(BrowseFlag, "BrowseMetadata") == 0 )
{
args.requested = 1;
@@ -486,14 +609,15 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
DPRINTF(E_ERROR, L_HTTP, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
- strcat(resp, resp1);
- sprintf(str_buf, "\n%u\n"
- "%u\n"
- "%u",
- args.returned, args.total, updateID);
- strcat(resp, str_buf);
- strcat(resp, resp2);
- BuildSendAndCloseSoapResp(h, resp, strlen(resp));
+ ret = snprintf(str_buf, sizeof(str_buf), "</DIDL-Lite>\n"
+ "%u\n"
+ "%u\n"
+ "%u"
+ "",
+ args.returned, args.total, updateID);
+ memcpy(resp+args.size, &str_buf, ret+1);
+ args.size += ret;
+ BuildSendAndCloseSoapResp(h, resp, args.size);
ClearNameValueList(&data);
free(resp);
if( h->req_client == EXbox )
@@ -511,8 +635,6 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
""
"<DIDL-Lite"
CONTENT_DIRECTORY_SCHEMAS;
- static const char resp1[] = "</DIDL-Lite>";
- static const char resp2[] = "";
char *resp = malloc(1048576);
char *zErrMsg = 0;
@@ -534,11 +656,23 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
memset(&args, 0, sizeof(args));
- args.total = 0;
+ args.resp = resp;
+ args.size = sprintf(resp, "%s", resp0);
+ /* See if we need to include DLNA namespace reference */
+ args.filter = set_filter_flags(Filter);
+ if( args.filter & FILTER_DLNA_NAMESPACE )
+ {
+ ret = sprintf(str_buf, DLNA_NAMESPACE);
+ memcpy(resp+args.size, &str_buf, ret+1);
+ args.size += ret;
+ }
+ ret = sprintf(str_buf, ">\n");
+ memcpy(resp+args.size, &str_buf, ret+1);
+ args.size += ret;
+
+ args.total = StartingIndex;
args.returned = 0;
args.requested = RequestedCount;
- args.resp = NULL;
- args.filter = NULL;
args.client = h->req_client;
if( h->req_client == EXbox )
{
@@ -563,14 +697,6 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
ContainerID, RequestedCount, StartingIndex,
SearchCriteria, Filter, SortCriteria);
- strcpy(resp, resp0);
- /* See if we need to include DLNA namespace reference */
- if( Filter && ((strlen(Filter) <= 1) || strstr(Filter, "dlna")) )
- strcat(resp, DLNA_NAMESPACE);
- strcat(resp, ">\n");
-
- if( Filter && (strlen(Filter) > 1) )
- args.filter = Filter;
if( strcmp(ContainerID, "0") == 0 )
*ContainerID = '*';
if( !SearchCriteria )
@@ -603,7 +729,6 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
}
DPRINTF(E_DEBUG, L_HTTP, "Translated SearchCriteria: %s\n", SearchCriteria);
- args.resp = resp;
sql = sqlite3_mprintf("SELECT distinct * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
" where OBJECT_ID glob '%s$*' and (%s) group by DETAIL_ID "
"%z"
@@ -621,14 +746,16 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
sqlite3_free(zErrMsg);
}
sqlite3_free(sql);
- strcat(resp, resp1);
- sprintf(str_buf, "\n%u\n"
- "%u\n"
- "%u",
- args.returned, args.total, updateID);
strcat(resp, str_buf);
- strcat(resp, resp2);
- BuildSendAndCloseSoapResp(h, resp, strlen(resp));
+ ret = snprintf(str_buf, sizeof(str_buf), "</DIDL-Lite>\n"
+ "%u\n"
+ "%u\n"
+ "%u"
+ "",
+ args.returned, args.total, updateID);
+ memcpy(resp+args.size, &str_buf, ret+1);
+ args.size += ret;
+ BuildSendAndCloseSoapResp(h, resp, args.size);
ClearNameValueList(&data);
if( newSearchCriteria )
free(newSearchCriteria);
diff --git a/upnpsoap.h b/upnpsoap.h
index 689ca71..c910213 100644
--- a/upnpsoap.h
+++ b/upnpsoap.h
@@ -21,7 +21,8 @@ struct Response
int returned;
int requested;
int total;
- char *filter;
+ int size;
+ u_int32_t filter;
enum clientType client;
};