Add some video metadata support through libdlna (>0.2.3).

Some more changes for DLNA compliance.
Reformat some other code.
This commit is contained in:
Justin Maggard 2008-10-30 06:53:17 +00:00
parent a163077b29
commit ccd9b957f6
6 changed files with 200 additions and 73 deletions

View File

@ -30,7 +30,7 @@ BASEOBJS = minidlna.o upnphttp.o upnpdescgen.o upnpsoap.o \
ALLOBJS = $(BASEOBJS) $(LNXOBJS)
#LIBS = -liptc
LIBS = -lexif -ltag_c -lsqlite3 #-lgd
LIBS = -lexif -ltag_c -lsqlite3 -ldlna #-lgd
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o

View File

@ -24,9 +24,11 @@
#include <sqlite3.h>
#include <taglib/tag_c.h>
#include <libexif/exif-loader.h>
#include <dlna.h>
#include "upnpglobalvars.h"
#include "metadata.h"
#include "sql.h"
#define FLAG_ARTIST 0x01
@ -98,6 +100,27 @@ strip_ext(char * name)
*rindex(name, '.') = '\0';
}
sqlite_int64
GetFolderMetadata(const char * name, const char * artist)
{
char * sql;
int ret;
sql = sqlite3_mprintf( "INSERT into DETAILS"
" (TITLE, ARTIST) "
"VALUES"
" ('%q', %Q);",
name, artist);
if( sql_exec(db, sql) != SQLITE_OK )
ret = 0;
else
ret = sqlite3_last_insert_rowid(db);
sqlite3_free(sql);
return ret;
}
sqlite_int64
GetAudioMetadata(const char * path, char * name)
{
@ -258,16 +281,17 @@ GetImageMetadata(const char * path, char * name)
ExifTag tag;
int width=0, height=0, thumb=0;
size_t size;
char date[64], make[32], model[64], dlna_pn[64];
char date[64], make[32], model[64];
char b[1024];
struct stat file;
sqlite_int64 ret;
char *sql;
char *zErrMsg = NULL;
metadata_t m;
memset(&m, '\0', sizeof(metadata_t));
date[0] = '\0';
model[0] = '\0';
dlna_pn[0] = '\0';
//DEBUG printf("Parsing %s...\n", path);
if ( stat(path, &file) == 0 )
@ -277,6 +301,9 @@ GetImageMetadata(const char * path, char * name)
strip_ext(name);
//DEBUG printf(" * size: %d\n", size);
/* MIME hard-coded to JPEG for now, until we add PNG support */
asprintf(&m.mime, "image/jpeg");
ExifLoader * l = exif_loader_new();
exif_loader_write_file(l, path);
ed = exif_loader_get_data(l);
@ -340,19 +367,20 @@ GetImageMetadata(const char * path, char * name)
exif_data_unref(ed);
if( width <= 640 && height <= 480 )
strcpy(dlna_pn, "JPEG_SM;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
asprintf(&m.dlna_pn, "JPEG_SM;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
else if( width <= 1024 && height <= 768 )
strcpy(dlna_pn, "JPEG_MED;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
asprintf(&m.dlna_pn, "JPEG_MED;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
else if( width <= 4096 && height <= 4096 )
strcpy(dlna_pn, "JPEG_LRG;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
asprintf(&m.dlna_pn, "JPEG_LRG;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
else
strcpy(dlna_pn, "JPEG_XL");
asprintf(&m.dlna_pn, "JPEG_XL");
asprintf(&m.resolution, "%dx%d", width, height);
sql = sqlite3_mprintf( "INSERT into DETAILS"
" (TITLE, SIZE, DATE, WIDTH, HEIGHT, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
" (TITLE, SIZE, DATE, RESOLUTION, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
"VALUES"
" ('%q', %d, '%s', %d, %d, %d, '%q', '%s', '%s');",
name, size, date, width, height, thumb, model, dlna_pn, "image/jpeg");
" ('%q', %d, '%s', %Q, %d, '%q', %Q, %Q);",
name, size, date, m.resolution, thumb, model, m.dlna_pn, m.mime);
//DEBUG printf("SQL: %s\n", sql);
if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
{
@ -366,6 +394,12 @@ GetImageMetadata(const char * path, char * name)
ret = sqlite3_last_insert_rowid(db);
}
sqlite3_free(sql);
if( m.resolution )
free(m.resolution);
if( m.dlna_pn )
free(m.dlna_pn);
if( m.mime )
free(m.mime);
return ret;
}
@ -374,9 +408,14 @@ GetVideoMetadata(const char * path, char * name)
{
size_t size = 0;
struct stat file;
dlna_t *dlna;
dlna_profile_t *p;
dlna_item_t *item;
char *sql;
char *zErrMsg = NULL;
int ret;
metadata_t m;
memset(&m, '\0', sizeof(m));
//DEBUG printf("Parsing %s...\n", path);
if ( stat(path, &file) == 0 )
@ -384,11 +423,53 @@ GetVideoMetadata(const char * path, char * name)
strip_ext(name);
//DEBUG printf(" * size: %d\n", size);
dlna = dlna_init();
dlna_register_all_media_profiles(dlna);
item = dlna_item_new (dlna, path);
if (item)
{
if (item->properties)
{
if( strlen(item->properties->duration) )
m.duration = item->properties->duration;
if( item->properties->bitrate )
asprintf(&m.bitrate, "%d", item->properties->bitrate);
if( item->properties->sample_frequency )
asprintf(&m.frequency, "%d", item->properties->sample_frequency);
if( item->properties->bps )
asprintf(&m.bps, "%d", item->properties->bps);
if( item->properties->channels )
asprintf(&m.channels, "%d", item->properties->channels);
m.resolution = item->properties->resolution;
}
}
p = dlna_guess_media_profile (dlna, path);
if (p)
{
m.mime = (char *)p->mime;
asprintf(&m.dlna_pn, "%s;DLNA.ORG_OP=01;DLNA.ORG_CI=0", p->id);
}
else
printf ("Unknown format [%s]\n", path);
sql = sqlite3_mprintf( "INSERT into DETAILS"
" (SIZE, DURATION, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION,"
" TITLE, DLNA_PN, MIME) "
"VALUES"
" (%d, %Q, %d, %d, %d, %Q, '%q', %Q, '%q');",
size, m.duration,
item->properties ? item->properties->channels : 0,
item->properties ? item->properties->bitrate : 0,
item->properties ? item->properties->sample_frequency : 0,
m.resolution, name,
m.dlna_pn, m.mime);
/* sql = sqlite3_mprintf( "INSERT into DETAILS"
" (TITLE, SIZE, MIME) "
"VALUES"
" ('%q', %d, %Q);",
name, size, "video/mpeg");
name, size, "video/mpeg");*/
//DEBUG printf("SQL: %s\n", sql);
if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
{
@ -402,5 +483,18 @@ GetVideoMetadata(const char * path, char * name)
ret = sqlite3_last_insert_rowid(db);
}
sqlite3_free(sql);
dlna_item_free(item);
dlna_uninit(dlna);
if( m.dlna_pn )
free(m.dlna_pn);
if( m.bitrate )
free(m.bitrate);
if( m.frequency )
free(m.frequency);
if( m.bps )
free(m.bps);
if( m.channels )
free(m.channels);
return ret;
}

View File

@ -10,9 +10,28 @@
#ifndef __METADATA_H__
#define __METADATA_H__
typedef struct metadata_s {
char *title;
char *artist;
char *album;
char *genre;
char *comment;
char *channels;
char *bitrate;
char *frequency;
char *bps;
char *resolution;
char *duration;
char *mime;
char *dlna_pn;
} metadata_t;
char *
modifyString(char * string, const char * before, const char * after, short like);
sqlite_int64
GetFolderMetadata(const char * name, const char * artist);
sqlite_int64
GetAudioMetadata(const char * path, char * name);

View File

@ -58,13 +58,14 @@ is_image(const char * file)
}
long long int
insert_container(const char * tmpTable, const char * item, const char * rootParent, const char *subParent, const char *class, long unsigned int detailID)
insert_container(const char * tmpTable, const char * item, const char * rootParent, const char *subParent, const char *class, const char *artist)
{
char **result;
char *sql;
int cols, rows, ret;
char *zErrMsg = NULL;
int parentID = 0, objectID = 0;
sqlite_int64 detailID;
sql = sqlite3_mprintf("SELECT * from %s where ITEM = '%q' and SUBITEM = '%q'", tmpTable, item, subParent);
ret = sql_get_table(db, sql, &result, &rows, &cols, &zErrMsg);
@ -95,10 +96,11 @@ insert_container(const char * tmpTable, const char * item, const char * rootPare
{
parentID = 0;
}
detailID = GetFolderMetadata(item, artist);
sql = sqlite3_mprintf( "INSERT into OBJECTS"
" (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME) "
"VALUES"
" ('%s$%X', '%s', %lu, 'container.%s', '%q')",
" ('%s$%X', '%s', %lld, 'container.%s', '%q')",
rootParent, parentID, rootParent, detailID, class, item);
ret = sql_exec(db, sql);
sqlite3_free(sql);
@ -136,7 +138,7 @@ insert_containers(const char * name, const char *path, const char * refID, const
strncpy(date_taken, date, 10);
if( date )
{
container = insert_container("DATES", date_taken, "3$12", NULL, "album.photoAlbum", 0);
container = insert_container("DATES", date_taken, "3$12", NULL, "album.photoAlbum", NULL);
parentID = container>>32;
objectID = container;
sql = sqlite3_mprintf( "INSERT into OBJECTS"
@ -149,12 +151,12 @@ insert_containers(const char * name, const char *path, const char * refID, const
}
if( cam && date )
{
container = insert_container("CAMS", cam, "3$13", NULL, "storageFolder", 0);
container = insert_container("CAMS", cam, "3$13", NULL, "storageFolder", NULL);
parentID = container>>32;
//objectID = container;
char parent[64];
sprintf(parent, "3$13$%X", parentID);
long long int subcontainer = insert_container("CAMDATE", date_taken, parent, cam, "storageFolder", 0);
long long int subcontainer = insert_container("CAMDATE", date_taken, parent, cam, "storageFolder", NULL);
int subParentID = subcontainer>>32;
int subObjectID = subcontainer;
sql = sqlite3_mprintf( "INSERT into OBJECTS"
@ -195,7 +197,7 @@ insert_containers(const char * name, const char *path, const char * refID, const
else
{
strcpy(last_artist, artist);
container = insert_container("ARTISTS", artist, "1$6", NULL, "person.musicArtist", 0);
container = insert_container("ARTISTS", artist, "1$6", NULL, "person.musicArtist", NULL);
parentID = container>>32;
objectID = container;
last_artist_objectID = objectID;
@ -219,7 +221,7 @@ insert_containers(const char * name, const char *path, const char * refID, const
else
{
strcpy(last_album, album);
container = insert_container("ALBUMS", album, "1$7", NULL, "album.musicAlbum", detailID);
container = insert_container("ALBUMS", album, "1$7", NULL, "album.musicAlbum", artist);
parentID = container>>32;
objectID = container;
last_album_objectID = objectID;
@ -243,7 +245,7 @@ insert_containers(const char * name, const char *path, const char * refID, const
else
{
strcpy(last_genre, genre);
container = insert_container("GENRES", genre, "1$5", NULL, "genre.musicGenre", 0);
container = insert_container("GENRES", genre, "1$5", NULL, "genre.musicGenre", NULL);
parentID = container>>32;
objectID = container;
last_genre_objectID = objectID;
@ -272,22 +274,30 @@ insert_containers(const char * name, const char *path, const char * refID, const
int
insert_directory(const char * name, const char * path, const char * parentID, int objectID)
{
char *sql;
char * sql;
int ret, i;
sqlite_int64 detailID;
char * refID = NULL;
char class[] = "container.storageFolder";
const char * const base[] = { BROWSEDIR_ID, MUSIC_DIR_ID, VIDEO_DIR_ID, IMAGE_DIR_ID, 0 };
detailID = GetFolderMetadata(name, NULL);
for( i=0; base[i]; i++ )
{
sql = sqlite3_mprintf( "INSERT into OBJECTS"
" (OBJECT_ID, PARENT_ID, CLASS, PATH, NAME) "
" (OBJECT_ID, PARENT_ID, REF_ID, DETAIL_ID, CLASS, PATH, NAME) "
"VALUES"
" ('%s%s$%X', '%s%s', '%s', '%q', '%q')",
base[i], parentID, objectID, base[i], parentID, class, path, name);
" ('%s%s$%X', '%s%s', %Q, '%lld', '%s', '%q', '%q')",
base[i], parentID, objectID, base[i], parentID, refID, detailID, class, path, name);
//DEBUG printf("SQL: %s\n", sql);
ret = sql_exec(db, sql);
sqlite3_free(sql);
if( !i )
asprintf(&refID, "%s%s$%X", base[0], parentID, objectID);
}
if( refID )
free(refID);
return -1;
}
@ -401,8 +411,7 @@ create_database(void)
"CHANNELS INTEGER, "
"TRACK INTEGER, "
"DATE DATE, "
"WIDTH TEXT, "
"HEIGHT TEXT, "
"RESOLUTION TEXT, "
"THUMBNAIL BOOL DEFAULT 0, "
"CREATOR TEXT, "
"DLNA_PN TEXT, "
@ -412,8 +421,10 @@ create_database(void)
goto sql_failed;
for( i=0; containers[i]; i=i+3 )
{
sprintf(sql_buf, "INSERT into OBJECTS (OBJECT_ID, PARENT_ID, CLASS, NAME) values ( '%s', '%s', 'container.storageFolder', '%s')",
containers[i], containers[i+1], containers[i+2]);
sprintf(sql_buf, "INSERT into OBJECTS (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME)"
" values "
"('%s', '%s', %lld, 'container.storageFolder', '%s')",
containers[i], containers[i+1], GetFolderMetadata(containers[i+2], NULL), containers[i+2]);
ret = sql_exec(db, sql_buf);
if( ret != SQLITE_OK )
goto sql_failed;

View File

@ -195,7 +195,7 @@ printf("Range Start-End: %lld-%lld\n", h->req_RangeStart, h->req_RangeEnd);
p = colon + 1;
while(isspace(*p))
p++;
if( strcmp(p, "1") != 0 )
if( (*p != '1') || !isspace(p[1]) )
h->reqflags |= FLAG_INVALID_REQ;
}
else if(strncasecmp(line, "TimeSeekRange.dlna.org", 22)==0)
@ -549,6 +549,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
HttpVer[i] = '\0';
syslog(LOG_INFO, "HTTP REQUEST : %s %s (%s)",
HttpCommand, HttpUrl, HttpVer);
//DEBUG printf("HTTP REQUEST:\n%s\n", h->req_buf);
ParseHttpHeaders(h);
if( (h->reqflags & FLAG_CHUNKED) && (h->req_chunklen > (h->req_buflen - h->req_contentoff) || h->req_chunklen < 0) )
@ -567,7 +568,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
{
if( ((strcmp(h->HttpVer, "HTTP/1.1")==0) && !(h->reqflags & FLAG_HOST)) || (h->reqflags & FLAG_INVALID_REQ) )
{
syslog(LOG_NOTICE, "No Host specified in HTTP headers, responding ERROR 400");
syslog(LOG_NOTICE, "Invalid request, responding ERROR 400. (No Host specified in HTTP headers?)");
Send400(h);
}
else if( h->reqflags & FLAG_TIMESEEK )
@ -1181,6 +1182,10 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
}
else //if( h->reqflags & FLAG_XFERINTERACTIVE )
{
if( (strncmp(mime, "vide", 4) == 0) ||
(strncmp(mime, "audi", 4) == 0) )
strcat(header, "transferMode.dlna.org: Streaming\r\n");
else
strcat(header, "transferMode.dlna.org: Interactive\r\n");
}

View File

@ -22,6 +22,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <ctype.h>
#include "config.h"
#include "upnpglobalvars.h"
@ -30,9 +31,8 @@
#include "upnpreplyparse.h"
#include "getifaddr.h"
#include <ctype.h>
#include "metadata.h"
#include <sqlite3.h>
#include "sql.h"
static void
BuildSendAndCloseSoapResp(struct upnphttp * h,
@ -254,14 +254,12 @@ GetCurrentConnectionInfo(struct upnphttp * h, const char * action)
static int callback(void *args, int argc, char **argv, char **azColName)
{
struct Response { char *resp; int returned; int requested; int total; char *filter; } *passed_args = (struct Response *)args;
char *id = argv[1], *parent = argv[2], *refID = argv[3], *class = argv[4], *name = argv[7], *size = argv[9],
*title = argv[10], *duration = argv[11], *bitrate = argv[12], *sampleFrequency = argv[13],
*artist = argv[14], *album = argv[15], *genre = argv[16], *comment = argv[17], *nrAudioChannels = argv[18],
*track = argv[19], *date = argv[20], *width = argv[21], *height = argv[22], *tn = argv[23],
*creator = argv[24], *dlna_pn = argv[25], *mime = argv[26];
char *id = argv[1], *parent = argv[2], *refID = argv[3], *class = argv[4], *size = argv[9], *title = argv[10],
*duration = argv[11], *bitrate = argv[12], *sampleFrequency = argv[13], *artist = argv[14], *album = argv[15],
*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];
char dlna_buf[64];
char str_buf[4096];
//char * str_buf = malloc(4096);
char **result;
int ret;
@ -269,20 +267,13 @@ static int callback(void *args, int argc, char **argv, char **azColName)
if( passed_args->requested && (passed_args->returned >= passed_args->requested) )
return 0;
//if( (strncmp(class, "item", 4) == 0) && !mime ) // Useless listing if there is no MIME type
// return 0;
passed_args->returned++;
if( dlna_pn )
//sprintf(dlna_buf, "DLNA.ORG_PN=%s;DLNA.ORG_OP=01", dlna_pn);
sprintf(dlna_buf, "DLNA.ORG_PN=%s", dlna_pn);
else
strcpy(dlna_buf, "*");
/*for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i]);
}*/
//printf("\n");
if( strncmp(class, "item", 4) == 0 )
{
sprintf(str_buf, "&lt;item id=\"%s\" parentID=\"%s\" restricted=\"1\"", id, parent);
@ -294,7 +285,7 @@ static int callback(void *args, int argc, char **argv, char **azColName)
sprintf(str_buf, "&gt;"
"&lt;dc:title&gt;%s&lt;/dc:title&gt;"
"&lt;upnp:class&gt;object.%s&lt;/upnp:class&gt;",
title?title:name, class);
title, class);
strcat(passed_args->resp, str_buf);
if( comment && (!passed_args->filter || strstr(passed_args->filter, "dc:description")) ) {
sprintf(str_buf, "&lt;dc:description&gt;%s&lt;/dc:description&gt;", comment);
@ -346,8 +337,8 @@ static int callback(void *args, int argc, char **argv, char **azColName)
sprintf(str_buf, "nrAudioChannels=\"%s\" ", nrAudioChannels);
strcat(passed_args->resp, str_buf);
}
if( width && height && (!passed_args->filter || strstr(passed_args->filter, "res@resolution")) ) {
sprintf(str_buf, "resolution=\"%sx%s\" ", width, height);
if( resolution && (!passed_args->filter || strstr(passed_args->filter, "res@resolution")) ) {
sprintf(str_buf, "resolution=\"%s\" ", resolution);
strcat(passed_args->resp, str_buf);
}
sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\"&gt;"
@ -382,15 +373,24 @@ static int callback(void *args, int argc, char **argv, char **azColName)
ret = sqlite3_get_table(db, str_buf, &result, 0, 0, 0);
sprintf(str_buf, "&lt;container id=\"%s\" parentID=\"%s\" restricted=\"1\" ", id, parent);
strcat(passed_args->resp, str_buf);
if( !passed_args->filter || strstr(passed_args->filter, "@childCount")) {
if( !passed_args->filter || strstr(passed_args->filter, "@childCount"))
{
sprintf(str_buf, "childCount=\"%s\"", result[1]);
strcat(passed_args->resp, str_buf);
}
/* If the client calls for BrowseMetadata on root, we have to include our "upnp:searchClass"'s */
if( (passed_args->requested == 1) && (strcmp(id, "0") == 0) )
{
strcat(passed_args->resp, "&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");
}
sprintf(str_buf, "&gt;"
"&lt;dc:title&gt;%s&lt;/dc:title&gt;"
"&lt;upnp:class&gt;object.%s&lt;/upnp:class&gt;"
"&lt;/container&gt;",
name, class);
title, class);
sqlite3_free_table(result);
}
strcat(passed_args->resp, str_buf);
@ -410,15 +410,10 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
static const char resp2[] = "<UpdateID>0</UpdateID></u:BrowseResponse>";
char *resp = calloc(1, 1048576);
strcpy(resp, resp0);
char str_buf[4096];
char str_buf2[4096];
memset(str_buf, '\0', sizeof(str_buf));
memset(str_buf2, '\0', sizeof(str_buf2));
char *zErrMsg = 0;
char *sql;
int ret;
char sql_buf[4096];
struct Response { char *resp; int returned; int requested; int total; char *filter; } args;
struct NameValueParserData data;
@ -432,8 +427,11 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
if( !ObjectId )
ObjectId = GetValueFromNameValueList(&data, "ContainerID");
memset(str_buf, '\0', sizeof(str_buf));
memset(&args, 0, sizeof(args));
args.total = 0;
strcpy(resp, resp0);
args.total = StartingIndex;
args.returned = 0;
args.requested = RequestedCount;
args.resp = NULL;
@ -458,16 +456,17 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
if( strcmp(BrowseFlag, "BrowseMetadata") == 0 )
{
args.requested = 1;
sprintf(sql_buf, "SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where OBJECT_ID = '%s';", ObjectId);
ret = sqlite3_exec(db, sql_buf, callback, (void *) &args, &zErrMsg);
sql = sqlite3_mprintf("SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where OBJECT_ID = '%s';", ObjectId);
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
}
else
{
sprintf(sql_buf, "SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
sql = sqlite3_mprintf("SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
" where PARENT_ID = '%s' order by d.TRACK, d.TITLE, o.NAME limit %d, -1;",
ObjectId, StartingIndex);
ret = sqlite3_exec(db, sql_buf, callback, (void *) &args, &zErrMsg);
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
}
sqlite3_free(sql);
if( ret != SQLITE_OK ){
printf("SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
@ -492,13 +491,11 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
static const char resp1[] = "&lt;/DIDL-Lite&gt;</Result>";
static const char resp2[] = "<UpdateID>0</UpdateID></u:SearchResponse>";
char *resp = calloc(8, 16384);
strcpy(resp, resp0);
char *resp = calloc(1, 1048576);
char *zErrMsg = 0;
char sql_buf[4096];
char str_buf[4096];
char str_buf2[4096];
memset(str_buf, '\0', sizeof(str_buf));
memset(str_buf2, '\0', sizeof(str_buf2));
int ret;
struct Response { char *resp; int returned; int requested; int total; char *filter; } args;
struct NameValueParserData data;
@ -510,7 +507,9 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
char * SearchCriteria = GetValueFromNameValueList(&data, "SearchCriteria");
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
memset(str_buf, '\0', sizeof(str_buf));
memset(&args, 0, sizeof(args));
args.total = 0;
args.returned = 0;
args.requested = RequestedCount;
@ -523,6 +522,8 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
printf("Asked for Filter: %s\n", Filter);
if( SortCriteria ) printf("Asked for SortCriteria: %s\n", SortCriteria);
strcpy(resp, resp0);
if( !Filter )
{
ClearNameValueList(&data);
@ -553,11 +554,8 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
SearchCriteria = modifyString(SearchCriteria, "@refID", "REF_ID", 0);
SearchCriteria = modifyString(SearchCriteria, "object.", "", 0);
}
printf("Asked for SearchCriteria: %s\n", SearchCriteria);
printf("Translated SearchCriteria: %s\n", SearchCriteria);
char *zErrMsg = 0;
int ret;
char sql_buf[4096];
args.resp = resp;
sprintf(sql_buf, "SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
" where OBJECT_ID like '%s$%%' and (%s) order by d.TRACK, d.TITLE, o.NAME limit %d, -1;",