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