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