diff options
Diffstat (limited to 'firmware/id3.c')
-rw-r--r-- | firmware/id3.c | 166 |
1 files changed, 109 insertions, 57 deletions
diff --git a/firmware/id3.c b/firmware/id3.c index 7344bf53c7..d783053426 100644 --- a/firmware/id3.c +++ b/firmware/id3.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include "id3.h" | 41 | #include "id3.h" |
42 | #include "mp3data.h" | 42 | #include "mp3data.h" |
43 | #include "system.h" | 43 | #include "system.h" |
44 | #include "replaygain.h" | ||
44 | 45 | ||
45 | #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ | 46 | #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ |
46 | ((long)(b1 & 0x7F) << (2*7)) | \ | 47 | ((long)(b1 & 0x7F) << (2*7)) | \ |
@@ -163,6 +164,10 @@ char* id3_get_codec(const struct mp3entry* id3) | |||
163 | Many ID3 symbolic names come in more than one form. You can add both | 164 | Many ID3 symbolic names come in more than one form. You can add both |
164 | forms, each referencing the same variable in struct mp3entry. | 165 | forms, each referencing the same variable in struct mp3entry. |
165 | If both forms are present, the last found will be used. | 166 | If both forms are present, the last found will be used. |
167 | Note that the offset can be zero, in which case no entry will be set | ||
168 | in the mp3entry struct; the frame is still read into the buffer and | ||
169 | the special processing function is called (several times, if there | ||
170 | are several frames with the same name). | ||
166 | 171 | ||
167 | 4. Alternately, use the TAG_LIST_ENTRY macro with | 172 | 4. Alternately, use the TAG_LIST_ENTRY macro with |
168 | ID3 tag symbolic name, | 173 | ID3 tag symbolic name, |
@@ -305,6 +310,34 @@ static int parsegenre( struct mp3entry* entry, char* tag, int bufferpos ) | |||
305 | } | 310 | } |
306 | } | 311 | } |
307 | 312 | ||
313 | #if CONFIG_HWCODEC == MASNONE | ||
314 | /* parse user defined text, looking for replaygain information. */ | ||
315 | static int parseuser( struct mp3entry* entry, char* tag, int bufferpos ) | ||
316 | { | ||
317 | char* value = NULL; | ||
318 | int desc_len = strlen(tag); | ||
319 | int value_len = 0; | ||
320 | |||
321 | if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos) { | ||
322 | /* At least part of the value was read, so we can safely try to | ||
323 | * parse it | ||
324 | */ | ||
325 | |||
326 | value = tag + desc_len + 1; | ||
327 | value_len = parse_replaygain(tag, value, entry, tag, | ||
328 | bufferpos - (tag - entry->id3v2buf)); | ||
329 | } | ||
330 | |||
331 | if (value_len) { | ||
332 | bufferpos = tag - entry->id3v2buf + value_len; | ||
333 | } else { | ||
334 | bufferpos = tag - entry->id3v2buf; | ||
335 | } | ||
336 | |||
337 | return bufferpos; | ||
338 | } | ||
339 | #endif | ||
340 | |||
308 | static const struct tag_resolver taglist[] = { | 341 | static const struct tag_resolver taglist[] = { |
309 | { "TPE1", 4, offsetof(struct mp3entry, artist), NULL }, | 342 | { "TPE1", 4, offsetof(struct mp3entry, artist), NULL }, |
310 | { "TP1", 3, offsetof(struct mp3entry, artist), NULL }, | 343 | { "TP1", 3, offsetof(struct mp3entry, artist), NULL }, |
@@ -319,6 +352,9 @@ static const struct tag_resolver taglist[] = { | |||
319 | { "TCOM", 4, offsetof(struct mp3entry, composer), NULL }, | 352 | { "TCOM", 4, offsetof(struct mp3entry, composer), NULL }, |
320 | { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre }, | 353 | { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre }, |
321 | { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre }, | 354 | { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre }, |
355 | #if CONFIG_HWCODEC == MASNONE | ||
356 | { "TXXX", 4, 0, &parseuser }, | ||
357 | #endif | ||
322 | }; | 358 | }; |
323 | 359 | ||
324 | #define TAGLIST_SIZE ((int)(sizeof(taglist) / sizeof(taglist[0]))) | 360 | #define TAGLIST_SIZE ((int)(sizeof(taglist) / sizeof(taglist[0]))) |
@@ -327,12 +363,12 @@ static const struct tag_resolver taglist[] = { | |||
327 | string. If it is, we attempt to convert it to a 8-bit ASCII string | 363 | string. If it is, we attempt to convert it to a 8-bit ASCII string |
328 | (for valid 8-bit ASCII characters). If it's not unicode, we leave | 364 | (for valid 8-bit ASCII characters). If it's not unicode, we leave |
329 | it alone. At some point we should fully support unicode strings */ | 365 | it alone. At some point we should fully support unicode strings */ |
330 | static int unicode_munge(char** string, int *len) { | 366 | static int unicode_munge(char* string, int *len) { |
331 | long tmp; | 367 | long tmp; |
332 | bool le = false; | 368 | bool le = false; |
333 | int i; | 369 | int i; |
334 | char *str = *string; | 370 | char *str = string; |
335 | char *outstr = *string; | 371 | char *outstr = string; |
336 | bool bom = false; | 372 | bool bom = false; |
337 | int outlen; | 373 | int outlen; |
338 | 374 | ||
@@ -343,8 +379,14 @@ static int unicode_munge(char** string, int *len) { | |||
343 | 379 | ||
344 | /* Type 0x00 is ordinary ISO 8859-1 */ | 380 | /* Type 0x00 is ordinary ISO 8859-1 */ |
345 | if(str[0] == 0x00) { | 381 | if(str[0] == 0x00) { |
346 | (*len)--; | 382 | int i = --(*len); |
347 | (*string)++; /* Skip the encoding type byte */ | 383 | |
384 | /* We must move the string to the left */ | ||
385 | while (i--) { | ||
386 | string[0] = string[1]; | ||
387 | string++; | ||
388 | } | ||
389 | |||
348 | return 0; | 390 | return 0; |
349 | } | 391 | } |
350 | 392 | ||
@@ -352,53 +394,59 @@ static int unicode_munge(char** string, int *len) { | |||
352 | if(str[0] == 0x01 || str[0] == 0x02) { | 394 | if(str[0] == 0x01 || str[0] == 0x02) { |
353 | (*len)--; | 395 | (*len)--; |
354 | str++; | 396 | str++; |
355 | tmp = BYTES2INT(0, 0, str[0], str[1]); | ||
356 | |||
357 | /* Now check if there is a BOM (zero-width non-breaking space, 0xfeff) | ||
358 | and if it is in little or big endian format */ | ||
359 | if(tmp == 0xfffe) { /* Little endian? */ | ||
360 | bom = true; | ||
361 | le = true; | ||
362 | str += 2; | ||
363 | (*len)-=2; | ||
364 | } | ||
365 | |||
366 | if(tmp == 0xfeff) { /* Big endian? */ | ||
367 | bom = true; | ||
368 | str += 2; | ||
369 | (*len)-=2; | ||
370 | } | ||
371 | |||
372 | /* If there is no BOM (which is a specification violation), | ||
373 | let's try to guess it. If one of the bytes is 0x00, it is | ||
374 | probably the most significant one. */ | ||
375 | if(!bom) { | ||
376 | if(str[1] == 0) | ||
377 | le = true; | ||
378 | } | ||
379 | |||
380 | i = 0; | 397 | i = 0; |
381 | 398 | ||
382 | outlen = *len / 2; | 399 | /* Handle frames with more than one string (needed for TXXX frames). |
383 | 400 | */ | |
384 | do { | 401 | do { |
385 | if(le) { | 402 | tmp = BYTES2INT(0, 0, str[0], str[1]); |
386 | if(str[1]) | 403 | |
387 | outstr[i++] = '.'; | 404 | /* Now check if there is a BOM (zero-width non-breaking space, 0xfeff) |
388 | else | 405 | and if it is in little or big endian format */ |
389 | outstr[i++] = str[0]; | 406 | if(tmp == 0xfffe) { /* Little endian? */ |
390 | } else { | 407 | bom = true; |
391 | if(str[0]) | 408 | le = true; |
392 | outstr[i++] = '.'; | 409 | str += 2; |
393 | else | 410 | (*len)-=2; |
394 | outstr[i++] = str[1]; | 411 | } |
412 | |||
413 | if(tmp == 0xfeff) { /* Big endian? */ | ||
414 | bom = true; | ||
415 | str += 2; | ||
416 | (*len)-=2; | ||
417 | } | ||
418 | |||
419 | /* If there is no BOM (which is a specification violation), | ||
420 | let's try to guess it. If one of the bytes is 0x00, it is | ||
421 | probably the most significant one. */ | ||
422 | if(!bom) { | ||
423 | if(str[1] == 0) | ||
424 | le = true; | ||
395 | } | 425 | } |
426 | |||
427 | outlen = *len / 2; | ||
428 | |||
429 | do { | ||
430 | if(le) { | ||
431 | if(str[1]) | ||
432 | outstr[i++] = '.'; | ||
433 | else | ||
434 | outstr[i++] = str[0]; | ||
435 | } else { | ||
436 | if(str[0]) | ||
437 | outstr[i++] = '.'; | ||
438 | else | ||
439 | outstr[i++] = str[1]; | ||
440 | } | ||
441 | str += 2; | ||
442 | } while((str[0] || str[1]) && (i < outlen)); | ||
443 | |||
396 | str += 2; | 444 | str += 2; |
397 | } while((str[0] || str[1]) && (i < outlen)); | 445 | outstr[i++] = 0; /* Terminate the string */ |
446 | } while(i < outlen); | ||
398 | 447 | ||
399 | *len = i; | 448 | *len = i - 1; |
400 | 449 | ||
401 | outstr[i] = 0; /* Terminate the string */ | ||
402 | return 0; | 450 | return 0; |
403 | } | 451 | } |
404 | 452 | ||
@@ -686,29 +734,33 @@ static void setid3v2title(int fd, struct mp3entry *entry) | |||
686 | 734 | ||
687 | for (i=0; i<TAGLIST_SIZE; i++) { | 735 | for (i=0; i<TAGLIST_SIZE; i++) { |
688 | const struct tag_resolver* tr = &taglist[i]; | 736 | const struct tag_resolver* tr = &taglist[i]; |
689 | char** ptag = (char**) (((char*)entry) + tr->offset); | 737 | char** ptag = tr->offset ? (char**) (((char*)entry) + tr->offset) |
738 | : NULL; | ||
690 | char* tag; | 739 | char* tag; |
691 | 740 | ||
692 | if( !*ptag && !memcmp( header, tr->tag, tr->tag_length ) ) { | 741 | if( (!ptag || !*ptag) && !memcmp( header, tr->tag, tr->tag_length ) ) { |
693 | 742 | ||
694 | /* found a tag matching one in tagList, and not yet filled */ | 743 | /* found a tag matching one in tagList, and not yet filled */ |
744 | tag = buffer + bufferpos; | ||
745 | |||
695 | if(global_unsynch && version <= ID3_VER_2_3) | 746 | if(global_unsynch && version <= ID3_VER_2_3) |
696 | bytesread = read_unsynched(fd, buffer + bufferpos, | 747 | bytesread = read_unsynched(fd, tag, framelen); |
697 | framelen); | ||
698 | else | 748 | else |
699 | bytesread = read(fd, buffer + bufferpos, framelen); | 749 | bytesread = read(fd, tag, framelen); |
700 | 750 | ||
701 | if( bytesread != framelen ) | 751 | if( bytesread != framelen ) |
702 | return; | 752 | return; |
703 | 753 | ||
704 | size -= bytesread; | 754 | size -= bytesread; |
705 | *ptag = buffer + bufferpos; | 755 | |
706 | |||
707 | if(unsynch || (global_unsynch && version >= ID3_VER_2_4)) | 756 | if(unsynch || (global_unsynch && version >= ID3_VER_2_4)) |
708 | bytesread = unsynchronize_frame(*ptag, bytesread); | 757 | bytesread = unsynchronize_frame(tag, bytesread); |
709 | 758 | ||
710 | unicode_munge( ptag, &bytesread ); | 759 | unicode_munge( tag, &bytesread ); |
711 | tag = *ptag; | 760 | |
761 | if (ptag) | ||
762 | *ptag = tag; | ||
763 | |||
712 | /* remove trailing spaces */ | 764 | /* remove trailing spaces */ |
713 | while ( bytesread > 0 && isspace(tag[bytesread-1])) | 765 | while ( bytesread > 0 && isspace(tag[bytesread-1])) |
714 | bytesread--; | 766 | bytesread--; |