1/* 2 * Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <string.h> 24#include <stdint.h> 25 26#include <event.h> 27#include "evhttp/evhttp.h" 28 29#include "db.h" 30#include "misc.h" 31#include "logger.h" 32#include "dmap_common.h" 33 34 35/* gperf static hash, dmap_fields.gperf */ 36#include "dmap_fields_hash.c" 37 38 39const struct dmap_field * 40dmap_get_fields_table(int *nfields) 41{ 42 *nfields = sizeof(dmap_fields) / sizeof(dmap_fields[0]); 43 44 return dmap_fields; 45} 46 47 48void 49dmap_add_container(struct evbuffer *evbuf, char *tag, int len) 50{ 51 unsigned char buf[4]; 52 53 evbuffer_add(evbuf, tag, 4); 54 55 /* Container length */ 56 buf[0] = (len >> 24) & 0xff; 57 buf[1] = (len >> 16) & 0xff; 58 buf[2] = (len >> 8) & 0xff; 59 buf[3] = len & 0xff; 60 61 evbuffer_add(evbuf, buf, sizeof(buf)); 62} 63 64void 65dmap_add_long(struct evbuffer *evbuf, char *tag, int64_t val) 66{ 67 unsigned char buf[12]; 68 69 evbuffer_add(evbuf, tag, 4); 70 71 /* Length */ 72 buf[0] = 0; 73 buf[1] = 0; 74 buf[2] = 0; 75 buf[3] = 8; 76 77 /* Value */ 78 buf[4] = (val >> 56) & 0xff; 79 buf[5] = (val >> 48) & 0xff; 80 buf[6] = (val >> 40) & 0xff; 81 buf[7] = (val >> 32) & 0xff; 82 buf[8] = (val >> 24) & 0xff; 83 buf[9] = (val >> 16) & 0xff; 84 buf[10] = (val >> 8) & 0xff; 85 buf[11] = val & 0xff; 86 87 evbuffer_add(evbuf, buf, sizeof(buf)); 88} 89 90void 91dmap_add_int(struct evbuffer *evbuf, char *tag, int val) 92{ 93 unsigned char buf[8]; 94 95 evbuffer_add(evbuf, tag, 4); 96 97 /* Length */ 98 buf[0] = 0; 99 buf[1] = 0; 100 buf[2] = 0; 101 buf[3] = 4; 102 103 /* Value */ 104 buf[4] = (val >> 24) & 0xff; 105 buf[5] = (val >> 16) & 0xff; 106 buf[6] = (val >> 8) & 0xff; 107 buf[7] = val & 0xff; 108 109 evbuffer_add(evbuf, buf, sizeof(buf)); 110} 111 112void 113dmap_add_short(struct evbuffer *evbuf, char *tag, short val) 114{ 115 unsigned char buf[6]; 116 117 evbuffer_add(evbuf, tag, 4); 118 119 /* Length */ 120 buf[0] = 0; 121 buf[1] = 0; 122 buf[2] = 0; 123 buf[3] = 2; 124 125 /* Value */ 126 buf[4] = (val >> 8) & 0xff; 127 buf[5] = val & 0xff; 128 129 evbuffer_add(evbuf, buf, sizeof(buf)); 130} 131 132void 133dmap_add_char(struct evbuffer *evbuf, char *tag, char val) 134{ 135 unsigned char buf[5]; 136 137 evbuffer_add(evbuf, tag, 4); 138 139 /* Length */ 140 buf[0] = 0; 141 buf[1] = 0; 142 buf[2] = 0; 143 buf[3] = 1; 144 145 /* Value */ 146 buf[4] = val; 147 148 evbuffer_add(evbuf, buf, sizeof(buf)); 149} 150 151void 152dmap_add_literal(struct evbuffer *evbuf, char *tag, char *str, int len) 153{ 154 char buf[4]; 155 156 evbuffer_add(evbuf, tag, 4); 157 158 /* Length */ 159 buf[0] = (len >> 24) & 0xff; 160 buf[1] = (len >> 16) & 0xff; 161 buf[2] = (len >> 8) & 0xff; 162 buf[3] = len & 0xff; 163 164 evbuffer_add(evbuf, buf, sizeof(buf)); 165 166 if (str && (len > 0)) 167 evbuffer_add(evbuf, str, len); 168} 169 170void 171dmap_add_string(struct evbuffer *evbuf, char *tag, const char *str) 172{ 173 unsigned char buf[4]; 174 int len; 175 176 if (str) 177 len = strlen(str); 178 else 179 len = 0; 180 181 evbuffer_add(evbuf, tag, 4); 182 183 /* String length */ 184 buf[0] = (len >> 24) & 0xff; 185 buf[1] = (len >> 16) & 0xff; 186 buf[2] = (len >> 8) & 0xff; 187 buf[3] = len & 0xff; 188 189 evbuffer_add(evbuf, buf, sizeof(buf)); 190 191 if (len) 192 evbuffer_add(evbuf, str, len); 193} 194 195void 196dmap_add_field(struct evbuffer *evbuf, const struct dmap_field *df, char *strval, int32_t intval) 197{ 198 union { 199 int32_t v_i32; 200 uint32_t v_u32; 201 int64_t v_i64; 202 uint64_t v_u64; 203 } val; 204 int ret; 205 206 if (strval && (df->type != DMAP_TYPE_STRING)) 207 { 208 switch (df->type) 209 { 210 case DMAP_TYPE_DATE: 211 case DMAP_TYPE_UBYTE: 212 case DMAP_TYPE_USHORT: 213 case DMAP_TYPE_UINT: 214 ret = safe_atou32(strval, &val.v_u32); 215 if (ret < 0) 216 val.v_u32 = 0; 217 break; 218 219 case DMAP_TYPE_BYTE: 220 case DMAP_TYPE_SHORT: 221 case DMAP_TYPE_INT: 222 ret = safe_atoi32(strval, &val.v_i32); 223 if (ret < 0) 224 val.v_i32 = 0; 225 break; 226 227 case DMAP_TYPE_ULONG: 228 ret = safe_atou64(strval, &val.v_u64); 229 if (ret < 0) 230 val.v_u64 = 0; 231 break; 232 233 case DMAP_TYPE_LONG: 234 ret = safe_atoi64(strval, &val.v_i64); 235 if (ret < 0) 236 val.v_i64 = 0; 237 break; 238 239 /* DMAP_TYPE_VERSION & DMAP_TYPE_LIST not handled here */ 240 default: 241 DPRINTF(E_LOG, L_DAAP, "Unsupported DMAP type %d for DMAP field %s\n", df->type, df->desc); 242 return; 243 } 244 } 245 else if (!strval && (df->type != DMAP_TYPE_STRING)) 246 { 247 switch (df->type) 248 { 249 case DMAP_TYPE_DATE: 250 case DMAP_TYPE_UBYTE: 251 case DMAP_TYPE_USHORT: 252 case DMAP_TYPE_UINT: 253 val.v_u32 = intval; 254 break; 255 256 case DMAP_TYPE_BYTE: 257 case DMAP_TYPE_SHORT: 258 case DMAP_TYPE_INT: 259 val.v_i32 = intval; 260 break; 261 262 case DMAP_TYPE_ULONG: 263 val.v_u64 = intval; 264 break; 265 266 case DMAP_TYPE_LONG: 267 val.v_i64 = intval; 268 break; 269 270 /* DMAP_TYPE_VERSION & DMAP_TYPE_LIST not handled here */ 271 default: 272 DPRINTF(E_LOG, L_DAAP, "Unsupported DMAP type %d for DMAP field %s\n", df->type, df->desc); 273 return; 274 } 275 } 276 277 switch (df->type) 278 { 279 case DMAP_TYPE_UBYTE: 280 if (val.v_u32) 281 dmap_add_char(evbuf, df->tag, val.v_u32); 282 break; 283 284 case DMAP_TYPE_BYTE: 285 if (val.v_i32) 286 dmap_add_char(evbuf, df->tag, val.v_i32); 287 break; 288 289 case DMAP_TYPE_USHORT: 290 if (val.v_u32) 291 dmap_add_short(evbuf, df->tag, val.v_u32); 292 break; 293 294 case DMAP_TYPE_SHORT: 295 if (val.v_i32) 296 dmap_add_short(evbuf, df->tag, val.v_i32); 297 break; 298 299 case DMAP_TYPE_DATE: 300 case DMAP_TYPE_UINT: 301 if (val.v_u32) 302 dmap_add_int(evbuf, df->tag, val.v_u32); 303 break; 304 305 case DMAP_TYPE_INT: 306 if (val.v_i32) 307 dmap_add_int(evbuf, df->tag, val.v_i32); 308 break; 309 310 case DMAP_TYPE_ULONG: 311 if (val.v_u64) 312 dmap_add_long(evbuf, df->tag, val.v_u64); 313 break; 314 315 case DMAP_TYPE_LONG: 316 if (val.v_i64) 317 dmap_add_long(evbuf, df->tag, val.v_i64); 318 break; 319 320 case DMAP_TYPE_STRING: 321 if (strval) 322 dmap_add_string(evbuf, df->tag, strval); 323 break; 324 325 case DMAP_TYPE_VERSION: 326 case DMAP_TYPE_LIST: 327 return; 328 } 329} 330 331 332void 333dmap_send_error(struct evhttp_request *req, char *container, char *errmsg) 334{ 335 struct evbuffer *evbuf; 336 int len; 337 int ret; 338 339 evbuf = evbuffer_new(); 340 if (!evbuf) 341 { 342 DPRINTF(E_LOG, L_DMAP, "Could not allocate evbuffer for DMAP error\n"); 343 344 evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error"); 345 return; 346 } 347 348 len = 12 + 8 + 8 + strlen(errmsg); 349 350 ret = evbuffer_expand(evbuf, len); 351 if (ret < 0) 352 { 353 DPRINTF(E_LOG, L_DMAP, "Could not expand evbuffer for DMAP error\n"); 354 355 evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error"); 356 357 evbuffer_free(evbuf); 358 return; 359 } 360 361 dmap_add_container(evbuf, container, len - 8); 362 dmap_add_int(evbuf, "mstt", 500); 363 dmap_add_string(evbuf, "msts", errmsg); 364 365 evhttp_send_reply(req, HTTP_OK, "OK", evbuf); 366 367 evbuffer_free(evbuf); 368} 369 370 371int 372dmap_encode_file_metadata(struct evbuffer *songlist, struct evbuffer *song, struct db_media_file_info *dbmfi, const struct dmap_field **meta, int nmeta, int sort_tags, int force_wav) 373{ 374 const struct dmap_field_map *dfm; 375 const struct dmap_field *df; 376 char **strval; 377 char *ptr; 378 int32_t val; 379 int want_mikd; 380 int want_asdk; 381 int i; 382 int ret; 383 384 want_mikd = 0; 385 want_asdk = 0; 386 387 i = -1; 388 while (1) 389 { 390 i++; 391 392 /* Specific meta tags requested (or default list) */ 393 if (nmeta > 0) 394 { 395 if (i == nmeta) 396 break; 397 398 df = meta[i]; 399 dfm = df->dfm; 400 } 401 /* No specific meta tags requested, send out everything */ 402 else 403 { 404 /* End of list */ 405 if (i == (sizeof(dmap_fields) / sizeof(dmap_fields[0]))) 406 break; 407 408 df = &dmap_fields[i]; 409 dfm = dmap_fields[i].dfm; 410 } 411 412 /* Not in struct media_file_info */ 413 if (dfm->mfi_offset < 0) 414 continue; 415 416 /* Will be prepended to the list */ 417 if (dfm == &dfm_dmap_mikd) 418 { 419 /* item kind */ 420 want_mikd = 1; 421 continue; 422 } 423 else if (dfm == &dfm_dmap_asdk) 424 { 425 /* data kind */ 426 want_asdk = 1; 427 continue; 428 } 429 430 DPRINTF(E_DBG, L_DAAP, "Investigating %s\n", df->desc); 431 432 strval = (char **) ((char *)dbmfi + dfm->mfi_offset); 433 434 if (!(*strval) || (**strval == '\0')) 435 continue; 436 437 /* Here's one exception ... codectype (ascd) is actually an integer */ 438 if (dfm == &dfm_dmap_ascd) 439 { 440 dmap_add_literal(song, df->tag, *strval, 4); 441 continue; 442 } 443 444 val = 0; 445 446 if (force_wav) 447 { 448 switch (dfm->mfi_offset) 449 { 450 case dbmfi_offsetof(type): 451 ptr = "wav"; 452 strval = &ptr; 453 break; 454 455 case dbmfi_offsetof(bitrate): 456 val = 0; 457 ret = safe_atoi32(dbmfi->samplerate, &val); 458 if ((ret < 0) || (val == 0)) 459 val = 1411; 460 else 461 val = (val * 8) / 250; 462 463 ptr = NULL; 464 strval = &ptr; 465 break; 466 467 case dbmfi_offsetof(description): 468 ptr = "wav audio file"; 469 strval = &ptr; 470 break; 471 472 default: 473 break; 474 } 475 } 476 477 dmap_add_field(song, df, *strval, val); 478 479 DPRINTF(E_DBG, L_DAAP, "Done with meta tag %s (%s)\n", df->desc, *strval); 480 } 481 482 if (sort_tags) 483 { 484 dmap_add_string(song, "assn", dbmfi->title_sort); 485 dmap_add_string(song, "assa", dbmfi->artist_sort); 486 dmap_add_string(song, "assu", dbmfi->album_sort); 487 dmap_add_string(song, "assl", dbmfi->album_artist_sort); 488 489 if (dbmfi->composer_sort) 490 dmap_add_string(song, "assc", dbmfi->composer_sort); 491 } 492 493 val = 0; 494 if (want_mikd) 495 val += 9; 496 if (want_asdk) 497 val += 9; 498 499 dmap_add_container(songlist, "mlit", EVBUFFER_LENGTH(song) + val); 500 501 /* Prepend mikd & asdk if needed */ 502 if (want_mikd) 503 { 504 /* dmap.itemkind must come first */ 505 ret = safe_atoi32(dbmfi->item_kind, &val); 506 if (ret < 0) 507 val = 2; /* music by default */ 508 dmap_add_char(songlist, "mikd", val); 509 } 510 if (want_asdk) 511 { 512 ret = safe_atoi32(dbmfi->data_kind, &val); 513 if (ret < 0) 514 val = 0; 515 dmap_add_char(songlist, "asdk", val); 516 } 517 518 ret = evbuffer_add_buffer(songlist, song); 519 if (ret < 0) 520 { 521 DPRINTF(E_LOG, L_DAAP, "Could not add song to song list\n"); 522 523 return -1; 524 } 525 526 return 0; 527} 528