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