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