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