File Coverage

src/id3.c
Criterion Covered Total %
statement 732 841 87.0
branch 408 552 73.9
condition n/a
subroutine n/a
pod n/a
total 1140 1393 81.8


line stmt bran cond sub pod time code
1             /*
2             * This program is free software; you can redistribute it and/or modify
3             * it under the terms of the GNU General Public License as published by
4             * the Free Software Foundation; either version 2 of the License, or
5             * (at your option) any later version.
6             *
7             * This program is distributed in the hope that it will be useful,
8             * but WITHOUT ANY WARRANTY; without even the implied warranty of
9             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10             * GNU General Public License for more details.
11             *
12             * You should have received a copy of the GNU General Public License
13             * along with this program; if not, write to the Free Software
14             * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15             */
16              
17             #include "id3.h"
18             #include "id3_genre.dat"
19             #include "id3_compat.c"
20             #include "id3_frametype.c"
21              
22             #define NGENRES (sizeof(genre_table) / sizeof(genre_table[0]))
23              
24             // Read an int from a variable number of bytes
25             static int
26 521           _varint(unsigned char *buf, int length)
27             {
28 521           int i, b, number = 0;
29              
30 521 50         if (buf) {
31 2589 100         for ( i = 0; i < length; i++ ) {
32 2068           b = length - 1 - i;
33 2068           number = number | (unsigned int)( buf[i] & 0xff ) << ( 8*b );
34             }
35 521           return number;
36             }
37             else {
38 0           return 0;
39             }
40             }
41              
42             int
43 106           parse_id3(PerlIO *infile, char *file, HV *info, HV *tags, off_t seek, off_t file_size)
44             {
45 106           int err = 0;
46             unsigned char *bptr;
47              
48             id3info *id3;
49 106           Newz(0, id3, sizeof(id3info), id3info);
50 106           Newz(0, id3->buf, sizeof(Buffer), Buffer);
51 106           Newz(0, id3->utf8, sizeof(Buffer), Buffer);
52              
53 106           id3->infile = infile;
54 106           id3->file = file;
55 106           id3->info = info;
56 106           id3->tags = tags;
57 106           id3->offset = seek;
58              
59 106           buffer_init(id3->buf, ID3_BLOCK_SIZE);
60              
61 106 100         if ( !seek ) {
62             // Check for ID3v1 tag first
63 100           PerlIO_seek(infile, file_size - 128, SEEK_SET);
64 100 50         if ( !_check_buf(infile, id3->buf, 128, 128) ) {
65 0           err = -1;
66 0           goto out;
67             }
68              
69 100           bptr = buffer_ptr(id3->buf);
70 100 100         if (bptr[0] == 'T' && bptr[1] == 'A' && bptr[2] == 'G') {
    50          
    50          
71 17           _id3_parse_v1(id3);
72             }
73             }
74              
75             // Check for ID3v2 tag
76 106           PerlIO_seek(infile, seek, SEEK_SET);
77 106           buffer_clear(id3->buf);
78              
79             // Read enough for header (10) + extended header size (4)
80 106 50         if ( !_check_buf(infile, id3->buf, 14, ID3_BLOCK_SIZE) ) {
81 0           err = -1;
82 0           goto out;
83             }
84              
85 106           bptr = buffer_ptr(id3->buf);
86 106 100         if (bptr[0] == 'I' && bptr[1] == 'D' && bptr[2] == '3') {
    50          
    50          
87 91           _id3_parse_v2(id3);
88             }
89              
90 15           out:
91 106           buffer_free(id3->buf);
92 106           Safefree(id3->buf);
93              
94 106 100         if (id3->utf8->alloc)
95 91           buffer_free(id3->utf8);
96 106           Safefree(id3->utf8);
97              
98 106           Safefree(id3);
99              
100 106           return err;
101             }
102              
103             int
104 17           _id3_parse_v1(id3info *id3)
105             {
106 17           SV *tmp = NULL;
107 17           uint8_t read = 0;
108             unsigned char *bptr;
109             uint8_t comment_len;
110             uint8_t genre;
111              
112 17           buffer_consume(id3->buf, 3); // TAG
113              
114 17           read = _id3_get_v1_utf8_string(id3, &tmp, 30);
115 17 50         if (tmp && SvPOK(tmp) && sv_len(tmp)) {
    50          
    100          
116             DEBUG_TRACE("ID3v1 title: %s\n", SvPVX(tmp));
117 10           my_hv_store( id3->tags, ID3_FRAME_TITLE, tmp );
118             }
119             else {
120 7 50         if (tmp) SvREFCNT_dec(tmp);
121             }
122 17 100         if (read < 30) {
123 14           buffer_consume(id3->buf, 30 - read);
124             }
125              
126 17           tmp = NULL;
127 17           read = _id3_get_v1_utf8_string(id3, &tmp, 30);
128 17 50         if (tmp && SvPOK(tmp) && sv_len(tmp)) {
    50          
    100          
129             DEBUG_TRACE("ID3v1 artist: %s\n", SvPVX(tmp));
130 10           my_hv_store( id3->tags, ID3_FRAME_ARTIST, tmp );
131 10           tmp = NULL;
132             }
133             else {
134 7 50         if (tmp) SvREFCNT_dec(tmp);
135             }
136 17 100         if (read < 30) {
137 14           buffer_consume(id3->buf, 30 - read);
138             }
139              
140 17           tmp = NULL;
141 17           read = _id3_get_v1_utf8_string(id3, &tmp, 30);
142 17 50         if (tmp && SvPOK(tmp) && sv_len(tmp)) {
    50          
    100          
143             DEBUG_TRACE("ID3v1 album: %s\n", SvPVX(tmp));
144 10           my_hv_store( id3->tags, ID3_FRAME_ALBUM, tmp );
145 10           tmp = NULL;
146             }
147             else {
148 7 50         if (tmp) SvREFCNT_dec(tmp);
149             }
150 17 100         if (read < 30) {
151 14           buffer_consume(id3->buf, 30 - read);
152             }
153              
154 17           tmp = NULL;
155 17           read = _id3_get_v1_utf8_string(id3, &tmp, 4);
156 17 50         if (tmp && SvPOK(tmp) && sv_len(tmp)) {
    50          
    100          
157             DEBUG_TRACE("ID3v1 year: %s\n", SvPVX(tmp));
158 9           my_hv_store( id3->tags, ID3_FRAME_YEAR, tmp );
159 9           tmp = NULL;
160             }
161             else {
162 8 50         if (tmp) SvREFCNT_dec(tmp);
163             }
164 17 100         if (read < 4) {
165 7           buffer_consume(id3->buf, 4 - read);
166             }
167              
168 17           bptr = buffer_ptr(id3->buf);
169 17 100         if (bptr[28] == 0 && bptr[29] != 0) {
    100          
170             // ID3v1.1 track number is present
171 5           comment_len = 28;
172 5           my_hv_store( id3->tags, ID3_FRAME_TRACK, newSVuv(bptr[29]) );
173 5           my_hv_store( id3->info, "id3_version", newSVpv( "ID3v1.1", 0 ) );
174             }
175             else {
176 12           comment_len = 30;
177 12           my_hv_store( id3->info, "id3_version", newSVpv( "ID3v1", 0 ) );
178             }
179              
180 17           tmp = NULL;
181 17           read = _id3_get_v1_utf8_string(id3, &tmp, comment_len);
182 17 50         if (tmp && SvPOK(tmp) && sv_len(tmp)) {
    50          
    100          
183 6           AV *comment_array = newAV();
184 6           av_push( comment_array, newSVpvn("XXX", 3) );
185 6           av_push( comment_array, newSVpvn("", 0) );
186 6           av_push( comment_array, tmp );
187             DEBUG_TRACE("ID3v1 comment: %s\n", SvPVX(tmp));
188 6           my_hv_store( id3->tags, ID3_FRAME_COMMENT, newRV_noinc( (SV *)comment_array ) );
189 6           tmp = NULL;
190             }
191             else {
192 11 50         if (tmp) SvREFCNT_dec(tmp);
193             }
194 17 100         if (read < 30) {
195 15           buffer_consume(id3->buf, 30 - read);
196             }
197              
198 17           genre = buffer_get_char(id3->buf);
199 17 100         if (genre < NGENRES) {
200 8           char const *genre_string = _id3_genre_index(genre);
201 8           my_hv_store( id3->tags, ID3_FRAME_GENRE, newSVpv(genre_string, 0) );
202             }
203 9 50         else if (genre < 255) {
204 0           my_hv_store( id3->tags, ID3_FRAME_GENRE, newSVpvf("Unknown/%d", genre) );
205             }
206              
207 17           return 1;
208             }
209              
210             int
211 91           _id3_parse_v2(id3info *id3)
212             {
213 91           int ret = 1;
214             unsigned char *bptr;
215              
216             // Verify we have a valid tag
217 91           bptr = buffer_ptr(id3->buf);
218 182           if ( !(
219 91 50         bptr[3] < 0xff && bptr[4] < 0xff &&
    50          
220 91 50         bptr[6] < 0x80 && bptr[7] < 0x80 && bptr[8] < 0x80 && bptr[9] < 0x80
    50          
    50          
    50          
221             ) ) {
222 0           PerlIO_printf(PerlIO_stderr(), "Invalid ID3v2 tag in %s\n", id3->file);
223 0           return 0;
224             }
225              
226 91           buffer_consume(id3->buf, 3); // ID3
227              
228 91           id3->version_major = buffer_get_char(id3->buf);
229 91           id3->version_minor = buffer_get_char(id3->buf);
230 91           id3->flags = buffer_get_char(id3->buf);
231 91           id3->size = 10 + buffer_get_syncsafe(id3->buf, 4);
232              
233 91           id3->size_remain = id3->size - 10;
234              
235 91 50         if (id3->flags & ID3_TAG_FLAG_FOOTERPRESENT) {
236 0           id3->size += 10;
237             }
238              
239             DEBUG_TRACE("Parsing ID3v2.%d.%d tag, flags %x, size %d\n", id3->version_major, id3->version_minor, id3->flags, id3->size);
240              
241 91 100         if (id3->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) {
242 13 100         if (id3->version_major < 4) {
243             // It's unclear but the v2.4.0-changes document seems to say that v2.4 should
244             // ignore the tag-level unsync flag and only worry about frame-level unsync
245              
246             // For v2.2/v2.3, unsync the entire tag. This is unfortunate due to
247             // increased memory usage but the only way to do it, as frame size values only
248             // indicate the post-unsync size, so it's not possible to unsync each frame individually
249             // tested with v2.3-unsync.mp3
250 4 50         if ( !_check_buf(id3->infile, id3->buf, id3->size, id3->size) ) {
251 0           ret = 0;
252 0           goto out;
253             }
254              
255 4           id3->size_remain = _id3_deunsync( buffer_ptr(id3->buf), id3->size );
256              
257             DEBUG_TRACE(" Un-synchronized tag, new_size %d\n", id3->size_remain);
258              
259 4           my_hv_store( id3->info, "id3_was_unsynced", newSVuv(1) );
260             }
261             else {
262             DEBUG_TRACE(" Ignoring v2.4 tag un-synchronize flag\n");
263             }
264             }
265              
266 91 100         if (id3->flags & ID3_TAG_FLAG_EXTENDEDHEADER) {
267             uint32_t ehsize;
268              
269             // If the tag is v2.2, this bit is actually the compression bit and the tag should be ignored
270 6 50         if (id3->version_major == 2) {
271 0           ret = 0;
272 0           goto out;
273             }
274              
275             // tested with v2.3-ext-header.mp3 & v2.4-ext-header.mp3
276              
277             // We don't care about the value of the extended flags or CRC, so just read the size and skip it
278              
279 6 100         if (id3->version_major == 3) {
280             // v2.3: 'Extended header size' excludes itself
281 2           ehsize = buffer_get_int(id3->buf);
282             }
283             else {
284             // v2.4: 'Extended header size' includes itself, and is a synchsafe integer of 4 bytes
285 4           ehsize = buffer_get_syncsafe(id3->buf, 4);
286             // must be at least 4 bytes - tested with v2.4-ext-header-invalid-too-short.mp3
287 4 100         if (ehsize < 4 ) {
288 1           warn("Error: Invalid ID3 extended header - too short (%s)\n", id3->file);
289 1           ret = 0;
290 1           goto out;
291             }
292 3           ehsize -= 4; // adjust to v2.3 basis
293             }
294              
295             // ehsize may be invalid, tested with v2.3-ext-header-invalid.mp3 & v2.4-ext-header-invalid.mp3
296 5 100         if (ehsize > id3->size_remain - 4) {
297 2           warn("Error: Invalid ID3 extended header size (%s)\n", id3->file);
298 2           ret = 0;
299 2           goto out;
300             }
301              
302             DEBUG_TRACE(" Skipping extended header, size %d\n", ehsize);
303              
304 3 50         if ( !_check_buf(id3->infile, id3->buf, ehsize, ID3_BLOCK_SIZE) ) {
305 0           ret = 0;
306 0           goto out;
307             }
308 3           buffer_consume(id3->buf, ehsize);
309              
310 3           id3->size_remain -= ehsize + 4;
311             }
312              
313             // Parse frames
314 1053 100         while (id3->size_remain > 0) {
315             //DEBUG_TRACE(" remain: %d\n", id3->size_remain);
316 1040 100         if ( !_id3_parse_v2_frame(id3) ) {
317 75           break;
318             }
319             }
320              
321 88 100         if (id3->version_major < 4) {
322             // map old year/date/time (TYER/TDAT/TIME) frames to TDRC
323             // tested in v2.3-xsop.mp3
324 51           _id3_convert_tdrc(id3);
325             }
326              
327             // Set id3_version info element, which contains all tag versions found
328             {
329 88           SV *version = newSVpvf( "ID3v2.%d.%d", id3->version_major, id3->version_minor );
330              
331 88 100         if ( my_hv_exists(id3->info, "id3_version") ) {
332 12           SV **entry = my_hv_fetch(id3->info, "id3_version");
333 12 50         if (entry != NULL) {
334 12           sv_catpv( version, ", " );
335 12           sv_catsv( version, *entry );
336             }
337             }
338              
339 88           my_hv_store( id3->info, "id3_version", version );
340             }
341              
342 91           out:
343 91           return ret;
344             }
345              
346             int
347 1040           _id3_parse_v2_frame(id3info *id3)
348             {
349 1040           int ret = 1;
350             char id[5];
351 1040           uint16_t flags = 0;
352 1040           uint32_t size = 0;
353 1040           uint32_t decoded_size = 0;
354 1040           uint32_t unsync_extra = 0;
355             id3_frametype const *frametype;
356 1040           Buffer *tmp_buf = 0;
357              
358             // If the frame is compressed, it will be decompressed here
359 1040           Buffer *decompressed = 0;
360              
361             // tag_data_safe flag is used if skipping artwork and artwork is not raw image data (needs unsync)
362 1040           id3->tag_data_safe = 1;
363              
364 1040 50         if ( !_check_buf(id3->infile, id3->buf, 10, ID3_BLOCK_SIZE) ) {
365 0           ret = 0;
366 0           goto out;
367             }
368              
369 1040 100         if (id3->version_major == 2) {
370             // v2.2
371             id3_compat const *compat;
372              
373             // Read 3-letter id
374 88           buffer_get(id3->buf, &id, 3);
375 88           id[3] = 0;
376              
377 88 100         if (id[0] == 0) {
378             // padding
379             DEBUG_TRACE(" Found start of padding, aborting\n");
380 4           ret = 0;
381 4           goto out;
382             }
383              
384 84           size = buffer_get_int24(id3->buf);
385              
386             DEBUG_TRACE(" %s, size %d\n", id, size);
387              
388             // map 3-char id to 4-char id
389 84           compat = _id3_compat_lookup((char *)&id, 3);
390 84 50         if (compat && compat->equiv) {
    50          
391 84           strncpy(id, compat->equiv, 4);
392 84           id[4] = 0;
393              
394             DEBUG_TRACE(" compat -> %s\n", id);
395             }
396             else {
397             // no compat mapping (obsolete), prepend 'Y' to id
398 0           id[4] = 0;
399 0           id[3] = id[2];
400 0           id[2] = id[1];
401 0           id[1] = id[0];
402 0           id[0] = 'Y';
403              
404             DEBUG_TRACE(" obsolete/unknown -> %s\n", id);
405             }
406              
407 84           id3->size_remain -= 6;
408              
409 84 50         if (size > id3->size_remain) {
410             DEBUG_TRACE(" frame size too big, aborting\n");
411 0           ret = 0;
412 0           goto out;
413             }
414             }
415             else {
416             // Read 4-letter id
417 952           buffer_get(id3->buf, &id, 4);
418 952           id[4] = 0;
419              
420 952 100         if (id[0] == 0) {
421             // padding
422             DEBUG_TRACE(" Found start of padding, aborting\n");
423 69           ret = 0;
424 69           goto out;
425             }
426              
427 883           id3->size_remain -= 4;
428              
429 883 100         if (id3->version_major == 3) {
430             // v2.3
431             id3_compat const *compat;
432              
433 392           size = buffer_get_int(id3->buf);
434 392           flags = buffer_get_short(id3->buf);
435              
436             DEBUG_TRACE(" %s, frame flags %x, size %d\n", id, flags, size);
437              
438             // map to v2.4 id
439 392 100         if (id[3] == ' ') {
440             // iTunes writes bad frame IDs such as 'TSA ', these should be run through compat
441             // as 3-char frames
442 6           compat = _id3_compat_lookup((char *)&id, 3);
443             }
444             else {
445 386           compat = _id3_compat_lookup((char *)&id, 4);
446             }
447 392 100         if (compat && compat->equiv) {
    100          
448 45           strncpy(id, compat->equiv, 4);
449 45           id[4] = 0;
450              
451             DEBUG_TRACE(" compat -> %s\n", id);
452             }
453              
454 392           id3->size_remain -= 6;
455              
456 392 50         if (size > id3->size_remain) {
457             DEBUG_TRACE(" frame size too big, aborting\n");
458 0           ret = 0;
459 0           goto out;
460             }
461              
462 392 100         if (flags & ID3_FRAME_FLAG_V23_COMPRESSION) {
463             // tested with v2.3-compressed-frame.mp3
464 1           decoded_size = buffer_get_int(id3->buf);
465 1           id3->size_remain -= 4;
466 1           size -= 4;
467             }
468              
469 392 100         if (flags & ID3_FRAME_FLAG_V23_ENCRYPTION) {
470             // tested with v2.3-encrypted-frame.mp3
471             #ifdef AUDIO_SCAN_DEBUG
472             DEBUG_TRACE(" encrypted, method %d\n", buffer_get_char(id3->buf));
473             #else
474 1           buffer_consume(id3->buf, 1);
475             #endif
476              
477 1           id3->size_remain--;
478 1           size--;
479              
480             DEBUG_TRACE(" skipping encrypted frame\n");
481 1           _id3_skip(id3, size);
482 1           id3->size_remain -= size;
483 1           goto out;
484             }
485              
486 391 100         if (flags & ID3_FRAME_FLAG_V23_GROUPINGIDENTITY) {
487             // tested with v2.3-group-id.mp3
488             #ifdef AUDIO_SCAN_DEBUG
489             DEBUG_TRACE(" group_id %d\n", buffer_get_char(id3->buf));
490             #else
491 1           buffer_consume(id3->buf, 1);
492             #endif
493              
494 1           id3->size_remain--;
495 1           size--;
496             }
497              
498             // Perform decompression if necessary after all optional extra bytes have been read
499             // XXX need test for compressed + unsync
500 391 100         if (flags & ID3_FRAME_FLAG_V23_COMPRESSION && decoded_size) {
    50          
501             unsigned long tmp_size;
502              
503 1 50         if ( !_check_buf(id3->infile, id3->buf, size, ID3_BLOCK_SIZE) ) {
504 0           ret = 0;
505 0           goto out;
506             }
507              
508             DEBUG_TRACE(" decompressing, decoded_size %d\n", decoded_size);
509              
510 1           Newz(0, decompressed, sizeof(Buffer), Buffer);
511 1           buffer_init(decompressed, decoded_size);
512              
513 1           tmp_size = decoded_size;
514 1 50         if (
515 1           uncompress(buffer_ptr(decompressed), &tmp_size, buffer_ptr(id3->buf), size) != Z_OK
516 1           ||
517 1 50         tmp_size != decoded_size
518             ) {
519             DEBUG_TRACE(" unable to decompress frame\n");
520 0           buffer_free(decompressed);
521 0           Safefree(decompressed);
522 0           decompressed = 0;
523             }
524             else {
525             // Hack buffer so it knows we've added data directly
526 1           decompressed->end = decoded_size;
527             }
528             }
529             }
530             else {
531             // v2.4
532              
533             // iTunes writes non-syncsafe length integers, check for this here
534 491 100         if ( _varint(buffer_ptr(id3->buf), 4) & 0x80 ) {
535 3           size = buffer_get_int(id3->buf);
536             DEBUG_TRACE(" found non-syncsafe iTunes size for %s, size adjusted to %d\n", id, size);
537             }
538             else {
539 488           size = buffer_get_syncsafe(id3->buf, 4);
540             }
541              
542 491           flags = buffer_get_short(id3->buf);
543              
544 491           id3->size_remain -= 6;
545              
546             DEBUG_TRACE(" %s, frame flags %x, size %d\n", id, flags, size);
547              
548 491 100         if (size > id3->size_remain) {
549             DEBUG_TRACE(" frame size too big, aborting\n");
550 2           ret = 0;
551 2           goto out;
552             }
553              
554             // iTunes writes bad frame IDs such as 'TSA ', these should be run through compat
555             // as 3-char frames
556 489 100         if (id[3] == ' ') {
557             id3_compat const *compat;
558 3           compat = _id3_compat_lookup((char *)&id, 3);
559 3 50         if (compat && compat->equiv) {
    50          
560 3           strncpy(id, compat->equiv, 4);
561 3           id[4] = 0;
562              
563             DEBUG_TRACE(" bad iTunes v2.4 tag, compat -> %s\n", id);
564             }
565             }
566              
567 489 100         if (flags & ID3_FRAME_FLAG_V24_GROUPINGIDENTITY) {
568             // tested with v2.4-group-id.mp3
569             #ifdef AUDIO_SCAN_DEBUG
570             DEBUG_TRACE(" group_id %d\n", buffer_get_char(id3->buf));
571             #else
572 1           buffer_consume(id3->buf, 1);
573             #endif
574 1           id3->size_remain--;
575 1           size--;
576             }
577              
578 489 100         if (flags & ID3_FRAME_FLAG_V24_ENCRYPTION) {
579             // tested with v2.4-encrypted-frame.mp3
580             #ifdef AUDIO_SCAN_DEBUG
581             DEBUG_TRACE(" encrypted, method %d\n", buffer_get_char(id3->buf));
582             #else
583 1           buffer_consume(id3->buf, 1);
584             #endif
585              
586 1           id3->size_remain--;
587 1           size--;
588              
589             DEBUG_TRACE(" skipping encrypted frame\n");
590 1           _id3_skip(id3, size);
591 1           id3->size_remain -= size;
592 1           goto out;
593             }
594              
595 488 100         if (flags & ID3_FRAME_FLAG_V24_DATALENGTHINDICATOR) {
596 12           decoded_size = buffer_get_syncsafe(id3->buf, 4);
597 12           id3->size_remain -= 4;
598 12           size -= 4;
599              
600             DEBUG_TRACE(" data length indicator, size %d\n", decoded_size);
601             }
602              
603 488 100         if (flags & ID3_FRAME_FLAG_V24_UNSYNCHRONISATION) {
604             // Special case, do not unsync an APIC frame if not reading artwork,
605             // FF's are not likely to appear in the part we care about anyway
606 12 100         if ( !strcmp(id, "APIC") && _env_true("AUDIO_SCAN_NO_ARTWORK") ) {
    100          
607             DEBUG_TRACE(" Would un-synchronize APIC frame, but ignoring because of AUDIO_SCAN_NO_ARTWORK\n");
608              
609             // Reset decoded_size to 0 since we aren't actually decoding.
610             // XXX this would break if we have a compressed + unsync APIC frame but not very likely in the real world
611 1           decoded_size = 0;
612              
613 1           id3->tag_data_safe = 0;
614             }
615             else {
616             // tested with v2.4-unsync.mp3
617 11 50         if ( !_check_buf(id3->infile, id3->buf, size, ID3_BLOCK_SIZE) ) {
618 0           ret = 0;
619 0           goto out;
620             }
621              
622 11           decoded_size = _id3_deunsync( buffer_ptr(id3->buf), size );
623              
624 11           unsync_extra = size - decoded_size;
625              
626             DEBUG_TRACE(" Un-synchronized frame, new_size %d\n", decoded_size);
627             }
628             }
629              
630 488 100         if (flags & ID3_FRAME_FLAG_V24_COMPRESSION) {
631             // tested with v2.4-compressed-frame.mp3
632             // XXX need test for compressed + unsync
633             unsigned long tmp_size;
634              
635 1 50         if ( !_check_buf(id3->infile, id3->buf, size, ID3_BLOCK_SIZE) ) {
636 0           ret = 0;
637 0           goto out;
638             }
639              
640             DEBUG_TRACE(" decompressing\n");
641              
642 1           Newz(0, decompressed, sizeof(Buffer), Buffer);
643 1           buffer_init(decompressed, decoded_size);
644              
645 1           tmp_size = decoded_size;
646 1 50         if (
647 1           uncompress(buffer_ptr(decompressed), &tmp_size, buffer_ptr(id3->buf), size) != Z_OK
648 1           ||
649 1 50         tmp_size != decoded_size
650             ) {
651             DEBUG_TRACE(" unable to decompress frame\n");
652 0           buffer_free(decompressed);
653 0           Safefree(decompressed);
654 0           decompressed = 0;
655             }
656             else {
657             // Hack buffer so it knows we've added data directly
658 1           decompressed->end = decoded_size;
659             }
660             }
661             }
662             }
663              
664             // Special case, completely skip XHD3 frame (mp3HD) as it will be large
665             // Also skip NCON, a large tag written by MusicMatch
666 963 100         if ( !strcmp(id, "XHD3") || !strcmp(id, "NCON") ) {
    50          
667             DEBUG_TRACE(" skipping large binary %s frame\n", id);
668 1           _id3_skip(id3, size);
669 1           id3->size_remain -= size;
670 1           goto out;
671             }
672              
673 962           frametype = _id3_frametype_lookup(id, 4);
674 962 100         if (frametype == 0) {
675 63           switch ( id[0] ) {
676 59           case 'T':
677 59           frametype = &id3_frametype_text;
678 59           break;
679              
680 0           case 'W':
681 0           frametype = &id3_frametype_url;
682 0           break;
683              
684 0           case 'X':
685             case 'Y':
686             case 'Z':
687 0           frametype = &id3_frametype_experimental;
688 0           break;
689              
690 4           default:
691 4           frametype = &id3_frametype_unknown;
692 4           break;
693             }
694             }
695              
696             #ifdef AUDIO_SCAN_DEBUG
697             {
698             int i;
699             DEBUG_TRACE(" nfields %d:", frametype->nfields);
700             for (i = 0; i < frametype->nfields; ++i) {
701             DEBUG_TRACE(" %d", frametype->fields[i]);
702             }
703             DEBUG_TRACE("\n");
704             }
705             #endif
706              
707             // If frame was compressed, temporarily set the id3 buffer to use the decompressed buffer
708 962 100         if (decompressed) {
709 2           tmp_buf = id3->buf;
710 2           id3->buf = decompressed;
711             }
712              
713 962 100         if ( !_id3_parse_v2_frame_data(id3, (char *)&id, decoded_size ? decoded_size : size, frametype) ) {
    50          
714             DEBUG_TRACE(" error parsing frame, aborting\n");
715 0           ret = 0;
716 0           goto out;
717             }
718              
719 962 100         if (id3->size_remain > size) {
720 949           id3->size_remain -= size;
721             }
722             else {
723 13           id3->size_remain = 0;
724             }
725              
726             // Consume extra bytes if we had to unsync this frame
727 962 100         if (unsync_extra) {
728             DEBUG_TRACE(" consuming extra bytes after unsync: %d\n", unsync_extra);
729 11           buffer_consume(id3->buf, unsync_extra);
730             }
731              
732 951           out:
733 1040 100         if (decompressed) {
734             // Reset id3 buffer and consume rest of compressed frame
735 2           id3->buf = tmp_buf;
736 2           buffer_consume(id3->buf, size);
737              
738 2           buffer_free(decompressed);
739 2           Safefree(decompressed);
740             }
741              
742 1040           return ret;
743             }
744              
745             int
746 962           _id3_parse_v2_frame_data(id3info *id3, char const *id, uint32_t size, id3_frametype const *frametype)
747             {
748 962           int ret = 1;
749 962           uint32_t read = 0;
750 962           int8_t encoding = -1;
751              
752 962           uint8_t buffer_art = ( !strcmp(id, "APIC") ) ? 1 : 0;
753 962 100         uint8_t skip_art = ( buffer_art && _env_true("AUDIO_SCAN_NO_ARTWORK") ) ? 1 : 0;
    100          
754              
755             // Bug 16703, a completely empty frame is against the rules, skip it
756 962 100         if (!size)
757 1           return 1;
758              
759 961 100         if (skip_art) {
760             // Only buffer enough for the APIC header fields, this is only a rough guess
761             // because the description could technically be very long
762 5 50         if ( !_check_buf(id3->infile, id3->buf, 128, ID3_BLOCK_SIZE) ) {
763 0           return 0;
764             }
765             DEBUG_TRACE(" partial read due to AUDIO_SCAN_NO_ARTWORK\n");
766             }
767             else {
768             // Use a special buffering mode for binary artwork, to avoid
769             // using 2x the memory of the APIC frame (once for buffer, once for SV)
770 956 100         if (buffer_art) {
771             // Buffer enough for encoding/MIME/picture type/description
772 23 50         if ( !_check_buf(id3->infile, id3->buf, 128, ID3_BLOCK_SIZE) ) {
773 0           return 0;
774             }
775             }
776             else {
777             // Buffer the entire frame
778 933 50         if ( !_check_buf(id3->infile, id3->buf, size, ID3_BLOCK_SIZE) ) {
779 0           return 0;
780             }
781             }
782             }
783              
784 961 100         if ( frametype->fields[0] == ID3_FIELD_TYPE_TEXTENCODING ) {
785             // many frames have an encoding byte, read it here
786 864           encoding = buffer_get_char(id3->buf);
787 864           read++;
788             DEBUG_TRACE(" encoding: %d\n", encoding);
789              
790 864 50         if (encoding < 0 || encoding > 3) {
    100          
791             DEBUG_TRACE(" invalid encoding, skipping frame\n");
792 3           goto out;
793             }
794             }
795              
796             // Special handling for TXXX/WXXX frames
797 1120 100         if ( !strcmp(id, "TXXX") || !strcmp(id, "WXXX") ) {
    100          
798             // Read key and uppercase it
799 162           SV *key = NULL;
800 162           SV *value = NULL;
801 162           AV *array = NULL;
802 162           int count = 0;
803              
804 162           read += _id3_get_utf8_string(id3, &key, size - read, encoding);
805              
806 162 50         if (key != NULL && SvPOK(key) && sv_len(key)) {
    50          
    100          
807 156           upcase(SvPVX(key));
808              
809             // Read value(s)
810 156 100         if (frametype->fields[2] == ID3_FIELD_TYPE_LATIN1) {
811             // WXXX frames have a latin1 value field regardless of encoding byte
812 14           encoding = ISO_8859_1;
813             }
814              
815             // ID3v2.4 allows multiple null-separated strings in TXXX value field.
816             // Loop mirrors the STRINGLIST handler for standard T* frames.
817 322 100         while (read < size) {
818 166 100         if (count++ == 1 && value != NULL) {
    50          
819 8           array = newAV();
820 8           av_push(array, value);
821             }
822 166           value = NULL;
823              
824 166           read += _id3_get_utf8_string(id3, &value, size - read, encoding);
825              
826 166 100         if (array != NULL && value != NULL && SvPOK(value)) {
    50          
    50          
827             // Bug 16452, do not add an empty string
828 10 100         if (sv_len(value) > 0)
829 9           av_push(array, value);
830             }
831             }
832              
833 156 100         if (array != NULL) {
834 8 50         if (av_len(array) == 0) {
835             // Multiple strings but only one non-empty: collapse to scalar
836 0           my_hv_store_ent( id3->tags, key, av_shift(array) );
837 0           SvREFCNT_dec(array);
838             }
839             else {
840 8           my_hv_store_ent( id3->tags, key, newRV_noinc( (SV *)array ) );
841             }
842 8           array = NULL;
843             }
844 148 50         else if (value != NULL && SvPOK(value)) {
    50          
845 148           my_hv_store_ent( id3->tags, key, value );
846             }
847             else {
848 0 0         if (value) SvREFCNT_dec(value);
849             }
850             }
851             else {
852             DEBUG_TRACE(" invalid/empty (T|W)XXX key, skipping frame\n");
853             }
854              
855 162 50         if (key) SvREFCNT_dec(key);
856             }
857              
858             // Special handling for TCON genre frame
859 796 100         else if ( !strcmp(id, "TCON") ) {
860 74           AV *genres = newAV();
861             char *sptr, *end, *tmp;
862              
863 149 100         while (read < size) {
864 75           SV *value = NULL;
865              
866             // v2.4 handles multiple genres using null char separators (or $00 $00 in UTF-16),
867             // this is handled by _id3_get_utf8_string
868 75           read += _id3_get_utf8_string(id3, &value, size - read, encoding);
869 75 100         if (value != NULL && SvPOK(value)) {
    50          
870 74           sptr = SvPVX(value);
871              
872             // Test if the string contains only a number,
873             // strtol will set tmp to end in this case
874 74           end = sptr + sv_len(value);
875 74           strtol(sptr, &tmp, 0);
876              
877 74 100         if ( tmp == end ) {
878             // Convert raw number to genre string
879 2           av_push( genres, newSVpv( _id3_genre_name((char *)sptr), 0 ) );
880              
881             // value as an SV won't be used, must drop refcnt
882 2           SvREFCNT_dec(value);
883             }
884 72 100         else if ( *sptr == '(' ) {
885             // Handle (26), (26)Ambient, etc, only the number portion will be read
886              
887 31 100         if (id3->version_major < 4) {
888             // v2.2/v2.3 handle multiple genres using parens for some reason, i.e. (51)(39) or (55)(Text)
889 17           char *ptr = sptr;
890 17           char *end = sptr + sv_len(value);
891              
892 114 100         while (end - ptr > 0) {
893 80 100         if ( *ptr++ == '(' ) {
894 20           char *paren = strchr(ptr, ')');
895 20 50         if (paren == NULL)
896 0           paren = end;
897              
898 20 100         if ( isdigit(*ptr) || !strncmp((char *)ptr, "RX", 2) || !strncmp((char *)ptr, "CR", 2) ) {
    100          
    100          
899 19           av_push( genres, newSVpv( _id3_genre_name((char *)ptr), 0 ) );
900             }
901             else {
902             // Handle text within parens
903 1           av_push( genres, newSVpvn(ptr, paren - ptr) );
904             }
905 20           ptr = paren;
906             }
907             }
908             }
909             else {
910             // v2.4, the (51) method is no longer valid but we will support it anyway
911 14           sptr++;
912 14 50         if ( isdigit(*sptr) || !strncmp(sptr, "RX", 2) || !strncmp(sptr, "CR", 2) ) {
    0          
    0          
913 14           av_push( genres, newSVpv( _id3_genre_name((char *)sptr), 0 ) );
914             }
915             else {
916 0           av_push( genres, newSVpv( (char *)sptr, 0 ) );
917             }
918             }
919              
920             // value as an SV won't be used, must drop refcnt
921 31           SvREFCNT_dec(value);
922             }
923             else {
924             // Support raw RX/CR value
925 41 50         if ( !strncmp(sptr, "RX", 2) || !strncmp(sptr, "CR", 2) ) {
    50          
926 0           av_push( genres, newSVpv( _id3_genre_name((char *)sptr), 0 ) );
927              
928             // value as an SV won't be used, must drop refcnt
929 0           SvREFCNT_dec(value);
930             }
931             else {
932             // Store plain text genre
933 41           av_push( genres, value );
934             }
935             }
936             }
937             }
938              
939 74 100         if (av_len(genres) > 0) {
940 6           my_hv_store( id3->tags, id, newRV_noinc( (SV *)genres ) );
941             }
942 68 100         else if (av_len(genres) == 0) {
943 65           my_hv_store( id3->tags, id, av_shift(genres) );
944 65           SvREFCNT_dec(genres);
945             }
946             else {
947 3           SvREFCNT_dec(genres);
948             }
949             }
950              
951             // 1-field frames: MCDI, PCNT, SEEK (unsupported), T* (text), W* (url), unknown
952             // and 2-field frames where the first field is encoding
953             // are mapped to plain hash entries
954 722           else if (
955 722 100         frametype->nfields == 1 ||
956 682 100         (frametype->nfields == 2 && frametype->fields[0] == ID3_FIELD_TYPE_TEXTENCODING)
    100          
957 573           ) {
958 573           int i = frametype->nfields - 1;
959 573           AV *array = NULL;
960 573           SV *value = NULL;
961 573           int count = 0;
962              
963 573           switch ( frametype->fields[i] ) {
964 28           case ID3_FIELD_TYPE_LATIN1: // W* frames
965 28           read += _id3_get_utf8_string(id3, &value, size - read, ISO_8859_1);
966 28 50         if (value != NULL && SvPOK(value))
    50          
967 28           my_hv_store( id3->tags, id, value );
968 28           break;
969              
970 533           case ID3_FIELD_TYPE_STRINGLIST: // T* frames
971             // XXX technically in v2.2/v2.3 we should ignore multiple strings separated by nulls, but
972             // allowing it is fine I think
973 1080 100         while (read < size) {
974 547 100         if (count++ == 1 && value != NULL) {
    50          
975             // we're reading the second string in the list, move first value to new array
976 4           array = newAV();
977 4           av_push(array, value);
978             }
979 547           value = NULL;
980              
981 547           read += _id3_get_utf8_string(id3, &value, size - read, encoding);
982              
983 547 100         if (array != NULL && value != NULL && SvPOK(value)) {
    50          
    50          
984             // second+ string, add to array
985             // Bug 16452, do not add a null string
986 34 100         if (sv_len(value) > 0)
987 4           av_push(array, value);
988             }
989             }
990              
991 533 100         if (array != NULL) {
992 4 100         if (av_len(array) == 0) {
993             // Handle the case where we have multiple empty strings leaving an array of 1
994 2           my_hv_store( id3->tags, id, av_shift(array) );
995 2           SvREFCNT_dec(array);
996             }
997             else {
998 2           my_hv_store( id3->tags, id, newRV_noinc( (SV *)array ) );
999             }
1000             }
1001 529 100         else if (value != NULL && SvPOK(value)) {
    50          
1002 506           my_hv_store( id3->tags, id, value );
1003             }
1004 533           break;
1005              
1006 0           case ID3_FIELD_TYPE_INT32: // SEEK (unsupported, XXX need test)
1007 0           my_hv_store( id3->tags, id, newSViv( buffer_get_int(id3->buf) ) );
1008 0           read += 4;
1009 0           break;
1010              
1011 7           case ID3_FIELD_TYPE_INT32PLUS: // PCNT
1012 7           my_hv_store( id3->tags, id, newSViv( _varint( buffer_ptr(id3->buf), size - read ) ) );
1013 7           buffer_consume(id3->buf, size - read);
1014 7           read = size;
1015 7           break;
1016              
1017 5           case ID3_FIELD_TYPE_BINARYDATA: // unknown/obsolete frames
1018             // Special handling for RVA(D), tested in v2.2-itunes81.mp3, v2.3-itunes81.mp3
1019 5 100         if ( !strcmp(id, "RVAD") ) {
1020 3           read += _id3_parse_rvad(id3, id, size - read);
1021             }
1022              
1023             // Special handling for RGAD (non-standard replaygain frame), tested in v2.3-rgad.mp3
1024             // Based on some code found at http://getid3.sourceforge.net/source/module.tag.id3v2.phps
1025 2 100         else if ( !strcmp(id, "RGAD") ) {
1026 1           read += _id3_parse_rgad(id3);
1027             }
1028              
1029             // Other unknown binary data
1030             else {
1031             // Y* obsolete frames
1032 1           my_hv_store( id3->tags, id, newSVpvn( buffer_ptr(id3->buf), size - read ) );
1033 1           buffer_consume(id3->buf, size - read);
1034 1           read = size;
1035             }
1036 5           break;
1037              
1038 0           default:
1039             // XXX
1040 0           warn(" !!! unhandled field type %d\n", frametype->fields[i]);
1041 0           buffer_consume(id3->buf, size - read);
1042 0           read += size - read;
1043 0           break;
1044             }
1045             }
1046              
1047             // 2+ field frames are mapped to arrayrefs:
1048             // The following frames have tests:
1049             // ETCO, UFID, USLT, SYLT, COMM, RVA2, APIC, GEOB, POPM, LINK, PRIV
1050             //
1051             // XXX The following frames need tests:
1052             // MLLT, SYTC, EQU2, RVRB, AENC, POSS, USER, OWNE,
1053             // COMR, ENCR, GRID, SIGN, ASPI, LINK (v2.4)
1054             else {
1055 149           int i = 0;
1056 149           AV *framedata = newAV();
1057              
1058             // If we read an initial encoding byte, start at field 2
1059 149 100         if (encoding >= 0)
1060 92           i = 1;
1061              
1062 591 100         for (; i < frametype->nfields; i++) {
1063 442           SV *value = NULL;
1064              
1065 442           switch ( frametype->fields[i] ) {
1066 87           case ID3_FIELD_TYPE_LATIN1:
1067             // Special case, fix v2.2 PIC frame fields as they don't match APIC
1068             // This is a rather hackish place to put this, but there's not really any other place
1069 87 100         if ( id3->version_major == 2 && !strcmp(id, "APIC") ) {
    100          
1070 3           av_push( framedata, newSVpvn( buffer_ptr(id3->buf), 3 ) );
1071 3           buffer_consume(id3->buf, 3);
1072 3           read += 3;
1073             DEBUG_TRACE(" PIC image format, read %d\n", read);
1074             }
1075             else {
1076 84           read += _id3_get_utf8_string(id3, &value, size - read, ISO_8859_1);
1077 84 50         if (value != NULL && SvPOK(value))
    50          
1078 84           av_push( framedata, value );
1079             }
1080 87           break;
1081              
1082             // ID3_FIELD_TYPE_LATIN1FULL - not used
1083              
1084 2           case ID3_FIELD_TYPE_LATIN1LIST: // LINK
1085 3 100         while (read < size) {
1086 1           read += _id3_get_utf8_string(id3, &value, size - read, ISO_8859_1);
1087 1 50         if (value != NULL && SvPOK(value))
    50          
1088 1           av_push( framedata, value );
1089 1           value = NULL;
1090             DEBUG_TRACE(" latin1list, read %d\n", read);
1091             }
1092 2           break;
1093              
1094 95           case ID3_FIELD_TYPE_STRING:
1095 95           read += _id3_get_utf8_string(id3, &value, size - read, encoding);
1096 95 50         if (value != NULL && SvPOK(value)) {
    50          
1097 95           av_push( framedata, value );
1098             DEBUG_TRACE(" string, read %d: %s\n", read, SvPVX(value));
1099             }
1100             else {
1101 0           av_push( framedata, &PL_sv_undef );
1102 0 0         if (value) SvREFCNT_dec(value);
1103             }
1104 95           break;
1105              
1106 60           case ID3_FIELD_TYPE_STRINGFULL: // USLT, COMM, read entire string until end of frame
1107             {
1108 60           SV *tmp = newSVpvn( "", 0 );
1109 125 100         while (read < size) {
1110 65           read += _id3_get_utf8_string(id3, &value, size - read, encoding);
1111 65 50         if (value != NULL && SvPOK(value)) {
    50          
1112 65           sv_catsv( tmp, value );
1113 65           SvREFCNT_dec(value);
1114             }
1115 65           value = NULL;
1116             }
1117 60           av_push( framedata, tmp );
1118             DEBUG_TRACE(" stringfull, read %d: %s\n", read, SvPVX(tmp));
1119 60           break;
1120             }
1121              
1122             // ID3_FIELD_TYPE_STRINGLIST - only used for text frames, handled above
1123              
1124 61           case ID3_FIELD_TYPE_LANGUAGE: // USLT, SYLT, COMM, USER, 3-byte language code
1125 61 50         if (size - read >= 3) {
1126 61           av_push( framedata, newSVpvn( buffer_ptr(id3->buf), 3 ) );
1127 61           buffer_consume(id3->buf, 3);
1128 61           read += 3;
1129             DEBUG_TRACE(" language, read %d\n", read);
1130             }
1131 61           break;
1132              
1133 2           case ID3_FIELD_TYPE_FRAMEID: // LINK, 3-byte frame id (v2.3, must be a bug in the spec?),
1134             // 4-byte frame id (v2.4) XXX need test
1135             {
1136 2 50         uint8_t len = (id3->version_major == 3) ? 3 : 4;
1137 2 50         if (size - read >= len) {
1138 2           av_push( framedata, newSVpvn( buffer_ptr(id3->buf), len ) );
1139 2           buffer_consume(id3->buf, len);
1140 2           read += len;
1141             DEBUG_TRACE(" frameid, read %d\n", read);
1142             }
1143 2           break;
1144             }
1145              
1146 0           case ID3_FIELD_TYPE_DATE: // OWNE, COMR, XXX need test, YYYYMMDD
1147 0 0         if (size - read >= 8) {
1148 0           av_push( framedata, newSVpvn( buffer_ptr(id3->buf), 8 ) );
1149 0           buffer_consume(id3->buf, 8);
1150 0           read += 8;
1151             DEBUG_TRACE(" date, read %d\n", read);
1152             }
1153 0           break;
1154              
1155 46           case ID3_FIELD_TYPE_INT8: // ETCO, MLLT, SYTC, SYLT, EQU2, RVRB, APIC,
1156             // POPM, RBUF, POSS, COMR, ENCR, GRID, SIGN, ASPI
1157 46 50         if (size - read >= 1) {
1158 46           av_push( framedata, newSViv( buffer_get_char(id3->buf) ) );
1159 46           read += 1;
1160             DEBUG_TRACE(" int8, read %d\n", read);
1161             }
1162 46           break;
1163              
1164 2           case ID3_FIELD_TYPE_INT16: // MLLT, RVRB, AENC, ASPI
1165 2 50         if (size - read >= 2) {
1166 0           av_push( framedata, newSViv( buffer_get_short(id3->buf) ) );
1167 0           read += 2;
1168             DEBUG_TRACE(" int16, read %d\n", read);
1169             }
1170 2           break;
1171              
1172 0           case ID3_FIELD_TYPE_INT24: // MLLT, RBUF
1173 0 0         if (size - read >= 3) {
1174 0           av_push( framedata, newSViv( buffer_get_int24(id3->buf) ) );
1175 0           read += 3;
1176             DEBUG_TRACE(" int24, read %d\n", read);
1177             }
1178 0           break;
1179              
1180 0           case ID3_FIELD_TYPE_INT32: // RBUF, SEEK, ASPI
1181 0 0         if (size - read >= 4) {
1182 0           av_push( framedata, newSViv( buffer_get_int(id3->buf) ) );
1183 0           read += 4;
1184             DEBUG_TRACE(" int32, read %d\n", read);
1185             }
1186 0           break;
1187              
1188 15           case ID3_FIELD_TYPE_INT32PLUS: // POPM
1189 15 50         if (size - read >= 4) {
1190 15           av_push( framedata, newSViv( _varint( buffer_ptr(id3->buf), size - read ) ) );
1191 15           buffer_consume(id3->buf, size - read);
1192 15           read = size;
1193             DEBUG_TRACE(" int32plus, read %d\n", read);
1194             }
1195 15           break;
1196              
1197 72           case ID3_FIELD_TYPE_BINARYDATA: // ETCO, MLLT, SYTC, SYLT, RVA2, EQU2, APIC,
1198             // GEOB, AENC, POSS, COMR, ENCR, GRID, PRIV, SIGN, ASPI
1199             // Special handling for APIC tags when in skip_art mode
1200 72 100         if (skip_art) {
1201 5           av_push( framedata, newSVuv(size - read) );
1202              
1203             // I don't think it's possible to obtain an APIC offset when a tag has been unsync'ed,
1204             // so we can't support skip_art mode in this case. See v2.3-unsync-apic-bad-offset.mp3
1205 5 100         if (id3->flags & ID3_TAG_FLAG_UNSYNCHRONISATION && id3->version_major < 4) {
    100          
1206             DEBUG_TRACE(" cannot obtain APIC offset due to v2.3 unsync tag\n");
1207             }
1208             else {
1209             // Record offset of APIC image data too, unless the data needs to be unsynchronized or is empty
1210 4 100         if (id3->tag_data_safe && (size - read) > 0)
    50          
1211 3           av_push( framedata, newSVuv(id3->offset + (id3->size - id3->size_remain) + read) );
1212             }
1213              
1214 5           _id3_skip(id3, size - read);
1215 5           read = size;
1216             }
1217              
1218             // Special buffering mode for APIC data, avoids a large buffer allocation
1219 67 100         else if (buffer_art) {
1220 23           uint32_t remain = size - read;
1221             uint32_t chunk_size;
1222 23           SV *artwork = newSVpv("", 0);
1223              
1224 271 100         while (read < size) {
1225 248 50         if ( !_check_buf(id3->infile, id3->buf, 1, ID3_BLOCK_SIZE) ) {
1226 0           return 0;
1227             }
1228              
1229 248 100         chunk_size = remain < buffer_len(id3->buf) ? remain : buffer_len(id3->buf);
1230              
1231 248           read += chunk_size;
1232 248           remain -= chunk_size;
1233              
1234 248           sv_catpvn( artwork, buffer_ptr(id3->buf), chunk_size );
1235 248           buffer_consume(id3->buf, chunk_size);
1236              
1237             DEBUG_TRACE(" buffered %d bytes of APIC data (remaining %d)\n", chunk_size, remain);
1238             }
1239              
1240 23           av_push( framedata, artwork );
1241             }
1242              
1243             // Special handling for RVA2 tags
1244 44 100         else if ( !strcmp(id, "RVA2") ) {
1245 10           read += _id3_parse_rva2(id3, size, framedata);
1246             }
1247              
1248             // Special handling for SYLT tags
1249 34 100         else if ( !strcmp(id, "SYLT") ) {
1250 1           read += _id3_parse_sylt(id3, encoding, size - read, framedata);
1251             }
1252              
1253             // Special handling for ETCO tags
1254 33 100         else if ( !strcmp(id, "ETCO") ) {
1255 1           read += _id3_parse_etco(id3, size - read, framedata);
1256             }
1257              
1258             // All other binary frames, copy as-is
1259             else {
1260 32 100         if (size - read > 1) {
1261 31           av_push( framedata, newSVpvn( buffer_ptr(id3->buf), size - read ) );
1262 31           buffer_consume(id3->buf, size - read);
1263 31           read = size;
1264             DEBUG_TRACE(" binarydata, read %d\n", read);
1265             }
1266             }
1267 72           break;
1268              
1269 0           default:
1270 0           break;
1271             }
1272             }
1273              
1274 149           _id3_set_array_tag(id3, id, framedata);
1275             }
1276              
1277 961           out:
1278 961 100         if (read < size) {
1279 8           buffer_consume(id3->buf, size - read);
1280             DEBUG_TRACE(" !!! consuming extra bytes in frame: %d\n", size - read);
1281             }
1282              
1283 961           return ret;
1284             }
1285              
1286             void
1287 149           _id3_set_array_tag(id3info *id3, char const *id, AV *framedata)
1288             {
1289 149 50         if ( av_len(framedata) != -1 ) {
1290 149 100         if ( my_hv_exists( id3->tags, id ) ) {
1291             // If tag already exists, move it to an arrayref
1292 37           SV **entry = my_hv_fetch( id3->tags, id );
1293 37 50         if (entry != NULL) {
1294 37 50         if ( SvTYPE( SvRV(*entry) ) == SVt_PV ) {
1295             // A normal string entry, convert to array
1296 0           AV *ref = newAV();
1297              
1298             // XXX need test, this may be illegal because you can't have multiple duplicate frames?
1299             DEBUG_TRACE(" !!! converting normal string tag to array\n");
1300              
1301 0           av_push( ref, *entry );
1302 0           av_push( ref, newRV_noinc( (SV *)framedata ) );
1303 0           my_hv_store( id3->tags, id, newRV_noinc( (SV *)ref ) );
1304             }
1305 37 50         else if ( SvTYPE( SvRV(*entry) ) == SVt_PVAV ) {
1306             // If type of first item is array, add new item to entry
1307 37           SV **first = av_fetch( (AV *)SvRV(*entry), 0, 0 );
1308 37 50         if ( first == NULL || ( SvROK(*first) && SvTYPE( SvRV(*first) ) == SVt_PVAV ) ) {
    100          
    50          
1309 15           av_push( (AV *)SvRV(*entry), newRV_noinc( (SV *)framedata ) );
1310             }
1311             else {
1312 22           AV *ref = newAV();
1313 22           av_push( ref, SvREFCNT_inc(*entry) );
1314 22           av_push( ref, newRV_noinc( (SV *)framedata) );
1315 22           my_hv_store( id3->tags, id, newRV_noinc( (SV *)ref ) );
1316             }
1317             }
1318             }
1319             }
1320             else {
1321 112           my_hv_store( id3->tags, id, newRV_noinc( (SV *)framedata ) );
1322             }
1323             }
1324             else {
1325 0           SvREFCNT_dec(framedata);
1326             }
1327 149           }
1328              
1329             // Read a latin1 or UTF-8 string from an ID3v1 tag
1330             // This function handles trimming spaces off the end
1331             uint32_t
1332 85           _id3_get_v1_utf8_string(id3info *id3, SV **string, uint32_t len)
1333             {
1334 85           uint32_t read = 0;
1335             char *ptr;
1336             char *str;
1337              
1338 85           read = _id3_get_utf8_string(id3, string, len, ISO_8859_1);
1339              
1340 85 50         if (read) {
1341             // Trim spaces from end
1342 85 50         if (*string != NULL) {
1343 85           str = SvPVX(*string);
1344 85           ptr = str + sv_len(*string);
1345              
1346 329 100         while (ptr > str && ptr[-1] == ' ')
    100          
1347 244           --ptr;
1348              
1349 85           *ptr = 0;
1350 85           SvCUR_set(*string, ptr - str);
1351             }
1352             }
1353              
1354 85           return read;
1355             }
1356              
1357             uint32_t
1358 1324           _id3_get_utf8_string(id3info *id3, SV **string, uint32_t len, uint8_t encoding)
1359             {
1360 1324           uint8_t byteorder = UTF16_BYTEORDER_ANY;
1361 1324           uint32_t read = 0;
1362             unsigned char *bptr;
1363              
1364             // Init scratch buffer if necessary
1365 1324 100         if ( !id3->utf8->alloc ) {
1366             // Use a larger initial buffer if reading ISO-8859-1 to avoid
1367             // always having to allocate a second time
1368 91 100         buffer_init( id3->utf8, encoding == ISO_8859_1 ? len * 2 : len );
1369             }
1370             else {
1371             // Reset scratch buffer
1372 1233           buffer_clear(id3->utf8);
1373             }
1374              
1375 1324 50         if ( *string != NULL ) {
1376 0           warn(" !!! string SV is not null: %s\n", SvPVX(*string));
1377             }
1378              
1379 1324           switch (encoding) {
1380 820           case ISO_8859_1:
1381 820           read += buffer_get_latin1_as_utf8(id3->buf, id3->utf8, len);
1382 820           break;
1383              
1384 13           case UTF_16BE:
1385 13           byteorder = UTF16_BYTEORDER_BE;
1386              
1387 157           case UTF_16:
1388 157           bptr = buffer_ptr(id3->buf);
1389              
1390 157           switch ( (bptr[0] << 8) | bptr[1] ) {
1391 0           case 0xfeff:
1392             DEBUG_TRACE(" UTF-16 BOM is big-endian\n");
1393 0           byteorder = UTF16_BYTEORDER_BE;
1394 0           buffer_consume(id3->buf, 2);
1395 0           read += 2;
1396 0           break;
1397              
1398 134           case 0xfffe:
1399             DEBUG_TRACE(" UTF-16 BOM is little-endian\n");
1400 134           byteorder = UTF16_BYTEORDER_LE;
1401 134           buffer_consume(id3->buf, 2);
1402 134           read += 2;
1403 134           break;
1404             }
1405              
1406             /* Bug 14728
1407             If there is no BOM, assume LE, this is what appears in the wild -andy
1408             */
1409 157 100         if (byteorder == UTF16_BYTEORDER_ANY) {
1410             DEBUG_TRACE(" UTF-16 byte order defaulting to little-endian, no BOM\n");
1411 10           byteorder = UTF16_BYTEORDER_LE;
1412             }
1413              
1414 157           read += buffer_get_utf16_as_utf8(id3->buf, id3->utf8, len - read, byteorder);
1415 157           break;
1416              
1417 347           case UTF_8:
1418 347           read += buffer_get_utf8(id3->buf, id3->utf8, len);
1419 347           break;
1420              
1421 0           default:
1422 0           break;
1423             }
1424              
1425 1324 50         if (read) {
1426 1324 100         if ( buffer_len(id3->utf8) ) {
1427 1320           *string = newSVpv( buffer_ptr(id3->utf8), 0 );
1428 1320           sv_utf8_decode(*string);
1429             DEBUG_TRACE(" read utf8 string of %d bytes: %s\n", buffer_len(id3->utf8), SvPVX(*string));
1430             }
1431             else {
1432             DEBUG_TRACE(" empty string\n");
1433             }
1434             }
1435              
1436 1324           return read;
1437             }
1438              
1439             uint32_t
1440 3           _id3_parse_rvad(id3info *id3, char const *id, uint32_t size)
1441             {
1442 3           unsigned char *rva = buffer_ptr(id3->buf);
1443 3 50         int sign_r = rva[0] & 0x01 ? 1 : -1;
1444 3 50         int sign_l = rva[0] & 0x02 ? 1 : -1;
1445 3           int bytes = rva[1] / 8;
1446             float vol[2];
1447             float peak[2];
1448             int i;
1449 3           AV *framedata = newAV();
1450              
1451             // Sanity check, first byte must be either 0 or 1, second byte > 0
1452 3 100         if (rva[0] & 0xFE || rva[1] == 0) {
    50          
1453 1           return 0;
1454             }
1455              
1456             // Calculated size must match the actual size
1457 2 50         if (size != 2 + (bytes * 4)) {
1458 0           return 0;
1459             }
1460              
1461 2           rva += 2;
1462              
1463 2           vol[0] = _varint( rva, bytes ) * sign_r / 256.;
1464 2           vol[1] = _varint( rva + bytes, bytes ) * sign_l / 256.;
1465              
1466 2           peak[0] = _varint( rva + (bytes * 2), bytes );
1467 2           peak[1] = _varint( rva + (bytes * 3), bytes );
1468              
1469             // iTunes uses a range of -255 to 255
1470             // to be -100% (silent) to 100% (+6dB)
1471 6 100         for (i = 0; i < 2; i++) {
1472 4 50         if ( vol[i] == -255 ) {
1473 0           vol[i] = -96.0;
1474             }
1475             else {
1476 4           vol[i] = 20.0 * log( ( vol[i] + 255 ) / 255 ) / log(10);
1477             }
1478              
1479 4           av_push( framedata, newSVpvf( "%f dB", vol[i] ) );
1480 4           av_push( framedata, newSVpvf( "%f", peak[i] ) );
1481             }
1482              
1483 2           my_hv_store( id3->tags, id, newRV_noinc( (SV *)framedata ) );
1484              
1485 2           buffer_consume(id3->buf, 2 + (bytes * 4));
1486              
1487 2           return 2 + (bytes * 4);
1488             }
1489              
1490             uint32_t
1491 1           _id3_parse_rgad(id3info *id3)
1492             {
1493 1           float radio = 0.0;
1494 1           float audiophile = 0.0;
1495 1           uint8_t sign = 0;
1496 1           HV *framedata = newHV();
1497 1           uint32_t read = 0;
1498              
1499             // Peak (32-bit float)
1500 1           my_hv_store( framedata, "peak", newSVpvf( "%f", (float)buffer_get_float32(id3->buf) ) );
1501 1           read += 4;
1502              
1503             // Radio (16 bits)
1504              
1505             // Radio Name code (3 bits, should always be 1)
1506 1           buffer_get_bits(id3->buf, 3);
1507              
1508 1           my_hv_store( framedata, "track_originator", newSVuv( buffer_get_bits(id3->buf, 3) ) );
1509              
1510             // Sign bit (1 bit)
1511 1           sign = buffer_get_bits(id3->buf, 1);
1512              
1513             // Gain value (9 bits)
1514 1           radio = (float)buffer_get_bits(id3->buf, 9);
1515 1           radio /= 10.0;
1516 1 50         if (sign == 1) radio *= -1.0;
1517 1           my_hv_store( framedata, "track_gain", newSVpvf( "%f dB", radio ) );
1518              
1519 1           read += 2;
1520              
1521             // Audiophile (16 bits)
1522              
1523             // Audiophile Name code (3 bits, should always be 2)
1524 1           buffer_get_bits(id3->buf, 3);
1525              
1526             // Audiophile Originator code (3 bits)
1527 1           my_hv_store( framedata, "album_originator", newSVuv( buffer_get_bits(id3->buf, 3) ) );
1528              
1529             // Sign bit (1 bit)
1530 1           sign = buffer_get_bits(id3->buf, 1);
1531              
1532             // Gain value (9 bits)
1533 1           audiophile = (float)buffer_get_bits(id3->buf, 9);
1534 1           audiophile /= 10.0;
1535 1 50         if (sign == 1) audiophile *= -1.0;
1536 1           my_hv_store( framedata, "album_gain", newSVpvf( "%f dB", audiophile ) );
1537              
1538 1           read += 2;
1539              
1540 1           my_hv_store( id3->tags, "RGAD", newRV_noinc( (SV *)framedata ) );
1541              
1542 1           return read;
1543             }
1544              
1545             uint32_t
1546 10           _id3_parse_rva2(id3info *id3, uint32_t len, AV *framedata)
1547             {
1548 10           float adj = 0.0;
1549             int adj_fp;
1550             uint8_t peakbits;
1551 10           float peak = 0.0;
1552 10           uint32_t read = 0;
1553             unsigned char *bptr;
1554              
1555             // Channel
1556 10           av_push( framedata, newSViv( buffer_get_char(id3->buf) ) );
1557              
1558             // Adjustment
1559 10           bptr = buffer_ptr(id3->buf);
1560 10           adj_fp = *(signed char *)(bptr) << 8;
1561 10           adj_fp |= *(unsigned char *)(bptr+1);
1562 10           adj = adj_fp / 512.0;
1563 10           av_push( framedata, newSVpvf( "%f dB", adj ) );
1564 10           buffer_consume(id3->buf, 2);
1565              
1566             // Peak
1567             // Based on code from mp3gain
1568 10           peakbits = buffer_get_char(id3->buf);
1569              
1570 10           read += 4;
1571              
1572 10 50         if (4 + (peakbits + 7) / 8 <= len) {
1573             DEBUG_TRACE(" peakbits: %d\n", peakbits);
1574 10 100         if (peakbits > 0) {
1575 2           peak += (float)buffer_get_char(id3->buf);
1576 2           read++;
1577             }
1578 10 100         if (peakbits > 8) {
1579 2           peak += (float)buffer_get_char(id3->buf) / 256.0;
1580 2           read++;
1581             }
1582 10 50         if (peakbits > 16) {
1583 0           peak += (float)buffer_get_char(id3->buf) / 65536.0;
1584 0           read++;
1585             }
1586              
1587 10 100         if (peakbits > 0)
1588 2           peak /= (float)(1 << ((peakbits - 1) & 7));
1589             }
1590              
1591 10           av_push( framedata, newSVpvf( "%f dB", peak ) );
1592              
1593 10           return read;
1594             }
1595              
1596             uint32_t
1597 1           _id3_parse_sylt(id3info *id3, uint8_t encoding, uint32_t len, AV *framedata)
1598             {
1599 1           uint32_t read = 0;
1600 1           AV *content = newAV();
1601             unsigned char *bptr;
1602              
1603 17 100         while (read < len) {
1604 16           SV *value = NULL;
1605 16           HV *lyric = newHV();
1606              
1607 16           read += _id3_get_utf8_string(id3, &value, len - read, encoding);
1608 16 50         if (value != NULL && SvPOK(value) && sv_len(value)) {
    50          
    50          
1609 16           my_hv_store( lyric, "text", value );
1610             }
1611             else {
1612 0           my_hv_store( lyric, "text", &PL_sv_undef );
1613 0 0         if (value) SvREFCNT(value);
1614             }
1615              
1616 16           my_hv_store( lyric, "timestamp", newSVuv( buffer_get_int(id3->buf) ) );
1617 16           read += 4;
1618              
1619             // A $0A newline byte may follow, for some odd reason
1620 16           bptr = buffer_ptr(id3->buf);
1621 16 50         if ( len - read > 0 && bptr[0] == 0x0a ) {
    50          
1622 16           buffer_consume(id3->buf, 1);
1623 16           read++;
1624             }
1625              
1626 16           av_push( content, newRV_noinc( (SV *)lyric ) );
1627             }
1628              
1629 1           av_push( framedata, newRV_noinc( (SV *)content ) );
1630              
1631 1           return read;
1632             }
1633              
1634             uint32_t
1635 1           _id3_parse_etco(id3info *id3, uint32_t len, AV *framedata)
1636             {
1637 1           uint32_t read = 0;
1638 1           AV *content = newAV();
1639              
1640 2 100         while (read < len) {
1641 1           HV *event = newHV();
1642              
1643 1           my_hv_store( event, "type", newSVuv( buffer_get_char(id3->buf) ) );
1644 1           my_hv_store( event, "timestamp", newSVuv( buffer_get_int(id3->buf) ) );
1645 1           read += 5;
1646              
1647 1           av_push( content, newRV_noinc( (SV *)event ) );
1648             }
1649              
1650 1           av_push( framedata, newRV_noinc( (SV *)content ) );
1651              
1652 1           return read;
1653             }
1654              
1655             void
1656 51           _id3_convert_tdrc(id3info *id3)
1657             {
1658 51           char timestamp[17] = { 0 };
1659              
1660 51 100         if ( my_hv_exists(id3->tags, "TYER") ) {
1661 35           SV *tyer = my_hv_delete(id3->tags, "TYER");
1662 35 50         if (SvPOK(tyer) && sv_len(tyer) == 4) {
    50          
1663 35           char *ptr = SvPVX(tyer);
1664 35           timestamp[0] = ptr[0];
1665 35           timestamp[1] = ptr[1];
1666 35           timestamp[2] = ptr[2];
1667 35           timestamp[3] = ptr[3];
1668             DEBUG_TRACE(" Converted TYER (%s) to TDRC (%s)\n", SvPVX(tyer), timestamp);
1669             }
1670             }
1671              
1672 51 100         if ( my_hv_exists(id3->tags, "TDAT") ) {
1673 4           SV *tdat = my_hv_delete(id3->tags, "TDAT");
1674 4 50         if (SvPOK(tdat) && sv_len(tdat) == 4) {
    50          
1675 4           char *ptr = SvPVX(tdat);
1676 4           timestamp[4] = '-';
1677 4           timestamp[5] = ptr[2];
1678 4           timestamp[6] = ptr[3];
1679 4           timestamp[7] = '-';
1680 4           timestamp[8] = ptr[0];
1681 4           timestamp[9] = ptr[1];
1682             DEBUG_TRACE(" Converted TDAT (%s) to TDRC (%s)\n", SvPVX(tdat), timestamp);
1683             }
1684             }
1685              
1686 51 100         if ( my_hv_exists(id3->tags, "TIME") ) {
1687 3           SV *time = my_hv_delete(id3->tags, "TIME");
1688 3 50         if (SvPOK(time) && sv_len(time) == 4) {
    50          
1689 3           char *ptr = SvPVX(time);
1690 3           timestamp[10] = 'T';
1691 3           timestamp[11] = ptr[0];
1692 3           timestamp[12] = ptr[1];
1693 3           timestamp[13] = ':';
1694 3           timestamp[14] = ptr[2];
1695 3           timestamp[15] = ptr[3];
1696             DEBUG_TRACE(" Converted TIME (%s) to TDRC (%s)\n", SvPVX(time), timestamp);
1697             }
1698             }
1699              
1700 51 100         if (timestamp[0]) {
1701 35           my_hv_store( id3->tags, "TDRC", newSVpv(timestamp, 0) );
1702             }
1703 51           }
1704              
1705             // deunsync in-place, from libid3tag
1706             uint32_t
1707 15           _id3_deunsync(unsigned char *data, uint32_t length)
1708             {
1709             unsigned char *old;
1710 15           unsigned char *end = data + length;
1711             unsigned char *new;
1712              
1713 15 50         if (length == 0)
1714 0           return 0;
1715              
1716 140703 100         for (old = new = data; old < end - 1; ++old) {
1717 140688           *new++ = *old;
1718 140688 100         if (old[0] == 0xff && old[1] == 0x00)
    100          
1719 1389           ++old;
1720             }
1721              
1722 15           *new++ = *old;
1723              
1724 15           return new - data;
1725             }
1726              
1727             void
1728 8           _id3_skip(id3info *id3, uint32_t size)
1729             {
1730 8 100         if ( buffer_len(id3->buf) >= size ) {
1731 6           buffer_consume(id3->buf, size);
1732              
1733             DEBUG_TRACE(" skipped buffer data size %d\n", size);
1734             }
1735             else {
1736 2           PerlIO_seek(id3->infile, size - buffer_len(id3->buf), SEEK_CUR);
1737 2           buffer_clear(id3->buf);
1738              
1739             DEBUG_TRACE(" seeked past %d bytes to %d\n", size, (int)PerlIO_tell(id3->infile));
1740             }
1741 8           }
1742              
1743             // return an ID3v1 genre string indexed by number
1744             char const *
1745 17           _id3_genre_index(unsigned int index)
1746             {
1747 17 50         return (index < NGENRES) ? genre_table[index] : 0;
1748             }
1749              
1750             // translate an ID3v2 genre number/keyword to its full name
1751             char const *
1752 35           _id3_genre_name(char const *string)
1753             {
1754             static char const genre_remix[] = { 'R', 'e', 'm', 'i', 'x', 0 };
1755             static char const genre_cover[] = { 'C', 'o', 'v', 'e', 'r', 0 };
1756             unsigned long number;
1757              
1758 35 50         if (string == 0 || *string == 0)
    50          
1759 0           return 0;
1760              
1761 35 100         if (string[0] == 'R' && string[1] == 'X')
    50          
1762 1           return genre_remix;
1763 34 100         if (string[0] == 'C' && string[1] == 'R')
    50          
1764 1           return genre_cover;
1765              
1766 33           number = strtol(string, NULL, 0);
1767              
1768 33 50         return (number < NGENRES) ? genre_table[number] : string;
1769             }