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