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