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