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