• 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/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) {
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             memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset);
399 
400             flags &= ~2;
401         }
402 
403         if (flags != prevFlags || iTunesHack) {
404             WriteSyncsafeInteger(&mData[offset + 4], dataSize);
405             mData[offset + 8] = flags >> 8;
406             mData[offset + 9] = flags & 0xff;
407         }
408 
409         offset += 10 + dataSize;
410     }
411 
412     memset(&mData[mSize], 0, oldSize - mSize);
413 
414     return true;
415 }
416 
Iterator(const ID3 & parent,const char * id)417 ID3::Iterator::Iterator(const ID3 &parent, const char *id)
418     : mParent(parent),
419       mID(NULL),
420       mOffset(mParent.mFirstFrameOffset),
421       mFrameData(NULL),
422       mFrameSize(0) {
423     if (id) {
424         mID = strdup(id);
425     }
426 
427     findFrame();
428 }
429 
~Iterator()430 ID3::Iterator::~Iterator() {
431     if (mID) {
432         free(mID);
433         mID = NULL;
434     }
435 }
436 
done() const437 bool ID3::Iterator::done() const {
438     return mFrameData == NULL;
439 }
440 
next()441 void ID3::Iterator::next() {
442     if (mFrameData == NULL) {
443         return;
444     }
445 
446     mOffset += mFrameSize;
447 
448     findFrame();
449 }
450 
getID(String8 * id) const451 void ID3::Iterator::getID(String8 *id) const {
452     id->setTo("");
453 
454     if (mFrameData == NULL) {
455         return;
456     }
457 
458     if (mParent.mVersion == ID3_V2_2) {
459         id->setTo((const char *)&mParent.mData[mOffset], 3);
460     } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) {
461         id->setTo((const char *)&mParent.mData[mOffset], 4);
462     } else {
463         CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
464 
465         switch (mOffset) {
466             case 3:
467                 id->setTo("TT2");
468                 break;
469             case 33:
470                 id->setTo("TP1");
471                 break;
472             case 63:
473                 id->setTo("TAL");
474                 break;
475             case 93:
476                 id->setTo("TYE");
477                 break;
478             case 97:
479                 id->setTo("COM");
480                 break;
481             case 126:
482                 id->setTo("TRK");
483                 break;
484             case 127:
485                 id->setTo("TCO");
486                 break;
487             default:
488                 CHECK(!"should not be here.");
489                 break;
490         }
491     }
492 }
493 
494 
495 // the 2nd argument is used to get the data following the \0 in a comment field
getString(String8 * id,String8 * comment) const496 void ID3::Iterator::getString(String8 *id, String8 *comment) const {
497     getstring(id, false);
498     if (comment != NULL) {
499         getstring(comment, true);
500     }
501 }
502 
503 // comment fields (COM/COMM) contain an initial short descriptor, followed by \0,
504 // followed by more data. The data following the \0 can be retrieved by setting
505 // "otherdata" to true.
getstring(String8 * id,bool otherdata) const506 void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
507     id->setTo("");
508 
509     const uint8_t *frameData = mFrameData;
510     if (frameData == NULL) {
511         return;
512     }
513 
514     uint8_t encoding = *frameData;
515 
516     if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
517         if (mOffset == 126 || mOffset == 127) {
518             // Special treatment for the track number and genre.
519             char tmp[16];
520             sprintf(tmp, "%d", (int)*frameData);
521 
522             id->setTo(tmp);
523             return;
524         }
525 
526         // this is supposed to be ISO-8859-1, but pass it up as-is to the caller, who will figure
527         // out the real encoding
528         id->setTo((const char*)frameData, mFrameSize);
529         return;
530     }
531 
532     if (mFrameSize < getHeaderLength() + 1) {
533         return;
534     }
535     size_t n = mFrameSize - getHeaderLength() - 1;
536     if (otherdata) {
537         // skip past the encoding, language, and the 0 separator
538         frameData += 4;
539         int32_t i = n - 4;
540         while(--i >= 0 && *++frameData != 0) ;
541         int skipped = (frameData - mFrameData);
542         if (skipped >= (int)n) {
543             return;
544         }
545         n -= skipped;
546     }
547 
548     if (n <= 0) {
549        return;
550     }
551 
552     if (encoding == 0x00) {
553         // supposedly ISO 8859-1
554         id->setTo((const char*)frameData + 1, n);
555     } else if (encoding == 0x03) {
556         // supposedly UTF-8
557         id->setTo((const char *)(frameData + 1), n);
558     } else if (encoding == 0x02) {
559         // supposedly UTF-16 BE, no byte order mark.
560         // API wants number of characters, not number of bytes...
561         int len = n / 2;
562         const char16_t *framedata = (const char16_t *) (frameData + 1);
563         char16_t *framedatacopy = NULL;
564 #if BYTE_ORDER == LITTLE_ENDIAN
565         if (len > 0) {
566             framedatacopy = new (std::nothrow) char16_t[len];
567             if (framedatacopy == NULL) {
568                 return;
569             }
570             for (int i = 0; i < len; i++) {
571                 framedatacopy[i] = bswap_16(framedata[i]);
572             }
573             framedata = framedatacopy;
574         }
575 #endif
576         id->setTo(framedata, len);
577         if (framedatacopy != NULL) {
578             delete[] framedatacopy;
579         }
580     } else if (encoding == 0x01) {
581         // UCS-2
582         // API wants number of characters, not number of bytes...
583         int len = n / 2;
584         const char16_t *framedata = (const char16_t *) (frameData + 1);
585         char16_t *framedatacopy = NULL;
586         if (*framedata == 0xfffe) {
587             // endianness marker != host endianness, convert & skip
588             if (len <= 1) {
589                 return;         // nothing after the marker
590             }
591             framedatacopy = new (std::nothrow) char16_t[len];
592             if (framedatacopy == NULL) {
593                 return;
594             }
595             for (int i = 0; i < len; i++) {
596                 framedatacopy[i] = bswap_16(framedata[i]);
597             }
598             framedata = framedatacopy;
599             // and skip over the marker
600             framedata++;
601             len--;
602         } else if (*framedata == 0xfeff) {
603             // endianness marker == host endianness, skip it
604             if (len <= 1) {
605                 return;         // nothing after the marker
606             }
607             framedata++;
608             len--;
609         }
610 
611         // check if the resulting data consists entirely of 8-bit values
612         bool eightBit = true;
613         for (int i = 0; i < len; i++) {
614             if (framedata[i] > 0xff) {
615                 eightBit = false;
616                 break;
617             }
618         }
619         if (eightBit) {
620             // collapse to 8 bit, then let the media scanner client figure out the real encoding
621             char *frame8 = new (std::nothrow) char[len];
622             if (frame8 != NULL) {
623                 for (int i = 0; i < len; i++) {
624                     frame8[i] = framedata[i];
625                 }
626                 id->setTo(frame8, len);
627                 delete [] frame8;
628             } else {
629                 id->setTo(framedata, len);
630             }
631         } else {
632             id->setTo(framedata, len);
633         }
634 
635         if (framedatacopy != NULL) {
636             delete[] framedatacopy;
637         }
638     }
639 }
640 
getData(size_t * length) const641 const uint8_t *ID3::Iterator::getData(size_t *length) const {
642     *length = 0;
643 
644     if (mFrameData == NULL) {
645         return NULL;
646     }
647 
648     // Prevent integer underflow
649     if (mFrameSize < getHeaderLength()) {
650         return NULL;
651     }
652 
653     *length = mFrameSize - getHeaderLength();
654 
655     return mFrameData;
656 }
657 
getHeaderLength() const658 size_t ID3::Iterator::getHeaderLength() const {
659     if (mParent.mVersion == ID3_V2_2) {
660         return 6;
661     } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) {
662         return 10;
663     } else {
664         CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
665         return 0;
666     }
667 }
668 
findFrame()669 void ID3::Iterator::findFrame() {
670     for (;;) {
671         mFrameData = NULL;
672         mFrameSize = 0;
673 
674         if (mParent.mVersion == ID3_V2_2) {
675             if (mOffset + 6 > mParent.mSize) {
676                 return;
677             }
678 
679             if (!memcmp(&mParent.mData[mOffset], "\0\0\0", 3)) {
680                 return;
681             }
682 
683             mFrameSize =
684                 (mParent.mData[mOffset + 3] << 16)
685                 | (mParent.mData[mOffset + 4] << 8)
686                 | mParent.mData[mOffset + 5];
687 
688             if (mFrameSize == 0) {
689                 return;
690             }
691             mFrameSize += 6; // add tag id and size field
692 
693             // Prevent integer overflow in validation
694             if (SIZE_MAX - mOffset <= mFrameSize) {
695                 return;
696             }
697 
698             if (mOffset + mFrameSize > mParent.mSize) {
699                 ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
700                     mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)6);
701                 return;
702             }
703 
704             mFrameData = &mParent.mData[mOffset + 6];
705 
706             if (!mID) {
707                 break;
708             }
709 
710             char id[4];
711             memcpy(id, &mParent.mData[mOffset], 3);
712             id[3] = '\0';
713 
714             if (!strcmp(id, mID)) {
715                 break;
716             }
717         } else if (mParent.mVersion == ID3_V2_3
718                 || mParent.mVersion == ID3_V2_4) {
719             if (mOffset + 10 > mParent.mSize) {
720                 return;
721             }
722 
723             if (!memcmp(&mParent.mData[mOffset], "\0\0\0\0", 4)) {
724                 return;
725             }
726 
727             size_t baseSize = 0;
728             if (mParent.mVersion == ID3_V2_4) {
729                 if (!ParseSyncsafeInteger(
730                             &mParent.mData[mOffset + 4], &baseSize)) {
731                     return;
732                 }
733             } else {
734                 baseSize = U32_AT(&mParent.mData[mOffset + 4]);
735             }
736 
737             if (baseSize == 0) {
738                 return;
739             }
740 
741             // Prevent integer overflow when adding
742             if (SIZE_MAX - 10 <= baseSize) {
743                 return;
744             }
745 
746             mFrameSize = 10 + baseSize; // add tag id, size field and flags
747 
748             // Prevent integer overflow in validation
749             if (SIZE_MAX - mOffset <= mFrameSize) {
750                 return;
751             }
752 
753             if (mOffset + mFrameSize > mParent.mSize) {
754                 ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
755                     mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)10);
756                 return;
757             }
758 
759             uint16_t flags = U16_AT(&mParent.mData[mOffset + 8]);
760 
761             if ((mParent.mVersion == ID3_V2_4 && (flags & 0x000c))
762                 || (mParent.mVersion == ID3_V2_3 && (flags & 0x00c0))) {
763                 // Compression or encryption are not supported at this time.
764                 // Per-frame unsynchronization and data-length indicator
765                 // have already been taken care of.
766 
767                 ALOGV("Skipping unsupported frame (compression, encryption "
768                      "or per-frame unsynchronization flagged");
769 
770                 mOffset += mFrameSize;
771                 continue;
772             }
773 
774             mFrameData = &mParent.mData[mOffset + 10];
775 
776             if (!mID) {
777                 break;
778             }
779 
780             char id[5];
781             memcpy(id, &mParent.mData[mOffset], 4);
782             id[4] = '\0';
783 
784             if (!strcmp(id, mID)) {
785                 break;
786             }
787         } else {
788             CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
789 
790             if (mOffset >= mParent.mSize) {
791                 return;
792             }
793 
794             mFrameData = &mParent.mData[mOffset];
795 
796             switch (mOffset) {
797                 case 3:
798                 case 33:
799                 case 63:
800                     mFrameSize = 30;
801                     break;
802                 case 93:
803                     mFrameSize = 4;
804                     break;
805                 case 97:
806                     if (mParent.mVersion == ID3_V1) {
807                         mFrameSize = 30;
808                     } else {
809                         mFrameSize = 29;
810                     }
811                     break;
812                 case 126:
813                     mFrameSize = 1;
814                     break;
815                 case 127:
816                     mFrameSize = 1;
817                     break;
818                 default:
819                     CHECK(!"Should not be here, invalid offset.");
820                     break;
821             }
822 
823             if (!mID) {
824                 break;
825             }
826 
827             String8 id;
828             getID(&id);
829 
830             if (id == mID) {
831                 break;
832             }
833         }
834 
835         mOffset += mFrameSize;
836     }
837 }
838 
StringSize(const uint8_t * start,uint8_t encoding)839 static size_t StringSize(const uint8_t *start, uint8_t encoding) {
840     if (encoding == 0x00 || encoding == 0x03) {
841         // ISO 8859-1 or UTF-8
842         return strlen((const char *)start) + 1;
843     }
844 
845     // UCS-2
846     size_t n = 0;
847     while (start[n] != '\0' || start[n + 1] != '\0') {
848         n += 2;
849     }
850 
851     // Add size of null termination.
852     return n + 2;
853 }
854 
855 const void *
getAlbumArt(size_t * length,String8 * mime) const856 ID3::getAlbumArt(size_t *length, String8 *mime) const {
857     *length = 0;
858     mime->setTo("");
859 
860     Iterator it(
861             *this,
862             (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) ? "APIC" : "PIC");
863 
864     while (!it.done()) {
865         size_t size;
866         const uint8_t *data = it.getData(&size);
867         if (!data) {
868             return NULL;
869         }
870 
871         if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
872             uint8_t encoding = data[0];
873             mime->setTo((const char *)&data[1]);
874             size_t mimeLen = strlen((const char *)&data[1]) + 1;
875 
876 #if 0
877             uint8_t picType = data[1 + mimeLen];
878             if (picType != 0x03) {
879                 // Front Cover Art
880                 it.next();
881                 continue;
882             }
883 #endif
884 
885             size_t descLen = StringSize(&data[2 + mimeLen], encoding);
886 
887             if (size < 2 ||
888                     size - 2 < mimeLen ||
889                     size - 2 - mimeLen < descLen) {
890                 ALOGW("bogus album art sizes");
891                 return NULL;
892             }
893             *length = size - 2 - mimeLen - descLen;
894 
895             return &data[2 + mimeLen + descLen];
896         } else {
897             uint8_t encoding = data[0];
898 
899             if (!memcmp(&data[1], "PNG", 3)) {
900                 mime->setTo("image/png");
901             } else if (!memcmp(&data[1], "JPG", 3)) {
902                 mime->setTo("image/jpeg");
903             } else if (!memcmp(&data[1], "-->", 3)) {
904                 mime->setTo("text/plain");
905             } else {
906                 return NULL;
907             }
908 
909 #if 0
910             uint8_t picType = data[4];
911             if (picType != 0x03) {
912                 // Front Cover Art
913                 it.next();
914                 continue;
915             }
916 #endif
917 
918             size_t descLen = StringSize(&data[5], encoding);
919 
920             *length = size - 5 - descLen;
921 
922             return &data[5 + descLen];
923         }
924     }
925 
926     return NULL;
927 }
928 
parseV1(const sp<DataSource> & source)929 bool ID3::parseV1(const sp<DataSource> &source) {
930     const size_t V1_TAG_SIZE = 128;
931 
932     off64_t size;
933     if (source->getSize(&size) != OK || size < (off64_t)V1_TAG_SIZE) {
934         return false;
935     }
936 
937     mData = (uint8_t *)malloc(V1_TAG_SIZE);
938     if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE)
939             != (ssize_t)V1_TAG_SIZE) {
940         free(mData);
941         mData = NULL;
942 
943         return false;
944     }
945 
946     if (memcmp("TAG", mData, 3)) {
947         free(mData);
948         mData = NULL;
949 
950         return false;
951     }
952 
953     mSize = V1_TAG_SIZE;
954     mFirstFrameOffset = 3;
955 
956     if (mData[V1_TAG_SIZE - 3] != 0) {
957         mVersion = ID3_V1;
958     } else {
959         mVersion = ID3_V1_1;
960     }
961 
962     return true;
963 }
964 
965 }  // namespace android
966