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