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