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