Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/azatoth/minidlna.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Fürstenberg <azatoth@gmail.com>2011-05-17 02:12:35 +0400
committerCarl Fürstenberg <azatoth@gmail.com>2011-05-17 02:12:35 +0400
commit5a4b5b380148dd8448d6b0264ed0e8cf7bb948ee (patch)
tree329b466fd95a8934abff84edc50ef5370f32126d
parentbc77a548639e4accb6a499d382fef8979639b16b (diff)
parente320bc63ba9057fc1b2617ba3f6188bd736b5719 (diff)
Merge commit 'e320bc63ba9057fc1b2617ba3f6188bd736b5719'v1.0.19.2
Conflicts: upnpsoap.c
-rw-r--r--minidlnatypes.h6
-rw-r--r--tivo_commands.c201
-rw-r--r--upnpglobalvars.h2
-rw-r--r--upnpsoap.c368
-rw-r--r--upnpsoap.h11
-rw-r--r--utils.c14
-rw-r--r--utils.h3
7 files changed, 245 insertions, 360 deletions
diff --git a/minidlnatypes.h b/minidlnatypes.h
index e4c8a90..594dac5 100644
--- a/minidlnatypes.h
+++ b/minidlnatypes.h
@@ -46,6 +46,12 @@ struct runtime_vars_s {
int notify_interval; /* seconds between SSDP announces */
};
+struct string_s {
+ char *data; // ptr to start of memory area
+ int off;
+ int size;
+};
+
enum media_types {
ALL_MEDIA,
AUDIO_ONLY,
diff --git a/tivo_commands.c b/tivo_commands.c
index 746b443..7c7afbd 100644
--- a/tivo_commands.c
+++ b/tivo_commands.c
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <libgen.h>
#include <time.h>
#include "tivo_utils.h"
@@ -86,7 +87,8 @@ SendRootContainer(struct upnphttp * h)
"</Content>"
"</Links>"
"</Item>"
- "</TiVoContainer>", friendly_name, friendly_name, friendly_name, friendly_name);
+ "</TiVoContainer>",
+ friendly_name, friendly_name, friendly_name, friendly_name);
BuildResp_upnphttp(h, resp, len);
free(resp);
SendResp_upnphttp(h);
@@ -112,8 +114,8 @@ int callback(void *args, int argc, char **argv, char **azColName)
char *id = argv[0], *class = argv[1], *detailID = argv[2], *size = argv[3], *title = argv[4], *duration = argv[5],
*bitrate = argv[6], *sampleFrequency = argv[7], *artist = argv[8], *album = argv[9], *genre = argv[10],
*comment = argv[11], *date = argv[12], *resolution = argv[13], *mime = argv[14], *path = argv[15];
- char str_buf[4096];
int ret = 0;
+ struct string_s *str = passed_args->str;
if( strncmp(class, "item", 4) == 0 )
{
@@ -122,44 +124,34 @@ int callback(void *args, int argc, char **argv, char **azColName)
if( strncmp(mime, "audio", 5) == 0 )
{
flags |= FLAG_NO_PARAMS;
- ret = sprintf(str_buf, "<Item><Details>"
- "<ContentType>audio/*</ContentType>"
- "<SourceFormat>%s</SourceFormat>"
- "<SourceSize>%s</SourceSize>"
- "<SongTitle>%s</SongTitle>", mime, size, title);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<Item><Details>"
+ "<ContentType>audio/*</ContentType>"
+ "<SourceFormat>%s</SourceFormat>"
+ "<SourceSize>%s</SourceSize>"
+ "<SongTitle>%s</SongTitle>", mime, size, title);
if( date )
{
- ret = sprintf(str_buf, "<AlbumYear>%.*s</AlbumYear>", 4, date);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<AlbumYear>%.*s</AlbumYear>", 4, date);
}
}
else if( strcmp(mime, "image/jpeg") == 0 )
{
flags |= FLAG_SEND_RESIZED;
- ret = sprintf(str_buf, "<Item><Details>"
- "<ContentType>image/*</ContentType>"
- "<SourceFormat>image/jpeg</SourceFormat>"
- "<SourceSize>%s</SourceSize>", size);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<Item><Details>"
+ "<ContentType>image/*</ContentType>"
+ "<SourceFormat>image/jpeg</SourceFormat>"
+ "<SourceSize>%s</SourceSize>", size);
if( date )
{
struct tm tm;
memset(&tm, 0, sizeof(tm));
tm.tm_isdst = -1; // Have libc figure out if DST is in effect or not
strptime(date, "%Y-%m-%dT%H:%M:%S", &tm);
- ret = sprintf(str_buf, "<CaptureDate>0x%X</CaptureDate>", (unsigned int)mktime(&tm));
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<CaptureDate>0x%X</CaptureDate>", (unsigned int)mktime(&tm));
}
if( comment )
{
- ret = sprintf(str_buf, "<Caption>%s</Caption>", comment);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<Caption>%s</Caption>", comment);
}
}
else if( strncmp(mime, "video", 5) == 0 )
@@ -167,111 +159,85 @@ int callback(void *args, int argc, char **argv, char **azColName)
char *episode;
flags |= FLAG_NO_PARAMS;
flags |= FLAG_VIDEO;
- ret = sprintf(str_buf, "<Item><Details>"
- "<ContentType>video/x-tivo-mpeg</ContentType>"
- "<SourceFormat>%s</SourceFormat>"
- "<SourceSize>%s</SourceSize>", mime, size);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<Item><Details>"
+ "<ContentType>video/x-tivo-mpeg</ContentType>"
+ "<SourceFormat>%s</SourceFormat>"
+ "<SourceSize>%s</SourceSize>", mime, size);
episode = strstr(title, " - ");
if( episode )
{
- ret = sprintf(str_buf, "<Title>%.*s</Title>"
- "<EpisodeTitle>%s</EpisodeTitle>",
- episode-title, title, episode+3);
+ ret = strcatf(str, "<Title>%.*s</Title>"
+ "<EpisodeTitle>%s</EpisodeTitle>",
+ (int)(episode-title), title, episode+3);
}
else
{
- ret = sprintf(str_buf, "<Title>%s</Title>", title);
+ ret = strcatf(str, "<Title>%s</Title>", title);
}
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
if( date )
{
struct tm tm;
memset(&tm, 0, sizeof(tm));
tm.tm_isdst = -1; // Have libc figure out if DST is in effect or not
strptime(date, "%Y-%m-%dT%H:%M:%S", &tm);
- ret = sprintf(str_buf, "<CaptureDate>0x%X</CaptureDate>", (unsigned int)mktime(&tm));
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<CaptureDate>0x%X</CaptureDate>", (unsigned int)mktime(&tm));
}
if( comment )
{
- ret = sprintf(str_buf, "<Description>%s</Description>", comment);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<Description>%s</Description>", comment);
}
}
else
{
return 0;
}
- ret = sprintf(str_buf, "<Title>%s</Title>", unescape_tag(title));
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<Title>%s</Title>", unescape_tag(title));
if( artist ) {
- ret = sprintf(str_buf, "<ArtistName>%s</ArtistName>", unescape_tag(artist));
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<ArtistName>%s</ArtistName>", unescape_tag(artist));
}
if( album ) {
- ret = sprintf(str_buf, "<AlbumTitle>%s</AlbumTitle>", unescape_tag(album));
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<AlbumTitle>%s</AlbumTitle>", unescape_tag(album));
}
if( genre ) {
- ret = sprintf(str_buf, "<MusicGenre>%s</MusicGenre>", unescape_tag(genre));
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<MusicGenre>%s</MusicGenre>", unescape_tag(genre));
}
if( resolution ) {
char *width = strsep(&resolution, "x");
- ret = sprintf(str_buf, "<SourceWidth>%s</SourceWidth>"
- "<SourceHeight>%s</SourceHeight>",
- width, resolution);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<SourceWidth>%s</SourceWidth>"
+ "<SourceHeight>%s</SourceHeight>",
+ width, resolution);
}
if( duration ) {
- ret = sprintf(str_buf, "<Duration>%d</Duration>",
+ ret = strcatf(str, "<Duration>%d</Duration>",
atoi(strrchr(duration, '.')+1) + (1000*atoi(strrchr(duration, ':')+1))
+ (60000*atoi(strrchr(duration, ':')-2)) + (3600000*atoi(duration)));
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
}
if( bitrate ) {
- ret = sprintf(str_buf, "<SourceBitRate>%s</SourceBitRate>", bitrate);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<SourceBitRate>%s</SourceBitRate>", bitrate);
}
if( sampleFrequency ) {
- ret = sprintf(str_buf, "<SourceSampleRate>%s</SourceSampleRate>", sampleFrequency);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
- }
- ret = sprintf(str_buf, "</Details><Links><Content>"
- "<ContentType>%s</ContentType>"
- "<Url>/%s/%s.dat</Url>%s</Content>",
- mime,
- (flags & FLAG_SEND_RESIZED)?"Resized":"MediaItems", detailID,
- (flags & FLAG_NO_PARAMS)?"<AcceptsParams>No</AcceptsParams>":"");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "<SourceSampleRate>%s</SourceSampleRate>", sampleFrequency);
+ }
+ ret = strcatf(str, "</Details><Links><Content>"
+ "<ContentType>%s</ContentType>"
+ "<Url>/%s/%s.dat</Url>%s</Content>",
+ mime,
+ (flags & FLAG_SEND_RESIZED)?"Resized":"MediaItems", detailID,
+ (flags & FLAG_NO_PARAMS)?"<AcceptsParams>No</AcceptsParams>":"");
if( flags & FLAG_VIDEO )
{
char *esc_name = escape_tag(basename(path), 1);
- ret = sprintf(str_buf, "<CustomIcon>"
- "<ContentType>video/*</ContentType>"
- "<Url>urn:tivo:image:save-until-i-delete-recording</Url>"
- "</CustomIcon>"
- "<Push><Container>Videos</Container></Push>"
- "<File>%s</File> </Links>", esc_name);
+ ret = strcatf(str, "<CustomIcon>"
+ "<ContentType>video/*</ContentType>"
+ "<Url>urn:tivo:image:save-until-i-delete-recording</Url>"
+ "</CustomIcon>"
+ "<Push><Container>Videos</Container></Push>"
+ "<File>%s</File> </Links>", esc_name);
free(esc_name);
}
else
{
- ret = sprintf(str_buf, "</Links>");
+ ret = strcatf(str, "</Links>");
}
}
else if( strncmp(class, "container", 9) == 0 )
@@ -285,26 +251,22 @@ int callback(void *args, int argc, char **argv, char **azColName)
" (MIME in ('image/jpeg', 'audio/mpeg', 'video/mpeg', 'video/x-tivo-mpeg')"
" or CLASS glob 'container*')", id);
#endif
- ret = sprintf(str_buf, "<Item>"
- "<Details>"
- "<ContentType>x-container/folder</ContentType>"
- "<SourceFormat>x-container/folder</SourceFormat>"
- "<Title>%s</Title>"
- "<TotalItems>%d</TotalItems>"
- "</Details>"
- "<Links>"
- "<Content>"
- "<Url>/TiVoConnect?Command=QueryContainer&amp;Container=%s</Url>"
- "<ContentType>x-tivo-container/folder</ContentType>"
- "</Content>"
- "</Links>",
- unescape_tag(title), count, id);
+ ret = strcatf(str, "<Item>"
+ "<Details>"
+ "<ContentType>x-container/folder</ContentType>"
+ "<SourceFormat>x-container/folder</SourceFormat>"
+ "<Title>%s</Title>"
+ "<TotalItems>%d</TotalItems>"
+ "</Details>"
+ "<Links>"
+ "<Content>"
+ "<Url>/TiVoConnect?Command=QueryContainer&amp;Container=%s</Url>"
+ "<ContentType>x-tivo-container/folder</ContentType>"
+ "</Content>"
+ "</Links>",
+ unescape_tag(title), count, id);
}
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
- ret = sprintf(str_buf, "</Item>");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "</Item>");
passed_args->returned++;
@@ -322,11 +284,13 @@ SendItemDetails(struct upnphttp * h, sqlite_int64 item)
char *sql;
char *zErrMsg = NULL;
struct Response args;
+ struct string_s str;
int ret;
memset(&args, 0, sizeof(args));
+ memset(&str, 0, sizeof(str));
- args.resp = resp;
- args.size = sprintf(resp, "<?xml version='1.0' encoding='UTF-8' ?>\n<TiVoItem>");
+ str.data = resp;
+ ret = strcatf(&str, "<?xml version='1.0' encoding='UTF-8' ?>\n<TiVoItem>");
args.requested = 1;
asprintf(&sql, SELECT_COLUMNS
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
@@ -339,10 +303,10 @@ SendItemDetails(struct upnphttp * h, sqlite_int64 item)
DPRINTF(E_ERROR, L_HTTP, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
- strcat(resp, "</TiVoItem>");
+ strcatf(&str, "</TiVoItem>");
- BuildResp_upnphttp(h, resp, strlen(resp));
- free(resp);
+ BuildResp_upnphttp(h, str.data, str.off);
+ free(str.data);
SendResp_upnphttp(h);
}
@@ -360,12 +324,15 @@ SendContainer(struct upnphttp * h, const char * objectID, int itemStart, int ite
char type[8];
char groupBy[19] = {0};
struct Response args;
+ struct string_s str;
int totalMatches = 0;
int i, ret;
memset(&args, 0, sizeof(args));
+ memset(&str, 0, sizeof(str));
- args.resp = resp;
- args.size = 1024;
+ args.str = &str;
+ str.data = resp+1024;
+ str.size = 262144-1024;
if( itemCount >= 0 )
{
args.requested = itemCount;
@@ -655,6 +622,7 @@ SendContainer(struct upnphttp * h, const char * objectID, int itemStart, int ite
free(resp);
return;
}
+ strcatf(&str, "</TiVoContainer>");
ret = sprintf(str_buf, "<?xml version='1.0' encoding='UTF-8' ?>\n"
"<TiVoContainer>"
@@ -667,15 +635,12 @@ SendContainer(struct upnphttp * h, const char * objectID, int itemStart, int ite
"<ItemStart>%d</ItemStart>"
"<ItemCount>%d</ItemCount>",
type, totalMatches, title, args.start, args.returned);
- args.resp = resp+1024-ret;
- memcpy(args.resp, &str_buf, ret);
- ret = sprintf(str_buf, "</TiVoContainer>");
- memcpy(resp+args.size, &str_buf, ret+1);
- args.size += ret;
- args.size -= args.resp-resp;
+ str.data -= ret;
+ memcpy(str.data, &str_buf, ret);
+ str.size = str.off+ret;
free(title);
free(which);
- BuildResp_upnphttp(h, args.resp, args.size);
+ BuildResp_upnphttp(h, str.data, str.size);
free(resp);
SendResp_upnphttp(h);
}
@@ -698,7 +663,7 @@ ProcessTiVoCommand(struct upnphttp * h, const char * orig_path)
item = strtok_r( path, "&", &saveptr );
while( item != NULL )
{
- if( strlen(item) == 0 )
+ if( *item == '\0' )
{
item = strtok_r( NULL, "&", &saveptr );
continue;
diff --git a/upnpglobalvars.h b/upnpglobalvars.h
index 093a5a3..44dec82 100644
--- a/upnpglobalvars.h
+++ b/upnpglobalvars.h
@@ -58,7 +58,7 @@
#include <sqlite3.h>
-#define MINIDLNA_VERSION "1.0.19.1"
+#define MINIDLNA_VERSION "1.0.19.2"
#ifdef NETGEAR
# define SERVER_NAME "ReadyDLNA"
diff --git a/upnpsoap.c b/upnpsoap.c
index 2202ede..e6aead6 100644
--- a/upnpsoap.c
+++ b/upnpsoap.c
@@ -63,13 +63,12 @@
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "upnpglobalvars.h"
+#include "utils.h"
#include "upnphttp.h"
#include "upnpsoap.h"
#include "upnpreplyparse.h"
#include "getifaddr.h"
-
#include "scanner.h"
-#include "utils.h"
#include "sql.h"
#include "log.h"
@@ -557,17 +556,13 @@ inline static void
add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn,
char *detailID, struct Response *passed_args)
{
- int ret;
int dstw = reqw;
int dsth = reqh;
- char str_buf[256];
if( passed_args->flags & FLAG_NO_RESIZE )
return;
- ret = sprintf(str_buf, "&lt;res ");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ strcatf(passed_args->str, "&lt;res ");
if( passed_args->filter & FILTER_RES_RESOLUTION )
{
dstw = reqw;
@@ -576,17 +571,12 @@ add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn,
dsth = reqh;
dstw = (((reqh<<10)/srch) * srcw>>10);
}
- ret = sprintf(str_buf, "resolution=\"%dx%d\" ", dstw, dsth);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ strcatf(passed_args->str, "resolution=\"%dx%d\" ", dstw, dsth);
}
- ret = sprintf(str_buf, "protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=%s;DLNA.ORG_CI=1\"&gt;"
- "http://%s:%d/Resized/%s.jpg?width=%d,height=%d"
- "&lt;/res&gt;",
- dlna_pn, lan_addr[0].str, runtime_vars.port,
- detailID, dstw, dsth);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ strcatf(passed_args->str, "protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=%s;DLNA.ORG_CI=1\"&gt;"
+ "http://%s:%d/Resized/%s.jpg?width=%d,height=%d"
+ "&lt;/res&gt;",
+ dlna_pn, lan_addr[0].str, runtime_vars.port, detailID, dstw, dsth);
}
inline static void
@@ -594,48 +584,30 @@ add_res(char *size, char *duration, char *bitrate, char *sampleFrequency,
char *nrAudioChannels, char *resolution, char *dlna_pn, char *mime,
char *detailID, char *ext, struct Response *passed_args)
{
- int ret;
- char str_buf[256];
-
- ret = sprintf(str_buf, "&lt;res ");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ strcatf(passed_args->str, "&lt;res ");
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;
+ strcatf(passed_args->str, "size=\"%s\" ", size);
}
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;
+ strcatf(passed_args->str, "duration=\"%s\" ", duration);
}
if( bitrate && (passed_args->filter & FILTER_RES_BITRATE) ) {
- ret = sprintf(str_buf, "bitrate=\"%s\" ", bitrate);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ strcatf(passed_args->str, "bitrate=\"%s\" ", bitrate);
}
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;
+ strcatf(passed_args->str, "sampleFrequency=\"%s\" ", sampleFrequency);
}
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;
+ strcatf(passed_args->str, "nrAudioChannels=\"%s\" ", nrAudioChannels);
}
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;
+ strcatf(passed_args->str, "resolution=\"%s\" ", resolution);
}
- ret = snprintf(str_buf, sizeof(str_buf), "protocolInfo=\"http-get:*:%s:%s\"&gt;"
- "http://%s:%d/MediaItems/%s.%s"
- "&lt;/res&gt;",
- mime, dlna_pn, lan_addr[0].str, runtime_vars.port, detailID, ext);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ strcatf(passed_args->str, "protocolInfo=\"http-get:*:%s:%s\"&gt;"
+ "http://%s:%d/MediaItems/%s.%s"
+ "&lt;/res&gt;",
+ mime, dlna_pn, lan_addr[0].str,
+ runtime_vars.port, detailID, ext);
}
#define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.PARENT_ID, o.REF_ID, o.DETAIL_ID, o.CLASS," \
@@ -653,21 +625,22 @@ callback(void *args, int argc, char **argv, char **azColName)
*tn = argv[18], *creator = argv[19], *dlna_pn = argv[20], *mime = argv[21], *album_art = argv[22];
char dlna_buf[96];
char ext[5];
- char str_buf[512];
+ struct string_s *str = passed_args->str;
int ret = 0;
- /* Make sure we have at least 4KB left of allocated memory to finish the response. */
- if( passed_args->size > (passed_args->alloced - 4096) )
+ /* Make sure we have at least 8KB left of allocated memory to finish the response. */
+ if( str->off > (str->size - 8192) )
{
#if MAX_RESPONSE_SIZE > 0
- if( (passed_args->alloced+1048576) <= MAX_RESPONSE_SIZE )
+ if( (str->size+DEFAULT_RESP_SIZE) <= MAX_RESPONSE_SIZE )
{
#endif
- passed_args->resp = realloc(passed_args->resp, (passed_args->alloced+1048576));
- if( passed_args->resp )
+ str->data = realloc(str->data, (str->off+DEFAULT_RESP_SIZE));
+ if( str->data )
{
- passed_args->alloced += 1048576;
- DPRINTF(E_DEBUG, L_HTTP, "HUGE RESPONSE ALERT: UPnP SOAP response had to be enlarged to %d. [%d results so far]\n", passed_args->alloced, passed_args->returned);
+ str->size += DEFAULT_RESP_SIZE;
+ DPRINTF(E_DEBUG, L_HTTP, "UPnP SOAP response enlarged to %d. [%d results so far]\n",
+ str->size, passed_args->returned);
}
else
{
@@ -741,120 +714,85 @@ callback(void *args, int argc, char **argv, char **azColName)
}
}
- ret = snprintf(str_buf, 512, "&lt;item id=\"%s\" parentID=\"%s\" restricted=\"1\"", id, parent);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;item id=\"%s\" parentID=\"%s\" restricted=\"1\"", id, parent);
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;
- }
- ret = snprintf(str_buf, 512, "&gt;"
- "&lt;dc:title&gt;%s&lt;/dc:title&gt;"
- "&lt;upnp:class&gt;object.%s&lt;/upnp:class&gt;",
- title, class);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, " refID=\"%s\"", refID);
+ }
+ ret = strcatf(str, "&gt;"
+ "&lt;dc:title&gt;%s&lt;/dc:title&gt;"
+ "&lt;upnp:class&gt;object.%s&lt;/upnp:class&gt;",
+ title, class);
if( comment && (passed_args->filter & FILTER_DC_DESCRIPTION) ) {
- ret = snprintf(str_buf, 512, "&lt;dc:description&gt;%.384s&lt;/dc:description&gt;", comment);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;dc:description&gt;%.384s&lt;/dc:description&gt;", comment);
}
if( creator && (passed_args->filter & FILTER_DC_CREATOR) ) {
- ret = snprintf(str_buf, 512, "&lt;dc:creator&gt;%s&lt;/dc:creator&gt;", creator);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;dc:creator&gt;%s&lt;/dc:creator&gt;", creator);
}
if( date && (passed_args->filter & FILTER_DC_DATE) ) {
- ret = snprintf(str_buf, 512, "&lt;dc:date&gt;%s&lt;/dc:date&gt;", date);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;dc:date&gt;%s&lt;/dc:date&gt;", date);
}
if( artist ) {
if( (*mime == 'v') && (passed_args->filter & FILTER_UPNP_ACTOR) ) {
- ret = snprintf(str_buf, 512, "&lt;upnp:actor&gt;%s&lt;/upnp:actor&gt;", artist);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:actor&gt;%s&lt;/upnp:actor&gt;", artist);
}
if( passed_args->filter & FILTER_UPNP_ARTIST ) {
- ret = snprintf(str_buf, 512, "&lt;upnp:artist&gt;%s&lt;/upnp:artist&gt;", artist);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:artist&gt;%s&lt;/upnp:artist&gt;", artist);
}
}
if( album && (passed_args->filter & FILTER_UPNP_ALBUM) ) {
- ret = snprintf(str_buf, 512, "&lt;upnp:album&gt;%s&lt;/upnp:album&gt;", album);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:album&gt;%s&lt;/upnp:album&gt;", album);
}
if( genre && (passed_args->filter & FILTER_UPNP_GENRE) ) {
- ret = snprintf(str_buf, 512, "&lt;upnp:genre&gt;%s&lt;/upnp:genre&gt;", genre);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:genre&gt;%s&lt;/upnp:genre&gt;", genre);
}
if( strncmp(id, MUSIC_PLIST_ID, strlen(MUSIC_PLIST_ID)) == 0 ) {
track = strrchr(id, '$')+1;
}
if( track && atoi(track) && (passed_args->filter & FILTER_UPNP_ORIGINALTRACKNUMBER) ) {
- ret = sprintf(str_buf, "&lt;upnp:originalTrackNumber&gt;%s&lt;/upnp:originalTrackNumber&gt;", track);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:originalTrackNumber&gt;%s&lt;/upnp:originalTrackNumber&gt;", track);
}
if( album_art && atoi(album_art) )
{
/* Video and audio album art is handled differently */
if( *mime == 'v' && (passed_args->filter & FILTER_RES) && !(passed_args->flags & FLAG_MS_PFS) ) {
- ret = sprintf(str_buf, "&lt;res protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN\"&gt;"
- "http://%s:%d/AlbumArt/%s-%s.jpg"
- "&lt;/res&gt;",
- lan_addr[0].str, runtime_vars.port, album_art, detailID);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN\"&gt;"
+ "http://%s:%d/AlbumArt/%s-%s.jpg"
+ "&lt;/res&gt;",
+ lan_addr[0].str, runtime_vars.port, album_art, detailID);
} else if( passed_args->filter & FILTER_UPNP_ALBUMARTURI ) {
- ret = sprintf(str_buf, "&lt;upnp:albumArtURI");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:albumArtURI");
if( passed_args->filter & FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID ) {
- ret = sprintf(str_buf, " dlna:profileID=\"%s\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\"", "JPEG_TN");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, " dlna:profileID=\"JPEG_TN\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\"");
}
- ret = sprintf(str_buf, "&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;",
- lan_addr[0].str, runtime_vars.port, album_art, detailID);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;",
+ lan_addr[0].str, runtime_vars.port, album_art, detailID);
}
}
#ifdef PFS_HACK
if( (passed_args->flags & FLAG_MS_PFS) && *mime == 'i' ) {
- ret = snprintf(str_buf, 512, "&lt;upnp:album&gt;%s&lt;/upnp:album&gt;", "[No Keywords]");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:album&gt;%s&lt;/upnp:album&gt;", "[No Keywords]");
if( tn && atoi(tn) ) {
- ret = snprintf(str_buf, 512, "&lt;upnp:albumArtURI&gt;"
- "http://%s:%d/Thumbnails/%s.jpg"
- "&lt;/upnp:albumArtURI&gt;",
- lan_addr[0].str, runtime_vars.port, detailID);
+ ret = strcatf(str, "&lt;upnp:albumArtURI&gt;"
+ "http://%s:%d/Thumbnails/%s.jpg"
+ "&lt;/upnp:albumArtURI&gt;",
+ lan_addr[0].str, runtime_vars.port, detailID);
} else {
- ret = snprintf(str_buf, 512, "&lt;upnp:albumArtURI&gt;"
- "http://%s:%d/Resized/%s.jpg?width=160,height=160"
- "&lt;/upnp:albumArtURI&gt;",
- lan_addr[0].str, runtime_vars.port, detailID);
+ ret = strcatf(str, "&lt;upnp:albumArtURI&gt;"
+ "http://%s:%d/Resized/%s.jpg?width=160,height=160"
+ "&lt;/upnp:albumArtURI&gt;",
+ lan_addr[0].str, runtime_vars.port, detailID);
}
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
}
#endif
if( passed_args->filter & FILTER_RES ) {
mime_to_ext(mime, ext);
if( (passed_args->client == EFreeBox) && tn && atoi(tn) ) {
- ret = sprintf(str_buf, "&lt;res protocolInfo=\"http-get:*:%s:%s\"&gt;"
- "http://%s:%d/Thumbnails/%s.jpg"
- "&lt;/res&gt;",
- 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 = strcatf(str, "&lt;res protocolInfo=\"http-get:*:%s:%s\"&gt;"
+ "http://%s:%d/Thumbnails/%s.jpg"
+ "&lt;/res&gt;",
+ mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str,
+ runtime_vars.port, detailID);
}
add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels,
resolution, dlna_buf, mime, detailID, ext, passed_args);
@@ -870,12 +808,11 @@ callback(void *args, int argc, char **argv, char **azColName)
}
#endif
if( tn && atoi(tn) ) {
- ret = sprintf(str_buf, "&lt;res protocolInfo=\"http-get:*:%s:%s\"&gt;"
- "http://%s:%d/Thumbnails/%s.jpg"
- "&lt;/res&gt;",
- 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 = strcatf(str, "&lt;res protocolInfo=\"http-get:*:%s:%s\"&gt;"
+ "http://%s:%d/Thumbnails/%s.jpg"
+ "&lt;/res&gt;",
+ mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str,
+ runtime_vars.port, detailID);
}
}
else if( *mime == 'v' ) {
@@ -949,74 +886,52 @@ callback(void *args, int argc, char **argv, char **azColName)
}
}
}
- ret = sprintf(str_buf, "&lt;/item&gt;");
+ ret = strcatf(str, "&lt;/item&gt;");
}
else if( strncmp(class, "container", 9) == 0 )
{
- ret = sprintf(str_buf, "&lt;container id=\"%s\" parentID=\"%s\" restricted=\"1\" ", id, parent);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;container id=\"%s\" parentID=\"%s\" restricted=\"1\" ", id, parent);
if( passed_args->filter & FILTER_CHILDCOUNT )
{
int children;
ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s';", id);
children = (ret > 0) ? ret : 0;
- ret = sprintf(str_buf, "childCount=\"%d\"", children);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "childCount=\"%d\"", children);
}
/* 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 & FILTER_UPNP_SEARCHCLASS )
{
- ret = sprintf(str_buf, "&gt;"
- "&lt;upnp:searchClass includeDerived=\"1\"&gt;object.item.audioItem&lt;/upnp:searchClass&gt;"
- "&lt;upnp:searchClass includeDerived=\"1\"&gt;object.item.imageItem&lt;/upnp:searchClass&gt;"
- "&lt;upnp:searchClass includeDerived=\"1\"&gt;object.item.videoItem&lt;/upnp:searchClass");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&gt;"
+ "&lt;upnp:searchClass includeDerived=\"1\"&gt;object.item.audioItem&lt;/upnp:searchClass&gt;"
+ "&lt;upnp:searchClass includeDerived=\"1\"&gt;object.item.imageItem&lt;/upnp:searchClass&gt;"
+ "&lt;upnp:searchClass includeDerived=\"1\"&gt;object.item.videoItem&lt;/upnp:searchClass");
}
}
- ret = snprintf(str_buf, 512, "&gt;"
- "&lt;dc:title&gt;%s&lt;/dc:title&gt;"
- "&lt;upnp:class&gt;object.%s&lt;/upnp:class&gt;",
- title, class);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&gt;"
+ "&lt;dc:title&gt;%s&lt;/dc:title&gt;"
+ "&lt;upnp:class&gt;object.%s&lt;/upnp:class&gt;",
+ title, class);
if( creator && (passed_args->filter & FILTER_DC_CREATOR) ) {
- ret = snprintf(str_buf, 512, "&lt;dc:creator&gt;%s&lt;/dc:creator&gt;", creator);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;dc:creator&gt;%s&lt;/dc:creator&gt;", creator);
}
if( genre && (passed_args->filter & FILTER_UPNP_GENRE) ) {
- ret = snprintf(str_buf, 512, "&lt;upnp:genre&gt;%s&lt;/upnp:genre&gt;", genre);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:genre&gt;%s&lt;/upnp:genre&gt;", genre);
}
if( artist && (passed_args->filter & FILTER_UPNP_ARTIST) ) {
- ret = snprintf(str_buf, 512, "&lt;upnp:artist&gt;%s&lt;/upnp:artist&gt;", artist);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:artist&gt;%s&lt;/upnp:artist&gt;", artist);
}
if( album_art && atoi(album_art) && (passed_args->filter & FILTER_UPNP_ALBUMARTURI) ) {
- ret = sprintf(str_buf, "&lt;upnp:albumArtURI ");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&lt;upnp:albumArtURI ");
if( passed_args->filter & FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID ) {
- ret = sprintf(str_buf, "dlna:profileID=\"%s\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\"", "JPEG_TN");
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "dlna:profileID=\"JPEG_TN\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\"");
}
- ret = sprintf(str_buf, "&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;",
- lan_addr[0].str, runtime_vars.port, album_art, detailID);
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
+ ret = strcatf(str, "&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;",
+ lan_addr[0].str, runtime_vars.port, album_art, detailID);
}
- ret = sprintf(str_buf, "&lt;/container&gt;");
+ ret = strcatf(str, "&lt;/container&gt;");
}
- memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
- passed_args->size += ret;
return 0;
}
@@ -1030,16 +945,13 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
"<Result>"
"&lt;DIDL-Lite"
CONTENT_DIRECTORY_SCHEMAS;
-
- char *resp = malloc(1048576);
- char str_buf[512];
char *zErrMsg = 0;
char *sql, *ptr;
int ret;
struct Response args;
+ struct string_s str;
int totalMatches;
struct NameValueParserData data;
- *resp = '\0';
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
char * ObjectId = GetValueFromNameValueList(&data, "ObjectID");
@@ -1070,21 +982,19 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
goto browse_error;
}
memset(&args, 0, sizeof(args));
+ memset(&str, 0, sizeof(str));
- args.alloced = 1048576;
- args.resp = resp;
- args.size = sprintf(resp, "%s", resp0);
+ str.data = malloc(DEFAULT_RESP_SIZE);
+ str.size = DEFAULT_RESP_SIZE;
+ str.off = sprintf(str.data, "%s", resp0);
+ args.str = &str;
/* See if we need to include DLNA namespace reference */
args.filter = set_filter_flags(Filter, h->req_client);
if( args.filter & FILTER_DLNA_NAMESPACE )
{
- ret = sprintf(str_buf, DLNA_NAMESPACE);
- memcpy(resp+args.size, &str_buf, ret+1);
- args.size += ret;
+ ret = strcatf(&str, DLNA_NAMESPACE);
}
- ret = sprintf(str_buf, "&gt;\n");
- memcpy(resp+args.size, &str_buf, ret+1);
- args.size += ret;
+ strcatf(&str, "&gt;\n");
args.returned = 0;
args.requested = RequestedCount;
@@ -1190,22 +1100,19 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
goto browse_error;
}
}
- ret = snprintf(str_buf, sizeof(str_buf), "&lt;/DIDL-Lite&gt;</Result>\n"
- "<NumberReturned>%u</NumberReturned>\n"
- "<TotalMatches>%u</TotalMatches>\n"
- "<UpdateID>%u</UpdateID>"
- "</u:BrowseResponse>",
- args.returned, totalMatches, updateID);
- memcpy(resp+args.size, &str_buf, ret+1);
- args.size += ret;
- BuildSendAndCloseSoapResp(h, resp, args.size);
+ ret = strcatf(&str, "&lt;/DIDL-Lite&gt;</Result>\n"
+ "<NumberReturned>%u</NumberReturned>\n"
+ "<TotalMatches>%u</TotalMatches>\n"
+ "<UpdateID>%u</UpdateID>"
+ "</u:BrowseResponse>",
+ args.returned, totalMatches, updateID);
+ BuildSendAndCloseSoapResp(h, str.data, str.off);
browse_error:
ClearNameValueList(&data);
- if( orderBy )
- free(orderBy);
if( args.flags & FLAG_FREE_OBJECT_ID )
sqlite3_free(ObjectId);
- free(resp);
+ free(orderBy);
+ free(str.data);
}
static void
@@ -1217,16 +1124,13 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
"<Result>"
"&lt;DIDL-Lite"
CONTENT_DIRECTORY_SCHEMAS;
-
- char *resp = malloc(1048576);
char *zErrMsg = 0;
char *sql, *ptr;
char **result;
- char str_buf[4096];
- int ret;
struct Response args;
+ struct string_s str;
int totalMatches = 0;
- *resp = '\0';
+ int ret;
struct NameValueParserData data;
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
@@ -1255,26 +1159,24 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
}
}
memset(&args, 0, sizeof(args));
+ memset(&str, 0, sizeof(str));
- args.alloced = 1048576;
- args.resp = resp;
- args.size = sprintf(resp, "%s", resp0);
+ str.data = malloc(DEFAULT_RESP_SIZE);
+ str.size = DEFAULT_RESP_SIZE;
+ str.off = sprintf(str.data, "%s", resp0);
/* See if we need to include DLNA namespace reference */
args.filter = set_filter_flags(Filter, h->req_client);
if( args.filter & FILTER_DLNA_NAMESPACE )
{
- ret = sprintf(str_buf, DLNA_NAMESPACE);
- memcpy(resp+args.size, &str_buf, ret+1);
- args.size += ret;
+ ret = strcatf(&str, DLNA_NAMESPACE);
}
- ret = sprintf(str_buf, "&gt;\n");
- memcpy(resp+args.size, &str_buf, ret+1);
- args.size += ret;
+ ret = strcatf(&str, "&gt;\n");
args.returned = 0;
args.requested = RequestedCount;
args.client = h->req_client;
args.flags = h->reqflags;
+ args.str = &str;
if( h->reqflags & FLAG_MS_PFS )
{
if( strchr(ContainerID, '$') || (strcmp(ContainerID, "0") == 0) )
@@ -1360,14 +1262,16 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
}
DPRINTF(E_DEBUG, L_HTTP, "Translated SearchCriteria: %s\n", SearchCriteria);
- sprintf(str_buf, "SELECT (select count(distinct DETAIL_ID) from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
- " where (OBJECT_ID glob '%s$*') and (%s))"
- " + "
- "(select count(*) from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
- " where (OBJECT_ID = '%s') and (%s))",
- ContainerID, SearchCriteria, ContainerID, SearchCriteria);
+ sql = sqlite3_mprintf("SELECT (select count(distinct DETAIL_ID)"
+ " from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
+ " where (OBJECT_ID glob '%s$*') and (%s))"
+ " + "
+ "(select count(*) from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
+ " where (OBJECT_ID = '%s') and (%s))",
+ ContainerID, SearchCriteria, ContainerID, SearchCriteria);
//DEBUG DPRINTF(E_DEBUG, L_HTTP, "Count SQL: %s\n", sql);
- ret = sql_get_table(db, str_buf, &result, NULL, NULL);
+ ret = sql_get_table(db, sql, &result, NULL, NULL);
+ sqlite3_free(sql);
if( ret == SQLITE_OK )
{
totalMatches = atoi(result[1]);
@@ -1421,25 +1325,19 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
sqlite3_free(zErrMsg);
}
sqlite3_free(sql);
- strcat(resp, str_buf);
- ret = snprintf(str_buf, sizeof(str_buf), "&lt;/DIDL-Lite&gt;</Result>\n"
- "<NumberReturned>%u</NumberReturned>\n"
- "<TotalMatches>%u</TotalMatches>\n"
- "<UpdateID>%u</UpdateID>"
- "</u:SearchResponse>",
- args.returned, totalMatches, updateID);
- memcpy(resp+args.size, &str_buf, ret+1);
- args.size += ret;
- BuildSendAndCloseSoapResp(h, resp, args.size);
+ ret = strcatf(&str, "&lt;/DIDL-Lite&gt;</Result>\n"
+ "<NumberReturned>%u</NumberReturned>\n"
+ "<TotalMatches>%u</TotalMatches>\n"
+ "<UpdateID>%u</UpdateID>"
+ "</u:SearchResponse>",
+ args.returned, totalMatches, updateID);
+ BuildSendAndCloseSoapResp(h, str.data, str.off);
search_error:
ClearNameValueList(&data);
- if( orderBy )
- free(orderBy);
- free(resp);
if( h->reqflags & FLAG_MS_PFS )
- {
sqlite3_free(ContainerID);
- }
+ free(orderBy);
+ free(str.data);
}
/*
diff --git a/upnpsoap.h b/upnpsoap.h
index d2c006d..9f75c03 100644
--- a/upnpsoap.h
+++ b/upnpsoap.h
@@ -21,7 +21,8 @@
#ifndef __UPNPSOAP_H__
#define __UPNPSOAP_H__
-#define MAX_RESPONSE_SIZE 1048576
+#define DEFAULT_RESP_SIZE 131072
+#define MAX_RESPONSE_SIZE 2097152
#define CONTENT_DIRECTORY_SCHEMAS \
" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" \
@@ -32,14 +33,12 @@
struct Response
{
- char *resp;
+ struct string_s *str;
int start;
int returned;
int requested;
- int size;
- int alloced;
- u_int32_t filter;
- u_int32_t flags;
+ uint32_t filter;
+ uint32_t flags;
enum client_types client;
};
diff --git a/utils.c b/utils.c
index f0e8788..136fbda 100644
--- a/utils.c
+++ b/utils.c
@@ -31,6 +31,20 @@
#include "upnpglobalvars.h"
#include "log.h"
+inline int
+strcatf(struct string_s *str, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(str->data + str->off, str->size - str->off, fmt, ap);
+ str->off += ret;
+ va_end(ap);
+
+ return ret;
+}
+
int
ends_with(const char * haystack, const char * needle)
{
diff --git a/utils.h b/utils.h
index abc4260..05ebb13 100644
--- a/utils.h
+++ b/utils.h
@@ -25,6 +25,9 @@
#define __UTILS_H__
int
+strcatf(struct string_s *str, char *fmt, ...);
+
+int
ends_with(const char * haystack, const char * needle);
char *