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 *length = mFrameSize - getHeaderLength();
622
623 return mFrameData;
624 }
625
getHeaderLength() const626 size_t ID3::Iterator::getHeaderLength() const {
627 if (mParent.mVersion == ID3_V2_2) {
628 return 6;
629 } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) {
630 return 10;
631 } else {
632 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
633 return 0;
634 }
635 }
636
findFrame()637 void ID3::Iterator::findFrame() {
638 for (;;) {
639 mFrameData = NULL;
640 mFrameSize = 0;
641
642 if (mParent.mVersion == ID3_V2_2) {
643 if (mOffset + 6 > mParent.mSize) {
644 return;
645 }
646
647 if (!memcmp(&mParent.mData[mOffset], "\0\0\0", 3)) {
648 return;
649 }
650
651 mFrameSize =
652 (mParent.mData[mOffset + 3] << 16)
653 | (mParent.mData[mOffset + 4] << 8)
654 | mParent.mData[mOffset + 5];
655
656 if (mFrameSize == 0) {
657 return;
658 }
659 mFrameSize += 6; // add tag id and size field
660
661 // Prevent integer overflow in validation
662 if (SIZE_MAX - mOffset <= mFrameSize) {
663 return;
664 }
665
666 if (mOffset + mFrameSize > mParent.mSize) {
667 ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
668 mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)6);
669 return;
670 }
671
672 mFrameData = &mParent.mData[mOffset + 6];
673
674 if (!mID) {
675 break;
676 }
677
678 char id[4];
679 memcpy(id, &mParent.mData[mOffset], 3);
680 id[3] = '\0';
681
682 if (!strcmp(id, mID)) {
683 break;
684 }
685 } else if (mParent.mVersion == ID3_V2_3
686 || mParent.mVersion == ID3_V2_4) {
687 if (mOffset + 10 > mParent.mSize) {
688 return;
689 }
690
691 if (!memcmp(&mParent.mData[mOffset], "\0\0\0\0", 4)) {
692 return;
693 }
694
695 size_t baseSize = 0;
696 if (mParent.mVersion == ID3_V2_4) {
697 if (!ParseSyncsafeInteger(
698 &mParent.mData[mOffset + 4], &baseSize)) {
699 return;
700 }
701 } else {
702 baseSize = U32_AT(&mParent.mData[mOffset + 4]);
703 }
704
705 if (baseSize == 0) {
706 return;
707 }
708
709 // Prevent integer overflow when adding
710 if (SIZE_MAX - 10 <= baseSize) {
711 return;
712 }
713
714 mFrameSize = 10 + baseSize; // add tag id, size field and flags
715
716 // Prevent integer overflow in validation
717 if (SIZE_MAX - mOffset <= mFrameSize) {
718 return;
719 }
720
721 if (mOffset + mFrameSize > mParent.mSize) {
722 ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
723 mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)10);
724 return;
725 }
726
727 uint16_t flags = U16_AT(&mParent.mData[mOffset + 8]);
728
729 if ((mParent.mVersion == ID3_V2_4 && (flags & 0x000c))
730 || (mParent.mVersion == ID3_V2_3 && (flags & 0x00c0))) {
731 // Compression or encryption are not supported at this time.
732 // Per-frame unsynchronization and data-length indicator
733 // have already been taken care of.
734
735 ALOGV("Skipping unsupported frame (compression, encryption "
736 "or per-frame unsynchronization flagged");
737
738 mOffset += mFrameSize;
739 continue;
740 }
741
742 mFrameData = &mParent.mData[mOffset + 10];
743
744 if (!mID) {
745 break;
746 }
747
748 char id[5];
749 memcpy(id, &mParent.mData[mOffset], 4);
750 id[4] = '\0';
751
752 if (!strcmp(id, mID)) {
753 break;
754 }
755 } else {
756 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
757
758 if (mOffset >= mParent.mSize) {
759 return;
760 }
761
762 mFrameData = &mParent.mData[mOffset];
763
764 switch (mOffset) {
765 case 3:
766 case 33:
767 case 63:
768 mFrameSize = 30;
769 break;
770 case 93:
771 mFrameSize = 4;
772 break;
773 case 97:
774 if (mParent.mVersion == ID3_V1) {
775 mFrameSize = 30;
776 } else {
777 mFrameSize = 29;
778 }
779 break;
780 case 126:
781 mFrameSize = 1;
782 break;
783 case 127:
784 mFrameSize = 1;
785 break;
786 default:
787 CHECK(!"Should not be here, invalid offset.");
788 break;
789 }
790
791 if (!mID) {
792 break;
793 }
794
795 String8 id;
796 getID(&id);
797
798 if (id == mID) {
799 break;
800 }
801 }
802
803 mOffset += mFrameSize;
804 }
805 }
806
StringSize(const uint8_t * start,uint8_t encoding)807 static size_t StringSize(const uint8_t *start, uint8_t encoding) {
808 if (encoding == 0x00 || encoding == 0x03) {
809 // ISO 8859-1 or UTF-8
810 return strlen((const char *)start) + 1;
811 }
812
813 // UCS-2
814 size_t n = 0;
815 while (start[n] != '\0' || start[n + 1] != '\0') {
816 n += 2;
817 }
818
819 // Add size of null termination.
820 return n + 2;
821 }
822
823 const void *
getAlbumArt(size_t * length,String8 * mime) const824 ID3::getAlbumArt(size_t *length, String8 *mime) const {
825 *length = 0;
826 mime->setTo("");
827
828 Iterator it(
829 *this,
830 (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) ? "APIC" : "PIC");
831
832 while (!it.done()) {
833 size_t size;
834 const uint8_t *data = it.getData(&size);
835
836 if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
837 uint8_t encoding = data[0];
838 mime->setTo((const char *)&data[1]);
839 size_t mimeLen = strlen((const char *)&data[1]) + 1;
840
841 #if 0
842 uint8_t picType = data[1 + mimeLen];
843 if (picType != 0x03) {
844 // Front Cover Art
845 it.next();
846 continue;
847 }
848 #endif
849
850 size_t descLen = StringSize(&data[2 + mimeLen], encoding);
851
852 if (size < 2 ||
853 size - 2 < mimeLen ||
854 size - 2 - mimeLen < descLen) {
855 ALOGW("bogus album art sizes");
856 return NULL;
857 }
858 *length = size - 2 - mimeLen - descLen;
859
860 return &data[2 + mimeLen + descLen];
861 } else {
862 uint8_t encoding = data[0];
863
864 if (!memcmp(&data[1], "PNG", 3)) {
865 mime->setTo("image/png");
866 } else if (!memcmp(&data[1], "JPG", 3)) {
867 mime->setTo("image/jpeg");
868 } else if (!memcmp(&data[1], "-->", 3)) {
869 mime->setTo("text/plain");
870 } else {
871 return NULL;
872 }
873
874 #if 0
875 uint8_t picType = data[4];
876 if (picType != 0x03) {
877 // Front Cover Art
878 it.next();
879 continue;
880 }
881 #endif
882
883 size_t descLen = StringSize(&data[5], encoding);
884
885 *length = size - 5 - descLen;
886
887 return &data[5 + descLen];
888 }
889 }
890
891 return NULL;
892 }
893
parseV1(const sp<DataSource> & source)894 bool ID3::parseV1(const sp<DataSource> &source) {
895 const size_t V1_TAG_SIZE = 128;
896
897 off64_t size;
898 if (source->getSize(&size) != OK || size < (off64_t)V1_TAG_SIZE) {
899 return false;
900 }
901
902 mData = (uint8_t *)malloc(V1_TAG_SIZE);
903 if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE)
904 != (ssize_t)V1_TAG_SIZE) {
905 free(mData);
906 mData = NULL;
907
908 return false;
909 }
910
911 if (memcmp("TAG", mData, 3)) {
912 free(mData);
913 mData = NULL;
914
915 return false;
916 }
917
918 mSize = V1_TAG_SIZE;
919 mFirstFrameOffset = 3;
920
921 if (mData[V1_TAG_SIZE - 3] != 0) {
922 mVersion = ID3_V1;
923 } else {
924 mVersion = ID3_V1_1;
925 }
926
927 return true;
928 }
929
930 } // namespace android
931