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