Rev 1905 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1905 | Rev 3960 | ||
---|---|---|---|
Line 33... | Line 33... | ||
33 | convert_utf16bom, |
33 | convert_utf16bom, |
34 | convert_utf16bom, |
34 | convert_utf16bom, |
35 | convert_utf8 |
35 | convert_utf8 |
36 | }; |
36 | }; |
Line 37... | Line 37... | ||
37 | 37 | ||
Line 38... | Line 38... | ||
38 | const unsigned int encoding_widths[4] = { 1, 2, 2, 1 }; |
38 | static const unsigned int encoding_widths[4] = { 1, 2, 2, 1 }; |
Line 39... | Line 39... | ||
39 | 39 | ||
40 | /* the code starts here... */ |
40 | /* the code starts here... */ |
Line 184... | Line 184... | ||
184 | Preserve the zero string separator (I don't need strlen for the total size). |
184 | Preserve the zero string separator (I don't need strlen for the total size). |
Line 185... | Line 185... | ||
185 | 185 | ||
186 | ID3v2 standard says that there should be one text frame of specific type per tag, and subsequent tags overwrite old values. |
186 | ID3v2 standard says that there should be one text frame of specific type per tag, and subsequent tags overwrite old values. |
187 | So, I always replace the text that may be stored already (perhaps with a list of zero-separated strings, though). |
187 | So, I always replace the text that may be stored already (perhaps with a list of zero-separated strings, though). |
188 | */ |
188 | */ |
189 | void store_id3_text(mpg123_string *sb, char *source, size_t source_size, const int noquiet, const int notranslate) |
189 | static void store_id3_text(mpg123_string *sb, char *source, size_t source_size, const int noquiet, const int notranslate) |
190 | { |
190 | { |
191 | if(!source_size) |
191 | if(!source_size) |
192 | { |
192 | { |
193 | debug("Empty id3 data!"); |
193 | debug("Empty id3 data!"); |
Line 245... | Line 245... | ||
245 | source_size -= source_size % bwidth; |
245 | source_size -= source_size % bwidth; |
246 | } |
246 | } |
247 | text_converters[encoding](sb, source, source_size, noquiet); |
247 | text_converters[encoding](sb, source, source_size, noquiet); |
248 | } |
248 | } |
Line 249... | Line 249... | ||
249 | 249 | ||
250 | char *next_text(char* prev, int encoding, size_t limit) |
250 | static char *next_text(char* prev, int encoding, size_t limit) |
251 | { |
251 | { |
252 | char *text = prev; |
252 | char *text = prev; |
Line 253... | Line 253... | ||
253 | size_t width = encoding_widths[encoding]; |
253 | size_t width = encoding_widths[encoding]; |
Line 272... | Line 272... | ||
272 | else return NULL; /* No full character left? This text is broken */ |
272 | else return NULL; /* No full character left? This text is broken */ |
273 | } |
273 | } |
Line 274... | Line 274... | ||
274 | 274 | ||
275 | text += width; |
275 | text += width; |
276 | } |
276 | } |
Line 277... | Line 277... | ||
277 | if(text-prev >= limit) text = NULL; |
277 | if((size_t)(text-prev) >= limit) text = NULL; |
278 | 278 | ||
Line 279... | Line 279... | ||
279 | return text; |
279 | return text; |
Line 350... | Line 350... | ||
350 | init_mpg123_text(&localcom); |
350 | init_mpg123_text(&localcom); |
351 | /* Store the text, without translation to UTF-8, but for comments always a local copy in UTF-8. |
351 | /* Store the text, without translation to UTF-8, but for comments always a local copy in UTF-8. |
352 | Reminder: No bailing out from here on without freeing the local comment data! */ |
352 | Reminder: No bailing out from here on without freeing the local comment data! */ |
353 | store_id3_text(&xcom->description, descr-1, text-descr+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT); |
353 | store_id3_text(&xcom->description, descr-1, text-descr+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT); |
354 | if(tt == comment) |
354 | if(tt == comment) |
355 | store_id3_text(&localcom.description, descr-1, text-descr+1, NOQUIET, 1); |
355 | store_id3_text(&localcom.description, descr-1, text-descr+1, NOQUIET, 0); |
Line 356... | Line 356... | ||
356 | 356 | ||
357 | text[-1] = encoding; /* Byte abusal for encoding... */ |
357 | text[-1] = encoding; /* Byte abusal for encoding... */ |
358 | store_id3_text(&xcom->text, text-1, realsize+1-(text-realdata), NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT); |
358 | store_id3_text(&xcom->text, text-1, realsize+1-(text-realdata), NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT); |
Line 377... | Line 377... | ||
377 | || !strcasecmp(localcom.description.p, "rva_user") ) |
377 | || !strcasecmp(localcom.description.p, "rva_user") ) |
378 | rva_mode = 1; |
378 | rva_mode = 1; |
379 | if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level)) |
379 | if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level)) |
380 | { |
380 | { |
381 | /* Only translate the contents in here where we really need them. */ |
381 | /* Only translate the contents in here where we really need them. */ |
382 | store_id3_text(&localcom.text, text-1, realsize+1-(text-realdata), NOQUIET, 1); |
382 | store_id3_text(&localcom.text, text-1, realsize+1-(text-realdata), NOQUIET, 0); |
383 | if(localcom.text.fill > 0) |
383 | if(localcom.text.fill > 0) |
384 | { |
384 | { |
385 | fr->rva.gain[rva_mode] = (float) atof(localcom.text.p); |
385 | fr->rva.gain[rva_mode] = (float) atof(localcom.text.p); |
386 | if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]); |
386 | if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]); |
387 | fr->rva.peak[rva_mode] = 0; |
387 | fr->rva.peak[rva_mode] = 0; |
Line 391... | Line 391... | ||
391 | } |
391 | } |
392 | /* Make sure to free the local memory... */ |
392 | /* Make sure to free the local memory... */ |
393 | free_mpg123_text(&localcom); |
393 | free_mpg123_text(&localcom); |
394 | } |
394 | } |
Line 395... | Line 395... | ||
395 | 395 | ||
396 | void process_extra(mpg123_handle *fr, char* realdata, size_t realsize, int rva_level, char *id) |
396 | static void process_extra(mpg123_handle *fr, char* realdata, size_t realsize, int rva_level, char *id) |
397 | { |
397 | { |
398 | /* Text encoding $xx */ |
398 | /* Text encoding $xx */ |
399 | /* Description ... $00 (00) */ |
399 | /* Description ... $00 (00) */ |
400 | /* Text ... */ |
400 | /* Text ... */ |
Line 422... | Line 422... | ||
422 | if(NOQUIET) error("Unable to attach new extra text!"); |
422 | if(NOQUIET) error("Unable to attach new extra text!"); |
423 | return; |
423 | return; |
424 | } |
424 | } |
425 | memcpy(xex->id, id, 4); |
425 | memcpy(xex->id, id, 4); |
426 | init_mpg123_text(&localex); /* For our local copy. */ |
426 | init_mpg123_text(&localex); /* For our local copy. */ |
- | 427 | ||
- | 428 | /* The outside storage gets reencoded to UTF-8 only if not requested otherwise. |
|
- | 429 | Remember that we really need the -1 here to hand in the encoding byte!*/ |
|
427 | store_id3_text(&xex->description, descr-1, text-descr+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT); |
430 | store_id3_text(&xex->description, descr-1, text-descr+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT); |
- | 431 | /* Our local copy is always stored in UTF-8! */ |
|
428 | store_id3_text(&localex.description, descr-1, text-descr+1, NOQUIET, 1); |
432 | store_id3_text(&localex.description, descr-1, text-descr+1, NOQUIET, 0); |
- | 433 | /* At first, only store the outside copy of the payload. We may not need the local copy. */ |
|
429 | text[-1] = encoding; |
434 | text[-1] = encoding; |
430 | store_id3_text(&xex->text, text-1, realsize-(text-realdata)+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT); |
435 | store_id3_text(&xex->text, text-1, realsize-(text-realdata)+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT); |
- | 436 | ||
431 | /* Now check if we would like to interpret this extra info for RVA. */ |
437 | /* Now check if we would like to interpret this extra info for RVA. */ |
432 | if(localex.description.fill > 0) |
438 | if(localex.description.fill > 0) |
433 | { |
439 | { |
434 | int is_peak = 0; |
440 | int is_peak = 0; |
435 | int rva_mode = -1; /* mix / album */ |
441 | int rva_mode = -1; /* mix / album */ |
Line 452... | Line 458... | ||
452 | else if(strcasecmp(localex.description.p, "replaygain_album_gain")) rva_mode = -1; |
458 | else if(strcasecmp(localex.description.p, "replaygain_album_gain")) rva_mode = -1; |
453 | } |
459 | } |
454 | if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level)) |
460 | if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level)) |
455 | { |
461 | { |
456 | /* Now we need the translated copy of the data. */ |
462 | /* Now we need the translated copy of the data. */ |
457 | store_id3_text(&localex.text, text-1, realsize-(text-realdata)+1, NOQUIET, 1); |
463 | store_id3_text(&localex.text, text-1, realsize-(text-realdata)+1, NOQUIET, 0); |
458 | if(localex.text.fill > 0) |
464 | if(localex.text.fill > 0) |
459 | { |
465 | { |
460 | if(is_peak) |
466 | if(is_peak) |
461 | { |
467 | { |
462 | fr->rva.peak[rva_mode] = (float) atof(localex.text.p); |
468 | fr->rva.peak[rva_mode] = (float) atof(localex.text.p); |
Line 477... | Line 483... | ||
477 | 483 | ||
478 | /* Make a ID3v2.3+ 4-byte ID from a ID3v2.2 3-byte ID |
484 | /* Make a ID3v2.3+ 4-byte ID from a ID3v2.2 3-byte ID |
479 | Note that not all frames survived to 2.4; the mapping goes to 2.3 . |
485 | Note that not all frames survived to 2.4; the mapping goes to 2.3 . |
480 | A notable miss is the old RVA frame, which is very unspecific anyway. |
486 | A notable miss is the old RVA frame, which is very unspecific anyway. |
481 | This function returns -1 when a not known 3 char ID was encountered, 0 otherwise. */ |
487 | This function returns -1 when a not known 3 char ID was encountered, 0 otherwise. */ |
482 | int promote_framename(mpg123_handle *fr, char *id) /* fr because of VERBOSE macros */ |
488 | static int promote_framename(mpg123_handle *fr, char *id) /* fr because of VERBOSE macros */ |
483 | { |
489 | { |
484 | size_t i; |
490 | size_t i; |
485 | char *old[] = |
491 | char *old[] = |
486 | { |
492 | { |
Line 528... | Line 534... | ||
528 | unsigned char buf[6]; |
534 | unsigned char buf[6]; |
529 | unsigned long length=0; |
535 | unsigned long length=0; |
530 | unsigned char flags = 0; |
536 | unsigned char flags = 0; |
531 | int ret = 1; |
537 | int ret = 1; |
532 | int ret2; |
538 | int ret2; |
533 | unsigned char* tagdata = NULL; |
- | |
534 | unsigned char major = first4bytes & 0xff; |
539 | unsigned char major = first4bytes & 0xff; |
535 | debug1("ID3v2: major tag version: %i", major); |
540 | debug1("ID3v2: major tag version: %i", major); |
536 | if(major == 0xff) return 0; /* Invalid... */ |
541 | if(major == 0xff) return 0; /* Invalid... */ |
537 | if((ret2 = fr->rd->read_frame_body(fr, buf, 6)) < 0) /* read more header information */ |
542 | if((ret2 = fr->rd->read_frame_body(fr, buf, 6)) < 0) /* read more header information */ |
538 | return ret2; |
543 | return ret2; |
Line 580... | Line 585... | ||
580 | } |
585 | } |
581 | debug1("ID3v2: tag data length %lu", length); |
586 | debug1("ID3v2: tag data length %lu", length); |
582 | #ifndef NO_ID3V2 |
587 | #ifndef NO_ID3V2 |
583 | if(VERBOSE2) fprintf(stderr,"Note: ID3v2.%i rev %i tag of %lu bytes\n", major, buf[0], length); |
588 | if(VERBOSE2) fprintf(stderr,"Note: ID3v2.%i rev %i tag of %lu bytes\n", major, buf[0], length); |
584 | /* skip if unknown version/scary flags, parse otherwise */ |
589 | /* skip if unknown version/scary flags, parse otherwise */ |
585 | if((flags & UNKNOWN_FLAGS) || (major > 4) || (major < 2)) |
590 | if(fr->p.flags & MPG123_SKIP_ID3V2 || ((flags & UNKNOWN_FLAGS) || (major > 4) || (major < 2))) |
- | 591 | { |
|
- | 592 | if(NOQUIET) |
|
586 | { |
593 | { |
- | 594 | if(fr->p.flags & MPG123_SKIP_ID3V2) |
|
- | 595 | { |
|
- | 596 | if(VERBOSE3) fprintf(stderr, "Note: Skipping ID3v2 tag per user request.\n"); |
|
- | 597 | } |
|
587 | /* going to skip because there are unknown flags set */ |
598 | else /* Must be because of scary Tag properties. */ |
588 | if(NOQUIET) warning2("ID3v2: Won't parse the ID3v2 tag with major version %u and flags 0x%xu - some extra code may be needed", major, flags); |
599 | warning2("ID3v2: Won't parse the ID3v2 tag with major version %u and flags 0x%xu - some extra code may be needed", major, flags); |
- | 600 | } |
|
589 | #endif |
601 | #endif |
590 | if((ret2 = fr->rd->skip_bytes(fr,length)) < 0) /* will not store data in backbuff! */ |
602 | if((ret2 = fr->rd->skip_bytes(fr,length)) < 0) /* will not store data in backbuff! */ |
591 | ret = ret2; |
603 | ret = ret2; |
592 | #ifndef NO_ID3V2 |
604 | #ifndef NO_ID3V2 |
593 | } |
605 | } |
594 | else |
606 | else |
595 | { |
607 | { |
- | 608 | unsigned char* tagdata = NULL; |
|
596 | fr->id3v2.version = major; |
609 | fr->id3v2.version = major; |
597 | /* try to interpret that beast */ |
610 | /* try to interpret that beast */ |
598 | if((tagdata = (unsigned char*) malloc(length+1)) != NULL) |
611 | if((tagdata = (unsigned char*) malloc(length+1)) != NULL) |
599 | { |
612 | { |
600 | debug("ID3v2: analysing frames..."); |
613 | debug("ID3v2: analysing frames..."); |
Line 639... | Line 652... | ||
639 | } |
652 | } |
640 | if(ret > 0) |
653 | if(ret > 0) |
641 | { |
654 | { |
642 | /* 4 or 3 bytes id */ |
655 | /* 4 or 3 bytes id */ |
643 | strncpy(id, (char*) tagdata+pos, head_part); |
656 | strncpy(id, (char*) tagdata+pos, head_part); |
- | 657 | id[head_part] = 0; /* terminate for 3 or 4 bytes */ |
|
644 | pos += head_part; |
658 | pos += head_part; |
645 | tagpos += head_part; |
659 | tagpos += head_part; |
646 | /* size as 32 bits or 28 bits */ |
660 | /* size as 32 bits or 28 bits */ |
647 | if(fr->id3v2.version == 2) threebytes_to_long(tagdata+pos, framesize); |
661 | if(fr->id3v2.version == 2) threebytes_to_long(tagdata+pos, framesize); |
648 | else |
662 | else |
Line 788... | Line 802... | ||
788 | } |
802 | } |
789 | } |
803 | } |
790 | } |
804 | } |
791 | else |
805 | else |
792 | { |
806 | { |
- | 807 | /* There are tags with zero length. Strictly not an error, then. */ |
|
793 | if(NOQUIET) error("ID3v2: Duh, not able to read ID3v2 tag data."); |
808 | if(length > 0 && NOQUIET && ret2 != MPG123_NEED_MORE) error("ID3v2: Duh, not able to read ID3v2 tag data."); |
794 | ret = ret2; |
809 | ret = ret2; |
795 | } |
810 | } |
796 | tagparse_cleanup: |
811 | tagparse_cleanup: |
797 | free(tagdata); |
812 | free(tagdata); |
798 | } |
813 | } |
Line 849... | Line 864... | ||
849 | -1: little endian |
864 | -1: little endian |
850 | 0: no BOM |
865 | 0: no BOM |
851 | 1: big endian |
866 | 1: big endian |
Line 852... | Line 867... | ||
852 | 867 | ||
853 | This modifies source and len to indicate the data _after_ the BOM(s). |
868 | This modifies source and len to indicate the data _after_ the BOM(s). |
854 | Note on nasty data: The last encountered BOM determines the endianess. |
869 | Note on nasty data: The last encountered BOM determines the endianness. |
855 | I have seen data with multiple BOMS, namely from "the" id3v2 program. |
870 | I have seen data with multiple BOMS, namely from "the" id3v2 program. |
856 | Not nice, but what should I do? |
871 | Not nice, but what should I do? |
857 | */ |
872 | */ |
858 | static int check_bom(const unsigned char** source, size_t *len) |
873 | static int check_bom(const unsigned char** source, size_t *len) |
Line 896... | Line 911... | ||
896 | int bom_endian; |
911 | int bom_endian; |
Line 897... | Line 912... | ||
897 | 912 | ||
Line 898... | Line 913... | ||
898 | debug1("convert_utf16 with length %lu", (unsigned long)l); |
913 | debug1("convert_utf16 with length %lu", (unsigned long)l); |
899 | 914 | ||
Line 900... | Line 915... | ||
900 | bom_endian = check_bom(&s, &l); |
915 | bom_endian = check_bom(&s, &l); |
901 | debug1("UTF16 endianess check: %i", bom_endian); |
916 | debug1("UTF16 endianness check: %i", bom_endian); |
902 | 917 | ||
903 | if(bom_endian == -1) /* little-endian */ |
918 | if(bom_endian == -1) /* little-endian */ |