1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ID3"
19 #include <utils/Log.h>
20
21 #include "../include/ID3.h"
22
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/DataSource.h>
25 #include <media/stagefright/Utils.h>
26 #include <utils/String8.h>
27 #include <byteswap.h>
28
29 namespace android {
30
31 static const size_t kMaxMetadataSize = 3 * 1024 * 1024;
32
33 struct MemorySource : public DataSource {
MemorySourceandroid::MemorySource34 MemorySource(const uint8_t *data, size_t size)
35 : mData(data),
36 mSize(size) {
37 }
38
initCheckandroid::MemorySource39 virtual status_t initCheck() const {
40 return OK;
41 }
42
readAtandroid::MemorySource43 virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
44 off64_t available = (offset >= (off64_t)mSize) ? 0ll : mSize - offset;
45
46 size_t copy = (available > (off64_t)size) ? size : available;
47 memcpy(data, mData + offset, copy);
48
49 return copy;
50 }
51
52 private:
53 const uint8_t *mData;
54 size_t mSize;
55
56 DISALLOW_EVIL_CONSTRUCTORS(MemorySource);
57 };
58
ID3(const sp<DataSource> & source,bool ignoreV1,off64_t offset)59 ID3::ID3(const sp<DataSource> &source, bool ignoreV1, off64_t offset)
60 : mIsValid(false),
61 mData(NULL),
62 mSize(0),
63 mFirstFrameOffset(0),
64 mVersion(ID3_UNKNOWN),
65 mRawSize(0) {
66 mIsValid = parseV2(source, offset);
67
68 if (!mIsValid && !ignoreV1) {
69 mIsValid = parseV1(source);
70 }
71 }
72
ID3(const uint8_t * data,size_t size,bool ignoreV1)73 ID3::ID3(const uint8_t *data, size_t size, bool ignoreV1)
74 : mIsValid(false),
75 mData(NULL),
76 mSize(0),
77 mFirstFrameOffset(0),
78 mVersion(ID3_UNKNOWN),
79 mRawSize(0) {
80 sp<MemorySource> source = new (std::nothrow) MemorySource(data, size);
81
82 if (source == NULL)
83 return;
84
85 mIsValid = parseV2(source, 0);
86
87 if (!mIsValid && !ignoreV1) {
88 mIsValid = parseV1(source);
89 }
90 }
91
~ID3()92 ID3::~ID3() {
93 if (mData) {
94 free(mData);
95 mData = NULL;
96 }
97 }
98
isValid() const99 bool ID3::isValid() const {
100 return mIsValid;
101 }
102
version() const103 ID3::Version ID3::version() const {
104 return mVersion;
105 }
106
107 // static
ParseSyncsafeInteger(const uint8_t encoded[4],size_t * x)108 bool ID3::ParseSyncsafeInteger(const uint8_t encoded[4], size_t *x) {
109 *x = 0;
110 for (int32_t i = 0; i < 4; ++i) {
111 if (encoded[i] & 0x80) {
112 return false;
113 }
114
115 *x = ((*x) << 7) | encoded[i];
116 }
117
118 return true;
119 }
120
parseV2(const sp<DataSource> & source,off64_t offset)121 bool ID3::parseV2(const sp<DataSource> &source, off64_t offset) {
122 struct id3_header {
123 char id[3];
124 uint8_t version_major;
125 uint8_t version_minor;
126 uint8_t flags;
127 uint8_t enc_size[4];
128 };
129
130 id3_header header;
131 if (source->readAt(
132 offset, &header, sizeof(header)) != (ssize_t)sizeof(header)) {
133 return false;
134 }
135
136 if (memcmp(header.id, "ID3", 3)) {
137 return false;
138 }
139
140 if (header.version_major == 0xff || header.version_minor == 0xff) {
141 return false;
142 }
143
144 if (header.version_major == 2) {
145 if (header.flags & 0x3f) {
146 // We only support the 2 high bits, if any of the lower bits are
147 // set, we cannot guarantee to understand the tag format.
148 return false;
149 }
150
151 if (header.flags & 0x40) {
152 // No compression scheme has been decided yet, ignore the
153 // tag if compression is indicated.
154
155 return false;
156 }
157 } else if (header.version_major == 3) {
158 if (header.flags & 0x1f) {
159 // We only support the 3 high bits, if any of the lower bits are
160 // set, we cannot guarantee to understand the tag format.
161 return false;
162 }
163 } else if (header.version_major == 4) {
164 if (header.flags & 0x0f) {
165 // The lower 4 bits are undefined in this spec.
166 return false;
167 }
168 } else {
169 return false;
170 }
171
172 size_t size;
173 if (!ParseSyncsafeInteger(header.enc_size, &size)) {
174 return false;
175 }
176
177 if (size > kMaxMetadataSize) {
178 ALOGE("skipping huge ID3 metadata of size %zu", size);
179 return false;
180 }
181
182 mData = (uint8_t *)malloc(size);
183
184 if (mData == NULL) {
185 return false;
186 }
187
188 mSize = size;
189 mRawSize = mSize + sizeof(header);
190
191 if (source->readAt(offset + sizeof(header), mData, mSize) != (ssize_t)mSize) {
192 free(mData);
193 mData = NULL;
194
195 return false;
196 }
197
198 if (header.version_major == 4) {
199 void *copy = malloc(size);
200 if (copy == NULL) {
201 free(mData);
202 mData = NULL;
203 ALOGE("b/24623447, no more memory");
204 return false;
205 }
206
207 memcpy(copy, mData, size);
208
209 bool success = removeUnsynchronizationV2_4(false /* iTunesHack */);
210 if (!success) {
211 memcpy(mData, copy, size);
212 mSize = size;
213
214 success = removeUnsynchronizationV2_4(true /* iTunesHack */);
215
216 if (success) {
217 ALOGV("Had to apply the iTunes hack to parse this ID3 tag");
218 }
219 }
220
221 free(copy);
222 copy = NULL;
223
224 if (!success) {
225 free(mData);
226 mData = NULL;
227
228 return false;
229 }
230 } else if (header.flags & 0x80) {
231 ALOGV("removing unsynchronization");
232
233 removeUnsynchronization();
234 }
235
236 mFirstFrameOffset = 0;
237 if (header.version_major == 3 && (header.flags & 0x40)) {
238 // Version 2.3 has an optional extended header.
239
240 if (mSize < 4) {
241 free(mData);
242 mData = NULL;
243
244 return false;
245 }
246
247 size_t extendedHeaderSize = U32_AT(&mData[0]);
248 if (extendedHeaderSize > SIZE_MAX - 4) {
249 free(mData);
250 mData = NULL;
251 ALOGE("b/24623447, extendedHeaderSize is too large");
252 return false;
253 }
254 extendedHeaderSize += 4;
255
256 if (extendedHeaderSize > mSize) {
257 free(mData);
258 mData = NULL;
259
260 return false;
261 }
262
263 mFirstFrameOffset = extendedHeaderSize;
264
265 uint16_t extendedFlags = 0;
266 if (extendedHeaderSize >= 6) {
267 extendedFlags = U16_AT(&mData[4]);
268
269 if (extendedHeaderSize >= 10) {
270 size_t paddingSize = U32_AT(&mData[6]);
271
272 if (paddingSize > SIZE_MAX - mFirstFrameOffset) {
273 ALOGE("b/24623447, paddingSize is too large");
274 }
275 if (paddingSize > mSize - mFirstFrameOffset) {
276 free(mData);
277 mData = NULL;
278
279 return false;
280 }
281
282 mSize -= paddingSize;
283 }
284
285 if (extendedFlags & 0x8000) {
286 ALOGV("have crc");
287 }
288 }
289 } else if (header.version_major == 4 && (header.flags & 0x40)) {
290 // Version 2.4 has an optional extended header, that's different
291 // from Version 2.3's...
292
293 if (mSize < 4) {
294 free(mData);
295 mData = NULL;
296
297 return false;
298 }
299
300 size_t ext_size;
301 if (!ParseSyncsafeInteger(mData, &ext_size)) {
302 free(mData);
303 mData = NULL;
304
305 return false;
306 }
307
308 if (ext_size < 6 || ext_size > mSize) {
309 free(mData);
310 mData = NULL;
311
312 return false;
313 }
314
315 mFirstFrameOffset = ext_size;
316 }
317
318 if (header.version_major == 2) {
319 mVersion = ID3_V2_2;
320 } else if (header.version_major == 3) {
321 mVersion = ID3_V2_3;
322 } else {
323 CHECK_EQ(header.version_major, 4);
324 mVersion = ID3_V2_4;
325 }
326
327 return true;
328 }
329
removeUnsynchronization()330 void ID3::removeUnsynchronization() {
331 for (size_t i = 0; i + 1 < mSize; ++i) {
332 if (mData[i] == 0xff && mData[i + 1] == 0x00) {
333 memmove(&mData[i + 1], &mData[i + 2], mSize - i - 2);
334 --mSize;
335 }
336 }
337 }
338
WriteSyncsafeInteger(uint8_t * dst,size_t x)339 static void WriteSyncsafeInteger(uint8_t *dst, size_t x) {
340 for (size_t i = 0; i < 4; ++i) {
341 dst[3 - i] = (x & 0x7f);
342 x >>= 7;
343 }
344 }
345
removeUnsynchronizationV2_4(bool iTunesHack)346 bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
347 size_t oldSize = mSize;
348
349 size_t offset = 0;
350 while (mSize >= 10 && offset <= mSize - 10) {
351 if (!memcmp(&mData[offset], "\0\0\0\0", 4)) {
352 break;
353 }
354
355 size_t dataSize;
356 if (iTunesHack) {
357 dataSize = U32_AT(&mData[offset + 4]);
358 } else if (!ParseSyncsafeInteger(&mData[offset + 4], &dataSize)) {
359 return false;
360 }
361
362 if (dataSize > mSize - 10 - offset) {
363 return false;
364 }
365
366 uint16_t flags = U16_AT(&mData[offset + 8]);
367 uint16_t prevFlags = flags;
368
369 if (flags & 1) {
370 // Strip data length indicator
371
372 if (mSize < 14 || mSize - 14 < offset || dataSize < 4) {
373 return false;
374 }
375 memmove(&mData[offset + 10], &mData[offset + 14], mSize - offset - 14);
376 mSize -= 4;
377 dataSize -= 4;
378
379 flags &= ~1;
380 }
381
382 if ((flags & 2) && (dataSize >= 2)) {
383 // This file has "unsynchronization", so we have to replace occurrences
384 // of 0xff 0x00 with just 0xff in order to get the real data.
385
386 size_t readOffset = offset + 11;
387 size_t writeOffset = offset + 11;
388 for (size_t i = 0; i + 1 < dataSize; ++i) {
389 if (mData[readOffset - 1] == 0xff
390 && mData[readOffset] == 0x00) {
391 ++readOffset;
392 --mSize;
393 --dataSize;
394 }
395 mData[writeOffset++] = mData[readOffset++];
396 }
397 // move the remaining data following this frame
398 if (readOffset <= oldSize) {
399 memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset);
400 } else {
401 ALOGE("b/34618607 (%zu %zu %zu %zu)", readOffset, writeOffset, oldSize, mSize);
402 android_errorWriteLog(0x534e4554, "34618607");
403 }
404
405 }
406 flags &= ~2;
407 if (flags != prevFlags || iTunesHack) {
408 WriteSyncsafeInteger(&mData[offset + 4], dataSize);
409 mData[offset + 8] = flags >> 8;
410 mData[offset + 9] = flags & 0xff;
411 }
412
413 offset += 10 + dataSize;
414 }
415
416 memset(&mData[mSize], 0, oldSize - mSize);
417
418 return true;
419 }
420
Iterator(const ID3 & parent,const char * id)421 ID3::Iterator::Iterator(const ID3 &parent, const char *id)
422 : mParent(parent),
423 mID(NULL),
424 mOffset(mParent.mFirstFrameOffset),
425 mFrameData(NULL),
426 mFrameSize(0) {
427 if (id) {
428 mID = strdup(id);
429 }
430
431 findFrame();
432 }
433
~Iterator()434 ID3::Iterator::~Iterator() {
435 if (mID) {
436 free(mID);
437 mID = NULL;
438 }
439 }
440
done() const441 bool ID3::Iterator::done() const {
442 return mFrameData == NULL;
443 }
444
next()445 void ID3::Iterator::next() {
446 if (mFrameData == NULL) {
447 return;
448 }
449
450 mOffset += mFrameSize;
451
452 findFrame();
453 }
454
getID(String8 * id) const455 void ID3::Iterator::getID(String8 *id) const {
456 id->setTo("");
457
458 if (mFrameData == NULL) {
459 return;
460 }
461
462 if (mParent.mVersion == ID3_V2_2) {
463 id->setTo((const char *)&mParent.mData[mOffset], 3);
464 } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) {
465 id->setTo((const char *)&mParent.mData[mOffset], 4);
466 } else {
467 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
468
469 switch (mOffset) {
470 case 3:
471 id->setTo("TT2");
472 break;
473 case 33:
474 id->setTo("TP1");
475 break;
476 case 63:
477 id->setTo("TAL");
478 break;
479 case 93:
480 id->setTo("TYE");
481 break;
482 case 97:
483 id->setTo("COM");
484 break;
485 case 126:
486 id->setTo("TRK");
487 break;
488 case 127:
489 id->setTo("TCO");
490 break;
491 default:
492 CHECK(!"should not be here.");
493 break;
494 }
495 }
496 }
497
498
499 // the 2nd argument is used to get the data following the \0 in a comment field
getString(String8 * id,String8 * comment) const500 void ID3::Iterator::getString(String8 *id, String8 *comment) const {
501 getstring(id, false);
502 if (comment != NULL) {
503 getstring(comment, true);
504 }
505 }
506
507 // comment fields (COM/COMM) contain an initial short descriptor, followed by \0,
508 // followed by more data. The data following the \0 can be retrieved by setting
509 // "otherdata" to true.
getstring(String8 * id,bool otherdata) const510 void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
511 id->setTo("");
512
513 const uint8_t *frameData = mFrameData;
514 if (frameData == NULL) {
515 return;
516 }
517
518 uint8_t encoding = *frameData;
519
520 if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
521 if (mOffset == 126 || mOffset == 127) {
522 // Special treatment for the track number and genre.
523 char tmp[16];
524 snprintf(tmp, sizeof(tmp), "%d", (int)*frameData);
525
526 id->setTo(tmp);
527 return;
528 }
529
530 // this is supposed to be ISO-8859-1, but pass it up as-is to the caller, who will figure
531 // out the real encoding
532 id->setTo((const char*)frameData, mFrameSize);
533 return;
534 }
535
536 if (mFrameSize < getHeaderLength() + 1) {
537 return;
538 }
539 size_t n = mFrameSize - getHeaderLength() - 1;
540 if (otherdata) {
541 if (n < 5) {
542 return;
543 }
544 // skip past the encoding, language, and the 0 separator
545 frameData += 4;
546 int32_t i = n - 4;
547 while(--i >= 0 && *++frameData != 0) ;
548 int skipped = (frameData - mFrameData);
549 if (skipped >= (int)n) {
550 return;
551 }
552 n -= skipped;
553 }
554
555 if (n <= 0) {
556 return;
557 }
558
559 if (encoding == 0x00) {
560 // supposedly ISO 8859-1
561 id->setTo((const char*)frameData + 1, n);
562 } else if (encoding == 0x03) {
563 // supposedly UTF-8
564 id->setTo((const char *)(frameData + 1), n);
565 } else if (encoding == 0x02) {
566 // supposedly UTF-16 BE, no byte order mark.
567 // API wants number of characters, not number of bytes...
568 int len = n / 2;
569 const char16_t *framedata = (const char16_t *) (frameData + 1);
570 char16_t *framedatacopy = NULL;
571 #if BYTE_ORDER == LITTLE_ENDIAN
572 if (len > 0) {
573 framedatacopy = new (std::nothrow) char16_t[len];
574 if (framedatacopy == NULL) {
575 return;
576 }
577 for (int i = 0; i < len; i++) {
578 framedatacopy[i] = bswap_16(framedata[i]);
579 }
580 framedata = framedatacopy;
581 }
582 #endif
583 id->setTo(framedata, len);
584 if (framedatacopy != NULL) {
585 delete[] framedatacopy;
586 }
587 } else if (encoding == 0x01) {
588 // UCS-2
589 // API wants number of characters, not number of bytes...
590 int len = n / 2;
591 const char16_t *framedata = (const char16_t *) (frameData + 1);
592 char16_t *framedatacopy = NULL;
593 if (*framedata == 0xfffe) {
594 // endianness marker != host endianness, convert & skip
595 if (len <= 1) {
596 return; // nothing after the marker
597 }
598 framedatacopy = new (std::nothrow) char16_t[len];
599 if (framedatacopy == NULL) {
600 return;
601 }
602 for (int i = 0; i < len; i++) {
603 framedatacopy[i] = bswap_16(framedata[i]);
604 }
605 framedata = framedatacopy;
606 // and skip over the marker
607 framedata++;
608 len--;
609 } else if (*framedata == 0xfeff) {
610 // endianness marker == host endianness, skip it
611 if (len <= 1) {
612 return; // nothing after the marker
613 }
614 framedata++;
615 len--;
616 }
617
618 // check if the resulting data consists entirely of 8-bit values
619 bool eightBit = true;
620 for (int i = 0; i < len; i++) {
621 if (framedata[i] > 0xff) {
622 eightBit = false;
623 break;
624 }
625 }
626 if (eightBit) {
627 // collapse to 8 bit, then let the media scanner client figure out the real encoding
628 char *frame8 = new (std::nothrow) char[len];
629 if (frame8 != NULL) {
630 for (int i = 0; i < len; i++) {
631 frame8[i] = framedata[i];
632 }
633 id->setTo(frame8, len);
634 delete [] frame8;
635 } else {
636 id->setTo(framedata, len);
637 }
638 } else {
639 id->setTo(framedata, len);
640 }
641
642 if (framedatacopy != NULL) {
643 delete[] framedatacopy;
644 }
645 }
646 }
647
getData(size_t * length) const648 const uint8_t *ID3::Iterator::getData(size_t *length) const {
649 *length = 0;
650
651 if (mFrameData == NULL) {
652 return NULL;
653 }
654
655 // Prevent integer underflow
656 if (mFrameSize < getHeaderLength()) {
657 return NULL;
658 }
659
660 *length = mFrameSize - getHeaderLength();
661
662 return mFrameData;
663 }
664
getHeaderLength() const665 size_t ID3::Iterator::getHeaderLength() const {
666 if (mParent.mVersion == ID3_V2_2) {
667 return 6;
668 } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) {
669 return 10;
670 } else {
671 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
672 return 0;
673 }
674 }
675
findFrame()676 void ID3::Iterator::findFrame() {
677 for (;;) {
678 mFrameData = NULL;
679 mFrameSize = 0;
680
681 if (mParent.mVersion == ID3_V2_2) {
682 if (mOffset + 6 > mParent.mSize) {
683 return;
684 }
685
686 if (!memcmp(&mParent.mData[mOffset], "\0\0\0", 3)) {
687 return;
688 }
689
690 mFrameSize =
691 (mParent.mData[mOffset + 3] << 16)
692 | (mParent.mData[mOffset + 4] << 8)
693 | mParent.mData[mOffset + 5];
694
695 if (mFrameSize == 0) {
696 return;
697 }
698 mFrameSize += 6; // add tag id and size field
699
700 // Prevent integer overflow in validation
701 if (SIZE_MAX - mOffset <= mFrameSize) {
702 return;
703 }
704
705 if (mOffset + mFrameSize > mParent.mSize) {
706 ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
707 mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)6);
708 return;
709 }
710
711 mFrameData = &mParent.mData[mOffset + 6];
712
713 if (!mID) {
714 break;
715 }
716
717 char id[4];
718 memcpy(id, &mParent.mData[mOffset], 3);
719 id[3] = '\0';
720
721 if (!strcmp(id, mID)) {
722 break;
723 }
724 } else if (mParent.mVersion == ID3_V2_3
725 || mParent.mVersion == ID3_V2_4) {
726 if (mOffset + 10 > mParent.mSize) {
727 return;
728 }
729
730 if (!memcmp(&mParent.mData[mOffset], "\0\0\0\0", 4)) {
731 return;
732 }
733
734 size_t baseSize = 0;
735 if (mParent.mVersion == ID3_V2_4) {
736 if (!ParseSyncsafeInteger(
737 &mParent.mData[mOffset + 4], &baseSize)) {
738 return;
739 }
740 } else {
741 baseSize = U32_AT(&mParent.mData[mOffset + 4]);
742 }
743
744 if (baseSize == 0) {
745 return;
746 }
747
748 // Prevent integer overflow when adding
749 if (SIZE_MAX - 10 <= baseSize) {
750 return;
751 }
752
753 mFrameSize = 10 + baseSize; // add tag id, size field and flags
754
755 // Prevent integer overflow in validation
756 if (SIZE_MAX - mOffset <= mFrameSize) {
757 return;
758 }
759
760 if (mOffset + mFrameSize > mParent.mSize) {
761 ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
762 mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)10);
763 return;
764 }
765
766 uint16_t flags = U16_AT(&mParent.mData[mOffset + 8]);
767
768 if ((mParent.mVersion == ID3_V2_4 && (flags & 0x000c))
769 || (mParent.mVersion == ID3_V2_3 && (flags & 0x00c0))) {
770 // Compression or encryption are not supported at this time.
771 // Per-frame unsynchronization and data-length indicator
772 // have already been taken care of.
773
774 ALOGV("Skipping unsupported frame (compression, encryption "
775 "or per-frame unsynchronization flagged");
776
777 mOffset += mFrameSize;
778 continue;
779 }
780
781 mFrameData = &mParent.mData[mOffset + 10];
782
783 if (!mID) {
784 break;
785 }
786
787 char id[5];
788 memcpy(id, &mParent.mData[mOffset], 4);
789 id[4] = '\0';
790
791 if (!strcmp(id, mID)) {
792 break;
793 }
794 } else {
795 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
796
797 if (mOffset >= mParent.mSize) {
798 return;
799 }
800
801 mFrameData = &mParent.mData[mOffset];
802
803 switch (mOffset) {
804 case 3:
805 case 33:
806 case 63:
807 mFrameSize = 30;
808 break;
809 case 93:
810 mFrameSize = 4;
811 break;
812 case 97:
813 if (mParent.mVersion == ID3_V1) {
814 mFrameSize = 30;
815 } else {
816 mFrameSize = 29;
817 }
818 break;
819 case 126:
820 mFrameSize = 1;
821 break;
822 case 127:
823 mFrameSize = 1;
824 break;
825 default:
826 CHECK(!"Should not be here, invalid offset.");
827 break;
828 }
829
830 if (!mID) {
831 break;
832 }
833
834 String8 id;
835 getID(&id);
836
837 if (id == mID) {
838 break;
839 }
840 }
841
842 mOffset += mFrameSize;
843 }
844 }
845
846 // return includes terminator; if unterminated, returns > limit
StringSize(const uint8_t * start,size_t limit,uint8_t encoding)847 static size_t StringSize(const uint8_t *start, size_t limit, uint8_t encoding) {
848
849 if (encoding == 0x00 || encoding == 0x03) {
850 // ISO 8859-1 or UTF-8
851 return strnlen((const char *)start, limit) + 1;
852 }
853
854 // UCS-2
855 size_t n = 0;
856 while ((n+1 < limit) && (start[n] != '\0' || start[n + 1] != '\0')) {
857 n += 2;
858 }
859 n += 2;
860 return n;
861 }
862
863 const void *
getAlbumArt(size_t * length,String8 * mime) const864 ID3::getAlbumArt(size_t *length, String8 *mime) const {
865 *length = 0;
866 mime->setTo("");
867
868 Iterator it(
869 *this,
870 (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) ? "APIC" : "PIC");
871
872 while (!it.done()) {
873 size_t size;
874 const uint8_t *data = it.getData(&size);
875 if (!data) {
876 return NULL;
877 }
878
879 if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
880 uint8_t encoding = data[0];
881 size_t consumed = 1;
882
883 // *always* in an 8-bit encoding
884 size_t mimeLen = StringSize(&data[consumed], size - consumed, 0x00);
885 if (mimeLen > size - consumed) {
886 ALOGW("bogus album art size: mime");
887 return NULL;
888 }
889 mime->setTo((const char *)&data[consumed]);
890 consumed += mimeLen;
891
892 #if 0
893 uint8_t picType = data[consumed];
894 if (picType != 0x03) {
895 // Front Cover Art
896 it.next();
897 continue;
898 }
899 #endif
900
901 consumed++;
902 if (consumed >= size) {
903 ALOGW("bogus album art size: pic type");
904 return NULL;
905 }
906
907 size_t descLen = StringSize(&data[consumed], size - consumed, encoding);
908 consumed += descLen;
909
910 if (consumed >= size) {
911 ALOGW("bogus album art size: description");
912 return NULL;
913 }
914
915 *length = size - consumed;
916
917 return &data[consumed];
918 } else {
919 uint8_t encoding = data[0];
920
921 if (size <= 5) {
922 return NULL;
923 }
924
925 if (!memcmp(&data[1], "PNG", 3)) {
926 mime->setTo("image/png");
927 } else if (!memcmp(&data[1], "JPG", 3)) {
928 mime->setTo("image/jpeg");
929 } else if (!memcmp(&data[1], "-->", 3)) {
930 mime->setTo("text/plain");
931 } else {
932 return NULL;
933 }
934
935 #if 0
936 uint8_t picType = data[4];
937 if (picType != 0x03) {
938 // Front Cover Art
939 it.next();
940 continue;
941 }
942 #endif
943
944 size_t descLen = StringSize(&data[5], size - 5, encoding);
945 if (descLen > size - 5) {
946 return NULL;
947 }
948
949 *length = size - 5 - descLen;
950
951 return &data[5 + descLen];
952 }
953 }
954
955 return NULL;
956 }
957
parseV1(const sp<DataSource> & source)958 bool ID3::parseV1(const sp<DataSource> &source) {
959 const size_t V1_TAG_SIZE = 128;
960
961 off64_t size;
962 if (source->getSize(&size) != OK || size < (off64_t)V1_TAG_SIZE) {
963 return false;
964 }
965
966 mData = (uint8_t *)malloc(V1_TAG_SIZE);
967 if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE)
968 != (ssize_t)V1_TAG_SIZE) {
969 free(mData);
970 mData = NULL;
971
972 return false;
973 }
974
975 if (memcmp("TAG", mData, 3)) {
976 free(mData);
977 mData = NULL;
978
979 return false;
980 }
981
982 mSize = V1_TAG_SIZE;
983 mFirstFrameOffset = 3;
984
985 if (mData[V1_TAG_SIZE - 3] != 0) {
986 mVersion = ID3_V1;
987 } else {
988 mVersion = ID3_V1_1;
989 }
990
991 return true;
992 }
993
994 } // namespace android
995