ID3.cpp revision 5a2621a64de196cbdb9a2a50357dee1c32fcf11b
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/DataSource.h>
24#include <media/stagefright/MediaDebug.h>
25#include <media/stagefright/Utils.h>
26#include <utils/String8.h>
27#include <sys/endian.h>
28
29namespace android {
30
31ID3::ID3(const sp<DataSource> &source)
32    : mIsValid(false),
33      mData(NULL),
34      mSize(0),
35      mFirstFrameOffset(0),
36      mVersion(ID3_UNKNOWN) {
37    mIsValid = parseV2(source);
38
39    if (!mIsValid) {
40        mIsValid = parseV1(source);
41    }
42}
43
44ID3::~ID3() {
45    if (mData) {
46        free(mData);
47        mData = NULL;
48    }
49}
50
51bool ID3::isValid() const {
52    return mIsValid;
53}
54
55ID3::Version ID3::version() const {
56    return mVersion;
57}
58
59bool ID3::parseV2(const sp<DataSource> &source) {
60    struct id3_header {
61        char id[3];
62        uint8_t version_major;
63        uint8_t version_minor;
64        uint8_t flags;
65        uint8_t enc_size[4];
66    };
67
68    id3_header header;
69    if (source->readAt(
70                0, &header, sizeof(header)) != (ssize_t)sizeof(header)) {
71        return false;
72    }
73
74    if (memcmp(header.id, "ID3", 3)) {
75        return false;
76    }
77
78    if (header.version_major == 0xff || header.version_minor == 0xff) {
79        return false;
80    }
81
82    if (header.version_major == 2) {
83        if (header.flags & 0x3f) {
84            // We only support the 2 high bits, if any of the lower bits are
85            // set, we cannot guarantee to understand the tag format.
86            return false;
87        }
88
89        if (header.flags & 0x40) {
90            // No compression scheme has been decided yet, ignore the
91            // tag if compression is indicated.
92
93            return false;
94        }
95    } else if (header.version_major == 3) {
96        if (header.flags & 0x1f) {
97            // We only support the 3 high bits, if any of the lower bits are
98            // set, we cannot guarantee to understand the tag format.
99            return false;
100        }
101    } else {
102        return false;
103    }
104
105    size_t size = 0;
106    for (int32_t i = 0; i < 4; ++i) {
107        if (header.enc_size[i] & 0x80) {
108            return false;
109        }
110
111        size = (size << 7) | header.enc_size[i];
112    }
113
114    mData = (uint8_t *)malloc(size);
115
116    if (mData == NULL) {
117        return false;
118    }
119
120    mSize = size;
121
122    if (source->readAt(sizeof(header), mData, mSize) != (ssize_t)mSize) {
123        return false;
124    }
125
126    if (header.flags & 0x80) {
127        LOGV("removing unsynchronization");
128        removeUnsynchronization();
129    }
130
131    mFirstFrameOffset = 0;
132    if (header.version_major == 3 && (header.flags & 0x40)) {
133        // Version 2.3 has an optional extended header.
134
135        if (mSize < 4) {
136            free(mData);
137            mData = NULL;
138
139            return false;
140        }
141
142        size_t extendedHeaderSize = U32_AT(&mData[0]) + 4;
143
144        if (extendedHeaderSize > mSize) {
145            free(mData);
146            mData = NULL;
147
148            return false;
149        }
150
151        mFirstFrameOffset = extendedHeaderSize;
152
153        uint16_t extendedFlags = 0;
154        if (extendedHeaderSize >= 6) {
155            extendedFlags = U16_AT(&mData[4]);
156
157            if (extendedHeaderSize >= 10) {
158                size_t paddingSize = U32_AT(&mData[6]);
159
160                if (mFirstFrameOffset + paddingSize > mSize) {
161                    free(mData);
162                    mData = NULL;
163
164                    return false;
165                }
166
167                mSize -= paddingSize;
168            }
169
170            if (extendedFlags & 0x8000) {
171                LOGV("have crc");
172            }
173        }
174    }
175
176    if (header.version_major == 2) {
177        mVersion = ID3_V2_2;
178    } else {
179        CHECK_EQ(header.version_major, 3);
180        mVersion = ID3_V2_3;
181    }
182
183    return true;
184}
185
186void ID3::removeUnsynchronization() {
187    for (size_t i = 0; i + 1 < mSize; ++i) {
188        if (mData[i] == 0xff && mData[i + 1] == 0x00) {
189            memmove(&mData[i + 1], &mData[i + 2], mSize - i - 2);
190            --mSize;
191        }
192    }
193}
194
195ID3::Iterator::Iterator(const ID3 &parent, const char *id)
196    : mParent(parent),
197      mID(NULL),
198      mOffset(mParent.mFirstFrameOffset),
199      mFrameData(NULL),
200      mFrameSize(0) {
201    if (id) {
202        mID = strdup(id);
203    }
204
205    findFrame();
206}
207
208ID3::Iterator::~Iterator() {
209    if (mID) {
210        free(mID);
211        mID = NULL;
212    }
213}
214
215bool ID3::Iterator::done() const {
216    return mFrameData == NULL;
217}
218
219void ID3::Iterator::next() {
220    if (mFrameData == NULL) {
221        return;
222    }
223
224    mOffset += mFrameSize;
225
226    findFrame();
227}
228
229void ID3::Iterator::getID(String8 *id) const {
230    id->setTo("");
231
232    if (mFrameData == NULL) {
233        return;
234    }
235
236    if (mParent.mVersion == ID3_V2_2) {
237        id->setTo((const char *)&mParent.mData[mOffset], 3);
238    } else if (mParent.mVersion == ID3_V2_3) {
239        id->setTo((const char *)&mParent.mData[mOffset], 4);
240    } else {
241        CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
242
243        switch (mOffset) {
244            case 3:
245                id->setTo("TT2");
246                break;
247            case 33:
248                id->setTo("TP1");
249                break;
250            case 63:
251                id->setTo("TAL");
252                break;
253            case 93:
254                id->setTo("TYE");
255                break;
256            case 97:
257                id->setTo("COM");
258                break;
259            case 126:
260                id->setTo("TRK");
261                break;
262            case 127:
263                id->setTo("TCO");
264                break;
265            default:
266                CHECK(!"should not be here.");
267                break;
268        }
269    }
270}
271
272static void convertISO8859ToString8(
273        const uint8_t *data, size_t size,
274        String8 *s) {
275    size_t utf8len = 0;
276    for (size_t i = 0; i < size; ++i) {
277        if (data[i] < 0x80) {
278            ++utf8len;
279        } else {
280            utf8len += 2;
281        }
282    }
283
284    if (utf8len == size) {
285        // Only ASCII characters present.
286
287        s->setTo((const char *)data, size);
288        return;
289    }
290
291    char *tmp = new char[utf8len];
292    char *ptr = tmp;
293    for (size_t i = 0; i < size; ++i) {
294        if (data[i] < 0x80) {
295            *ptr++ = data[i];
296        } else if (data[i] < 0xc0) {
297            *ptr++ = 0xc2;
298            *ptr++ = data[i];
299        } else {
300            *ptr++ = 0xc3;
301            *ptr++ = data[i] - 64;
302        }
303    }
304
305    s->setTo(tmp, utf8len);
306
307    delete[] tmp;
308    tmp = NULL;
309}
310
311void ID3::Iterator::getString(String8 *id) const {
312    id->setTo("");
313
314    if (mFrameData == NULL) {
315        return;
316    }
317
318    if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
319        if (mOffset == 126 || mOffset == 127) {
320            // Special treatment for the track number and genre.
321            char tmp[16];
322            sprintf(tmp, "%d", (int)*mFrameData);
323
324            id->setTo(tmp);
325            return;
326        }
327
328        id->setTo((const char *)mFrameData, mFrameSize);
329        return;
330    }
331
332    size_t n = mFrameSize - getHeaderLength() - 1;
333
334    if (*mFrameData == 0x00) {
335        // ISO 8859-1
336        convertISO8859ToString8(mFrameData + 1, n, id);
337    } else {
338        // UCS-2
339        // API wants number of characters, not number of bytes...
340        int len = n / 2;
341        const char16_t *framedata = (const char16_t *) (mFrameData + 1);
342        char16_t *framedatacopy = NULL;
343        if (*framedata == 0xfffe) {
344            // endianness marker doesn't match host endianness, convert
345            framedatacopy = new char16_t[len];
346            for (int i = 0; i < len; i++) {
347                framedatacopy[i] = swap16(framedata[i]);
348            }
349            framedata = framedatacopy;
350        }
351        // If the string starts with an endianness marker, skip it
352        if (*framedata == 0xfeff) {
353            framedata++;
354            len--;
355        }
356        id->setTo(framedata, len);
357        if (framedatacopy != NULL) {
358            delete[] framedatacopy;
359        }
360    }
361}
362
363const uint8_t *ID3::Iterator::getData(size_t *length) const {
364    *length = 0;
365
366    if (mFrameData == NULL) {
367        return NULL;
368    }
369
370    *length = mFrameSize - getHeaderLength();
371
372    return mFrameData;
373}
374
375size_t ID3::Iterator::getHeaderLength() const {
376    if (mParent.mVersion == ID3_V2_2) {
377        return 6;
378    } else if (mParent.mVersion == ID3_V2_3) {
379        return 10;
380    } else {
381        CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
382        return 0;
383    }
384}
385
386void ID3::Iterator::findFrame() {
387    for (;;) {
388        mFrameData = NULL;
389        mFrameSize = 0;
390
391        if (mParent.mVersion == ID3_V2_2) {
392            if (mOffset + 6 > mParent.mSize) {
393                return;
394            }
395
396            if (!memcmp(&mParent.mData[mOffset], "\0\0\0", 3)) {
397                return;
398            }
399
400            mFrameSize =
401                (mParent.mData[mOffset + 3] << 16)
402                | (mParent.mData[mOffset + 4] << 8)
403                | mParent.mData[mOffset + 5];
404
405            mFrameSize += 6;
406
407            if (mOffset + mFrameSize > mParent.mSize) {
408                LOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)",
409                     mOffset, mFrameSize, mParent.mSize - mOffset - 6);
410                return;
411            }
412
413            mFrameData = &mParent.mData[mOffset + 6];
414
415            if (!mID) {
416                break;
417            }
418
419            char id[4];
420            memcpy(id, &mParent.mData[mOffset], 3);
421            id[3] = '\0';
422
423            if (!strcmp(id, mID)) {
424                break;
425            }
426        } else if (mParent.mVersion == ID3_V2_3) {
427            if (mOffset + 10 > mParent.mSize) {
428                return;
429            }
430
431            if (!memcmp(&mParent.mData[mOffset], "\0\0\0\0", 4)) {
432                return;
433            }
434
435            mFrameSize = 10 + U32_AT(&mParent.mData[mOffset + 4]);
436
437            if (mOffset + mFrameSize > mParent.mSize) {
438                LOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)",
439                     mOffset, mFrameSize, mParent.mSize - mOffset - 10);
440                return;
441            }
442
443            mFrameData = &mParent.mData[mOffset + 10];
444
445            if (!mID) {
446                break;
447            }
448
449            char id[5];
450            memcpy(id, &mParent.mData[mOffset], 4);
451            id[4] = '\0';
452
453            if (!strcmp(id, mID)) {
454                break;
455            }
456        } else {
457            CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
458
459            if (mOffset >= mParent.mSize) {
460                return;
461            }
462
463            mFrameData = &mParent.mData[mOffset];
464
465            switch (mOffset) {
466                case 3:
467                case 33:
468                case 63:
469                    mFrameSize = 30;
470                    break;
471                case 93:
472                    mFrameSize = 4;
473                    break;
474                case 97:
475                    if (mParent.mVersion == ID3_V1) {
476                        mFrameSize = 30;
477                    } else {
478                        mFrameSize = 29;
479                    }
480                    break;
481                case 126:
482                    mFrameSize = 1;
483                    break;
484                case 127:
485                    mFrameSize = 1;
486                    break;
487                default:
488                    CHECK(!"Should not be here, invalid offset.");
489                    break;
490            }
491
492            if (!mID) {
493                break;
494            }
495
496            String8 id;
497            getID(&id);
498
499            if (id == mID) {
500                break;
501            }
502        }
503
504        mOffset += mFrameSize;
505    }
506}
507
508static size_t StringSize(const uint8_t *start, uint8_t encoding) {
509    if (encoding== 0x00) {
510        // ISO 8859-1
511        return strlen((const char *)start) + 1;
512    }
513
514    // UCS-2
515    size_t n = 0;
516    while (start[n] != '\0' || start[n + 1] != '\0') {
517        n += 2;
518    }
519
520    return n;
521}
522
523const void *
524ID3::getAlbumArt(size_t *length, String8 *mime) const {
525    *length = 0;
526    mime->setTo("");
527
528    Iterator it(*this, mVersion == ID3_V2_3 ? "APIC" : "PIC");
529
530    while (!it.done()) {
531        size_t size;
532        const uint8_t *data = it.getData(&size);
533
534        if (mVersion == ID3_V2_3) {
535            uint8_t encoding = data[0];
536            mime->setTo((const char *)&data[1]);
537            size_t mimeLen = strlen((const char *)&data[1]) + 1;
538
539            uint8_t picType = data[1 + mimeLen];
540#if 0
541            if (picType != 0x03) {
542                // Front Cover Art
543                it.next();
544                continue;
545            }
546#endif
547
548            size_t descLen = StringSize(&data[2 + mimeLen], encoding);
549
550            *length = size - 2 - mimeLen - descLen;
551
552            return &data[2 + mimeLen + descLen];
553        } else {
554            uint8_t encoding = data[0];
555
556            if (!memcmp(&data[1], "PNG", 3)) {
557                mime->setTo("image/png");
558            } else if (!memcmp(&data[1], "JPG", 3)) {
559                mime->setTo("image/jpeg");
560            } else if (!memcmp(&data[1], "-->", 3)) {
561                mime->setTo("text/plain");
562            } else {
563                return NULL;
564            }
565
566#if 0
567            uint8_t picType = data[4];
568            if (picType != 0x03) {
569                // Front Cover Art
570                it.next();
571                continue;
572            }
573#endif
574
575            size_t descLen = StringSize(&data[5], encoding);
576
577            *length = size - 5 - descLen;
578
579            return &data[5 + descLen];
580        }
581    }
582
583    return NULL;
584}
585
586bool ID3::parseV1(const sp<DataSource> &source) {
587    const size_t V1_TAG_SIZE = 128;
588
589    off_t size;
590    if (source->getSize(&size) != OK || size < (off_t)V1_TAG_SIZE) {
591        return false;
592    }
593
594    mData = (uint8_t *)malloc(V1_TAG_SIZE);
595    if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE)
596            != (ssize_t)V1_TAG_SIZE) {
597        free(mData);
598        mData = NULL;
599
600        return false;
601    }
602
603    if (memcmp("TAG", mData, 3)) {
604        free(mData);
605        mData = NULL;
606
607        return false;
608    }
609
610    mSize = V1_TAG_SIZE;
611    mFirstFrameOffset = 3;
612
613    if (mData[V1_TAG_SIZE - 3] != 0) {
614        mVersion = ID3_V1;
615    } else {
616        mVersion = ID3_V1_1;
617    }
618
619    return true;
620}
621
622}  // namespace android
623