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
29namespace android {
30
31static const size_t kMaxMetadataSize = 3 * 1024 * 1024;
32
33struct MemorySource : public DataSource {
34    MemorySource(const uint8_t *data, size_t size)
35        : mData(data),
36          mSize(size) {
37    }
38
39    virtual status_t initCheck() const {
40        return OK;
41    }
42
43    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
52private:
53    const uint8_t *mData;
54    size_t mSize;
55
56    DISALLOW_EVIL_CONSTRUCTORS(MemorySource);
57};
58
59ID3::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
73ID3::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
92ID3::~ID3() {
93    if (mData) {
94        free(mData);
95        mData = NULL;
96    }
97}
98
99bool ID3::isValid() const {
100    return mIsValid;
101}
102
103ID3::Version ID3::version() const {
104    return mVersion;
105}
106
107// static
108bool 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
121bool ID3::parseV2(const sp<DataSource> &source, off64_t offset) {
122struct 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
330void 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
339static 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
346bool 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
421ID3::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
434ID3::Iterator::~Iterator() {
435    if (mID) {
436        free(mID);
437        mID = NULL;
438    }
439}
440
441bool ID3::Iterator::done() const {
442    return mFrameData == NULL;
443}
444
445void ID3::Iterator::next() {
446    if (mFrameData == NULL) {
447        return;
448    }
449
450    mOffset += mFrameSize;
451
452    findFrame();
453}
454
455void 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
500void 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.
510void 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
648const 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
665size_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
676void 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
847static 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
863const void *
864ID3::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
958bool 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