Home | History | Annotate | Download | only in id3
      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 {
     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 
     52 private:
     53     const uint8_t *mData;
     54     size_t mSize;
     55 
     56     DISALLOW_EVIL_CONSTRUCTORS(MemorySource);
     57 };
     58 
     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 
     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 
     92 ID3::~ID3() {
     93     if (mData) {
     94         free(mData);
     95         mData = NULL;
     96     }
     97 }
     98 
     99 bool ID3::isValid() const {
    100     return mIsValid;
    101 }
    102 
    103 ID3::Version ID3::version() const {
    104     return mVersion;
    105 }
    106 
    107 // static
    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 
    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 
    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 
    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 
    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 
    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 
    430 ID3::Iterator::~Iterator() {
    431     if (mID) {
    432         free(mID);
    433         mID = NULL;
    434     }
    435 }
    436 
    437 bool ID3::Iterator::done() const {
    438     return mFrameData == NULL;
    439 }
    440 
    441 void ID3::Iterator::next() {
    442     if (mFrameData == NULL) {
    443         return;
    444     }
    445 
    446     mOffset += mFrameSize;
    447 
    448     findFrame();
    449 }
    450 
    451 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
    496 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.
    506 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 
    641 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 
    658 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 
    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 
    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 *
    856 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 
    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