Add xml output for daap requests (using output=xml in request)

This commit is contained in:
Ron Pedde 2005-03-03 06:07:11 +00:00
parent c86be33245
commit 3b26120a3b
9 changed files with 220 additions and 21 deletions

View File

@ -38,7 +38,7 @@ CREATE TABLE config (
value VARCHAR(1024) NOT NULL
);
CREATE INDEX idx_id ON songs(id);
CREATE INDEX idx_path on songs(path);
#CREATE INDEX idx_id ON songs(id);
#CREATE INDEX idx_path on songs(path);
INSERT INTO config (term, value) VALUES ('version','8');

View File

@ -333,11 +333,154 @@ DAAP_BLOCK *daap_add_empty(DAAP_BLOCK *parent, char *tag) {
return daap_add_formatted(parent,tag,0,NULL);
}
DAAP_ITEMS *daap_lookup_tag(char *tag) {
DAAP_ITEMS *pitem;
pitem=taglist;
while((pitem->tag) && (strncmp(tag,pitem->tag,4))) {
pitem++;
}
if(!pitem->tag)
DPRINTF(E_FATAL,L_DAAP,"Unknown daap tag: %c%c%c%c\n",tag[0],tag[1],tag[2],tag[3]);
return pitem;
}
/**
* xml entity encoding, stupid style
*/
char *daap_xml_entity_encode(char *original) {
char *new;
char *s, *d;
int destsize;
destsize = 6*strlen(original)+1;
new=(char *)malloc(destsize);
if(!new) return NULL;
memset(new,0x00,destsize);
s=original;
d=new;
while(*s) {
switch(*s) {
case '>':
strcat(d,">");
d += 4;
s++;
break;
case '<':
strcat(d,"&lt;");
d += 4;
s++;
break;
case '"':
strcat(d,"&quot;");
d += 6;
s++;
break;
case '\'':
strcat(d,"&apos;");
d += 6;
s++;
break;
case '&':
strcat(d,"&amp;");
d += 5;
s++;
break;
default:
*d++ = *s++;
}
}
return new;
}
/**
* serialize a dmap tree as xml
*/
int daap_serialize_xml(DAAP_BLOCK *root, int fd) {
DAAP_ITEMS *pitem;
unsigned char *data;
int ivalue;
long long lvalue;
char *encoded_string;
while(root) {
if(root->free)
data=(unsigned char *)root->value;
else
data=(unsigned char *)root->svalue;
pitem=daap_lookup_tag(root->tag);
r_fdprintf(fd,"<%s>",pitem->description);
if(pitem->type != 0x0c) { /* container */
switch(pitem->type) {
case 0x01: /* byte */
r_fdprintf(fd,"%d",*((char *)data));
break;
case 0x02: /* unsigned byte */
r_fdprintf(fd,"%ud",*((char *)data));
break;
case 0x03: /* short */
ivalue = data[0] << 8 | data[1];
r_fdprintf(fd,"%d",ivalue);
break;
case 0x05: /* int */
case 0x0A: /* epoch */
ivalue = data[0] << 24 |
data[1] << 16 |
data[2] << 8 |
data[3];
r_fdprintf(fd,"%d",ivalue);
break;
case 0x07: /* long long */
ivalue = data[0] << 24 |
data[1] << 16 |
data[2] << 8 |
data[3];
lvalue=ivalue;
ivalue = data[4] << 24 |
data[5] << 16 |
data[6] << 8 |
data[7];
lvalue = (lvalue << 32) | ivalue;
r_fdprintf(fd,"%ll",ivalue);
break;
case 0x09: /* string */
encoded_string=daap_xml_entity_encode(data);
r_fdprintf(fd,"%s",encoded_string);
free(encoded_string);
break;
case 0x0B: /* version? */
ivalue=data[0] << 8 | data[1];
r_fdprintf(fd,"%d.%d.%d",ivalue,data[2],data[3]);
break;
default:
DPRINTF(E_FATAL,L_DAAP,"Bad dmap type: %d, %s\n",
pitem->type, pitem->description);
break;
}
} else {
daap_serialize_xml(root->children,fd);
}
r_fdprintf(fd,"</%s>",pitem->description);
root=root->next;
}
}
/*
* daap_serialmem
*
* Serialize a daap tree to a fd;
*/
*/
int daap_serialize(DAAP_BLOCK *root, int fd, GZIP_STREAM *gz) {
char size[4];

View File

@ -74,5 +74,14 @@ DAAP_BLOCK *daap_find(DAAP_BLOCK *parent, char* tag);
// search a block's children and change an integer value
int daap_set_int(DAAP_BLOCK* parent, char* tag, int value);
typedef struct tag_daap_items {
int type;
char *tag;
char *description;
} DAAP_ITEMS;
extern DAAP_ITEMS taglist[];
#endif

View File

@ -41,12 +41,6 @@
#include "daapd.h"
#include "query.h"
typedef struct tag_daap_items {
int type;
char *tag;
char *description;
} DAAP_ITEMS;
DAAP_ITEMS taglist[] = {
{ 0x05, "miid", "dmap.itemid" },
{ 0x09, "minm", "dmap.itemname" },
@ -132,6 +126,16 @@ DAAP_ITEMS taglist[] = {
{ 0x0C, "arif", "daap.resolveinfo" },
{ 0x05, "aeNV", "com.apple.itunes.norm-volume" },
{ 0x01, "aeSP", "com.apple.itunes.smart-playlist" },
/* iTunes 4.5+ */
{ 0x01, "msas", "dmap.authenticationschemes" },
{ 0x05, "ascd", "daap.songcodectype" },
{ 0x05, "aeSV", "com.apple.itunes.music-sharing-version" },
{ 0x05, "aePI", "com.apple.itunes.itms-playlistid" },
{ 0x05, "aeCI", "com.apple.iTunes.itms-composerid" },
{ 0x05, "aeGI", "com.apple.iTunes.itms-genreid" },
{ 0x05, "aeAI", "com.apple.iTunes.itms-artistid" },
{ 0x05, "aeSI", "com.apple.iTunes.itms-songid" },
{ 0x09, "agrp", "daap.songgrouping" },
{ 0x00, NULL, NULL }
};

View File

@ -233,7 +233,7 @@ void db_init_once(void) {
int db_open(char *parameters, int reload) {
char db_path[PATH_MAX + 1];
int current_db_version;
char *errmsg;
char *perr;
int err;
if(pthread_once(&db_initlock,db_init_once))
@ -242,14 +242,14 @@ int db_open(char *parameters, int reload) {
snprintf(db_path,sizeof(db_path),"%s/%s",parameters,"songs_sqlite.db");
db_gdbmlock();
db_songs=sqlite_open(db_path,0,&errmsg);
db_songs=sqlite_open(db_path,0,&perr);
if(!db_songs)
DPRINTF(E_FATAL,L_DB,"db_open: %s\n",errmsg);
DPRINTF(E_FATAL,L_DB,"db_open: %s\n",perr);
if(reload) {
err=sqlite_exec(db_songs,"DELETE FROM songs",NULL,NULL,&errmsg);
err=sqlite_exec(db_songs,"DELETE FROM songs",NULL,NULL,&perr);
if(err != SQLITE_OK)
DPRINTF(E_FATAL,L_DB,"Cannot reload tables: %s\n",errmsg);
DPRINTF(E_FATAL,L_DB,"Cannot reload tables: %s\n",perr);
}
db_gdbmunlock();
@ -423,6 +423,7 @@ int db_start_initial_update(void) {
/* load up the red-black tree with all the current songs in the db */
db_gdbmlock();
sqlite_exec(db_songs,"PRAGMA synchronous=OFF;",NULL,NULL,&perr);
err=sqlite_get_table(db_songs,"SELECT id FROM songs",&resarray,
&rows, &cols, &perr);
db_gdbmunlock();
@ -474,6 +475,12 @@ int db_end_initial_update(void) {
DB_PLAYLIST *current,*last;
DB_PLAYLISTENTRY *pple;
char *perr;
db_gdbmlock();
sqlite_exec(db_songs,"PRAGMA synchronous=NORMAL;",NULL,NULL,&perr);
db_gdbmunlock();
DPRINTF(E_DBG,L_DB|L_SCAN,"Initial update over. Removing stale items\n");
val=rblookup(RB_LUFIRST,NULL,db_removed);

View File

@ -182,6 +182,7 @@ void daap_handler(WS_CONNINFO *pwsc) {
int start_time;
int end_time;
int bytes_written;
int serialize_as_xml;
MP3FILE *pmp3;
int file_fd;
@ -256,7 +257,7 @@ void daap_handler(WS_CONNINFO *pwsc) {
* /databases/id/containers, which returns a container
* /databases/id/containers/id/items, which returns playlist elements
* /databases/id/items/id.mp3, to spool an mp3
* /databases/id/browse/category
* /databases/id/browse/category
*/
uri = strdup(pwsc->uri);
@ -342,7 +343,13 @@ void daap_handler(WS_CONNINFO *pwsc) {
if(!streaming) {
DPRINTF(E_DBG,L_WS,"Satisfying request\n");
if((config.compress) && ws_testrequestheader(pwsc,"Accept-Encoding","gzip") && root->reported_size >= 1000) {
serialize_as_xml=0;
if(ws_getvar(pwsc,"output"))
serialize_as_xml=1;
if((config.compress) && ws_testrequestheader(pwsc,"Accept-Encoding","gzip") &&
(root->reported_size >= 1000) && (!serialize_as_xml)) {
compress=1;
}
@ -366,11 +373,21 @@ void daap_handler(WS_CONNINFO *pwsc) {
}
else {
bytes_written = root->reported_size + 8;
ws_addresponseheader(pwsc,"Content-Length","%d",bytes_written);
if(!serialize_as_xml) {
ws_addresponseheader(pwsc,"Content-Length","%d",bytes_written);
} else {
ws_addresponseheader(pwsc,"Connection","close");
pwsc->close=1;
}
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
DPRINTF(E_DBG,L_WS,"Emitting headers\n");
ws_emitheaders(pwsc);
daap_serialize(root,pwsc->fd,NULL);
if(!serialize_as_xml) {
daap_serialize(root,pwsc->fd,NULL);
} else {
ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
daap_serialize_xml(root,pwsc->fd);
}
}
end_time = time(NULL);
DPRINTF(E_DBG,L_WS|L_DAAP,"Sent %d bytes in %d seconds\n",bytes_written,end_time-start_time);

View File

@ -68,6 +68,18 @@ static int gettimeout(struct timeval end,
return 0;
}
int r_fdprintf(int fd, char *fmt, ...) {
char buffer[1024];
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, 1024, fmt, ap);
va_end(ap);
return r_write(fd,buffer,strlen(buffer));
}
/* Restart versions of traditional functions */
int r_close(int fildes) {

View File

@ -43,6 +43,7 @@
struct timeval add2currenttime(double seconds);
int copyfile(int fromfd, int tofd);
int r_fdprintf(int fd, char *fmt, ...);
int r_close(int fildes);
int r_dup2(int fildes, int fildes2);
int r_open2(const char *path, int oflag);

View File

@ -1109,14 +1109,20 @@ int ws_testrequestheader(WS_CONNINFO *pwsc, char *header, char *value) {
*/
int ws_testarg(ARGLIST *root, char *key, char *value) {
char *retval;
int result;
DPRINTF(E_DBG,L_WS,"Checking to see if %s matches %s\n",key,value);
retval=ws_getarg(root,key);
if(!retval)
if(!retval) {
DPRINTF(E_DBG,L_WS,"Nope!\n");
return 0;
}
return !strcasecmp(value,retval);
result=!strcasecmp(value,retval);
DPRINTF(E_DBG,L_WS,"And it %s\n",result ? "DOES!" : "does NOT");
return result;
}
/*
@ -1187,7 +1193,7 @@ int ws_addarg(ARGLIST *root, char *key, char *fmt, ...) {
current=root->next;
while(current) {
if(!strcmp(current->key,key)) {
if(!strcasecmp(current->key,key)) {
/* got a match! */
DPRINTF(E_DBG,L_WS,"Updating %s from %s to %s\n",
key,current->value,value);