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