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 29 namespace android { 30 31 static const size_t kMaxMetadataSize = 3 * 1024 * 1024; 32 33 struct 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 52 private: 53 const uint8_t *mData; 54 size_t mSize; 55 56 DISALLOW_EVIL_CONSTRUCTORS(MemorySource); 57 }; 58 59 ID3::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 73 ID3::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 92 ID3::~ID3() { 93 if (mData) { 94 free(mData); 95 mData = NULL; 96 } 97 } 98 99 bool ID3::isValid() const { 100 return mIsValid; 101 } 102 103 ID3::Version ID3::version() const { 104 return mVersion; 105 } 106 107 // static 108 bool 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 121 bool ID3::parseV2(const sp<DataSource> &source, off64_t offset) { 122 struct 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 330 void 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 339 static 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 346 bool 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) { 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 memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset); 399 400 flags &= ~2; 401 } 402 403 if (flags != prevFlags || iTunesHack) { 404 WriteSyncsafeInteger(&mData[offset + 4], dataSize); 405 mData[offset + 8] = flags >> 8; 406 mData[offset + 9] = flags & 0xff; 407 } 408 409 offset += 10 + dataSize; 410 } 411 412 memset(&mData[mSize], 0, oldSize - mSize); 413 414 return true; 415 } 416 417 ID3::Iterator::Iterator(const ID3 &parent, const char *id) 418 : mParent(parent), 419 mID(NULL), 420 mOffset(mParent.mFirstFrameOffset), 421 mFrameData(NULL), 422 mFrameSize(0) { 423 if (id) { 424 mID = strdup(id); 425 } 426 427 findFrame(); 428 } 429 430 ID3::Iterator::~Iterator() { 431 if (mID) { 432 free(mID); 433 mID = NULL; 434 } 435 } 436 437 bool ID3::Iterator::done() const { 438 return mFrameData == NULL; 439 } 440 441 void ID3::Iterator::next() { 442 if (mFrameData == NULL) { 443 return; 444 } 445 446 mOffset += mFrameSize; 447 448 findFrame(); 449 } 450 451 void ID3::Iterator::getID(String8 *id) const { 452 id->setTo(""); 453 454 if (mFrameData == NULL) { 455 return; 456 } 457 458 if (mParent.mVersion == ID3_V2_2) { 459 id->setTo((const char *)&mParent.mData[mOffset], 3); 460 } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) { 461 id->setTo((const char *)&mParent.mData[mOffset], 4); 462 } else { 463 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); 464 465 switch (mOffset) { 466 case 3: 467 id->setTo("TT2"); 468 break; 469 case 33: 470 id->setTo("TP1"); 471 break; 472 case 63: 473 id->setTo("TAL"); 474 break; 475 case 93: 476 id->setTo("TYE"); 477 break; 478 case 97: 479 id->setTo("COM"); 480 break; 481 case 126: 482 id->setTo("TRK"); 483 break; 484 case 127: 485 id->setTo("TCO"); 486 break; 487 default: 488 CHECK(!"should not be here."); 489 break; 490 } 491 } 492 } 493 494 495 // the 2nd argument is used to get the data following the \0 in a comment field 496 void ID3::Iterator::getString(String8 *id, String8 *comment) const { 497 getstring(id, false); 498 if (comment != NULL) { 499 getstring(comment, true); 500 } 501 } 502 503 // comment fields (COM/COMM) contain an initial short descriptor, followed by \0, 504 // followed by more data. The data following the \0 can be retrieved by setting 505 // "otherdata" to true. 506 void ID3::Iterator::getstring(String8 *id, bool otherdata) const { 507 id->setTo(""); 508 509 const uint8_t *frameData = mFrameData; 510 if (frameData == NULL) { 511 return; 512 } 513 514 uint8_t encoding = *frameData; 515 516 if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) { 517 if (mOffset == 126 || mOffset == 127) { 518 // Special treatment for the track number and genre. 519 char tmp[16]; 520 sprintf(tmp, "%d", (int)*frameData); 521 522 id->setTo(tmp); 523 return; 524 } 525 526 // this is supposed to be ISO-8859-1, but pass it up as-is to the caller, who will figure 527 // out the real encoding 528 id->setTo((const char*)frameData, mFrameSize); 529 return; 530 } 531 532 if (mFrameSize < getHeaderLength() + 1) { 533 return; 534 } 535 size_t n = mFrameSize - getHeaderLength() - 1; 536 if (otherdata) { 537 // skip past the encoding, language, and the 0 separator 538 frameData += 4; 539 int32_t i = n - 4; 540 while(--i >= 0 && *++frameData != 0) ; 541 int skipped = (frameData - mFrameData); 542 if (skipped >= (int)n) { 543 return; 544 } 545 n -= skipped; 546 } 547 548 if (n <= 0) { 549 return; 550 } 551 552 if (encoding == 0x00) { 553 // supposedly ISO 8859-1 554 id->setTo((const char*)frameData + 1, n); 555 } else if (encoding == 0x03) { 556 // supposedly UTF-8 557 id->setTo((const char *)(frameData + 1), n); 558 } else if (encoding == 0x02) { 559 // supposedly UTF-16 BE, no byte order mark. 560 // API wants number of characters, not number of bytes... 561 int len = n / 2; 562 const char16_t *framedata = (const char16_t *) (frameData + 1); 563 char16_t *framedatacopy = NULL; 564 #if BYTE_ORDER == LITTLE_ENDIAN 565 if (len > 0) { 566 framedatacopy = new (std::nothrow) char16_t[len]; 567 if (framedatacopy == NULL) { 568 return; 569 } 570 for (int i = 0; i < len; i++) { 571 framedatacopy[i] = bswap_16(framedata[i]); 572 } 573 framedata = framedatacopy; 574 } 575 #endif 576 id->setTo(framedata, len); 577 if (framedatacopy != NULL) { 578 delete[] framedatacopy; 579 } 580 } else if (encoding == 0x01) { 581 // UCS-2 582 // API wants number of characters, not number of bytes... 583 int len = n / 2; 584 const char16_t *framedata = (const char16_t *) (frameData + 1); 585 char16_t *framedatacopy = NULL; 586 if (*framedata == 0xfffe) { 587 // endianness marker != host endianness, convert & skip 588 if (len <= 1) { 589 return; // nothing after the marker 590 } 591 framedatacopy = new (std::nothrow) char16_t[len]; 592 if (framedatacopy == NULL) { 593 return; 594 } 595 for (int i = 0; i < len; i++) { 596 framedatacopy[i] = bswap_16(framedata[i]); 597 } 598 framedata = framedatacopy; 599 // and skip over the marker 600 framedata++; 601 len--; 602 } else if (*framedata == 0xfeff) { 603 // endianness marker == host endianness, skip it 604 if (len <= 1) { 605 return; // nothing after the marker 606 } 607 framedata++; 608 len--; 609 } 610 611 // check if the resulting data consists entirely of 8-bit values 612 bool eightBit = true; 613 for (int i = 0; i < len; i++) { 614 if (framedata[i] > 0xff) { 615 eightBit = false; 616 break; 617 } 618 } 619 if (eightBit) { 620 // collapse to 8 bit, then let the media scanner client figure out the real encoding 621 char *frame8 = new (std::nothrow) char[len]; 622 if (frame8 != NULL) { 623 for (int i = 0; i < len; i++) { 624 frame8[i] = framedata[i]; 625 } 626 id->setTo(frame8, len); 627 delete [] frame8; 628 } else { 629 id->setTo(framedata, len); 630 } 631 } else { 632 id->setTo(framedata, len); 633 } 634 635 if (framedatacopy != NULL) { 636 delete[] framedatacopy; 637 } 638 } 639 } 640 641 const uint8_t *ID3::Iterator::getData(size_t *length) const { 642 *length = 0; 643 644 if (mFrameData == NULL) { 645 return NULL; 646 } 647 648 // Prevent integer underflow 649 if (mFrameSize < getHeaderLength()) { 650 return NULL; 651 } 652 653 *length = mFrameSize - getHeaderLength(); 654 655 return mFrameData; 656 } 657 658 size_t ID3::Iterator::getHeaderLength() const { 659 if (mParent.mVersion == ID3_V2_2) { 660 return 6; 661 } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) { 662 return 10; 663 } else { 664 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); 665 return 0; 666 } 667 } 668 669 void ID3::Iterator::findFrame() { 670 for (;;) { 671 mFrameData = NULL; 672 mFrameSize = 0; 673 674 if (mParent.mVersion == ID3_V2_2) { 675 if (mOffset + 6 > mParent.mSize) { 676 return; 677 } 678 679 if (!memcmp(&mParent.mData[mOffset], "\0\0\0", 3)) { 680 return; 681 } 682 683 mFrameSize = 684 (mParent.mData[mOffset + 3] << 16) 685 | (mParent.mData[mOffset + 4] << 8) 686 | mParent.mData[mOffset + 5]; 687 688 if (mFrameSize == 0) { 689 return; 690 } 691 mFrameSize += 6; // add tag id and size field 692 693 // Prevent integer overflow in validation 694 if (SIZE_MAX - mOffset <= mFrameSize) { 695 return; 696 } 697 698 if (mOffset + mFrameSize > mParent.mSize) { 699 ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)", 700 mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)6); 701 return; 702 } 703 704 mFrameData = &mParent.mData[mOffset + 6]; 705 706 if (!mID) { 707 break; 708 } 709 710 char id[4]; 711 memcpy(id, &mParent.mData[mOffset], 3); 712 id[3] = '\0'; 713 714 if (!strcmp(id, mID)) { 715 break; 716 } 717 } else if (mParent.mVersion == ID3_V2_3 718 || mParent.mVersion == ID3_V2_4) { 719 if (mOffset + 10 > mParent.mSize) { 720 return; 721 } 722 723 if (!memcmp(&mParent.mData[mOffset], "\0\0\0\0", 4)) { 724 return; 725 } 726 727 size_t baseSize = 0; 728 if (mParent.mVersion == ID3_V2_4) { 729 if (!ParseSyncsafeInteger( 730 &mParent.mData[mOffset + 4], &baseSize)) { 731 return; 732 } 733 } else { 734 baseSize = U32_AT(&mParent.mData[mOffset + 4]); 735 } 736 737 if (baseSize == 0) { 738 return; 739 } 740 741 // Prevent integer overflow when adding 742 if (SIZE_MAX - 10 <= baseSize) { 743 return; 744 } 745 746 mFrameSize = 10 + baseSize; // add tag id, size field and flags 747 748 // Prevent integer overflow in validation 749 if (SIZE_MAX - mOffset <= mFrameSize) { 750 return; 751 } 752 753 if (mOffset + mFrameSize > mParent.mSize) { 754 ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)", 755 mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)10); 756 return; 757 } 758 759 uint16_t flags = U16_AT(&mParent.mData[mOffset + 8]); 760 761 if ((mParent.mVersion == ID3_V2_4 && (flags & 0x000c)) 762 || (mParent.mVersion == ID3_V2_3 && (flags & 0x00c0))) { 763 // Compression or encryption are not supported at this time. 764 // Per-frame unsynchronization and data-length indicator 765 // have already been taken care of. 766 767 ALOGV("Skipping unsupported frame (compression, encryption " 768 "or per-frame unsynchronization flagged"); 769 770 mOffset += mFrameSize; 771 continue; 772 } 773 774 mFrameData = &mParent.mData[mOffset + 10]; 775 776 if (!mID) { 777 break; 778 } 779 780 char id[5]; 781 memcpy(id, &mParent.mData[mOffset], 4); 782 id[4] = '\0'; 783 784 if (!strcmp(id, mID)) { 785 break; 786 } 787 } else { 788 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); 789 790 if (mOffset >= mParent.mSize) { 791 return; 792 } 793 794 mFrameData = &mParent.mData[mOffset]; 795 796 switch (mOffset) { 797 case 3: 798 case 33: 799 case 63: 800 mFrameSize = 30; 801 break; 802 case 93: 803 mFrameSize = 4; 804 break; 805 case 97: 806 if (mParent.mVersion == ID3_V1) { 807 mFrameSize = 30; 808 } else { 809 mFrameSize = 29; 810 } 811 break; 812 case 126: 813 mFrameSize = 1; 814 break; 815 case 127: 816 mFrameSize = 1; 817 break; 818 default: 819 CHECK(!"Should not be here, invalid offset."); 820 break; 821 } 822 823 if (!mID) { 824 break; 825 } 826 827 String8 id; 828 getID(&id); 829 830 if (id == mID) { 831 break; 832 } 833 } 834 835 mOffset += mFrameSize; 836 } 837 } 838 839 static size_t StringSize(const uint8_t *start, uint8_t encoding) { 840 if (encoding == 0x00 || encoding == 0x03) { 841 // ISO 8859-1 or UTF-8 842 return strlen((const char *)start) + 1; 843 } 844 845 // UCS-2 846 size_t n = 0; 847 while (start[n] != '\0' || start[n + 1] != '\0') { 848 n += 2; 849 } 850 851 // Add size of null termination. 852 return n + 2; 853 } 854 855 const void * 856 ID3::getAlbumArt(size_t *length, String8 *mime) const { 857 *length = 0; 858 mime->setTo(""); 859 860 Iterator it( 861 *this, 862 (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) ? "APIC" : "PIC"); 863 864 while (!it.done()) { 865 size_t size; 866 const uint8_t *data = it.getData(&size); 867 if (!data) { 868 return NULL; 869 } 870 871 if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) { 872 uint8_t encoding = data[0]; 873 mime->setTo((const char *)&data[1]); 874 size_t mimeLen = strlen((const char *)&data[1]) + 1; 875 876 #if 0 877 uint8_t picType = data[1 + mimeLen]; 878 if (picType != 0x03) { 879 // Front Cover Art 880 it.next(); 881 continue; 882 } 883 #endif 884 885 size_t descLen = StringSize(&data[2 + mimeLen], encoding); 886 887 if (size < 2 || 888 size - 2 < mimeLen || 889 size - 2 - mimeLen < descLen) { 890 ALOGW("bogus album art sizes"); 891 return NULL; 892 } 893 *length = size - 2 - mimeLen - descLen; 894 895 return &data[2 + mimeLen + descLen]; 896 } else { 897 uint8_t encoding = data[0]; 898 899 if (!memcmp(&data[1], "PNG", 3)) { 900 mime->setTo("image/png"); 901 } else if (!memcmp(&data[1], "JPG", 3)) { 902 mime->setTo("image/jpeg"); 903 } else if (!memcmp(&data[1], "-->", 3)) { 904 mime->setTo("text/plain"); 905 } else { 906 return NULL; 907 } 908 909 #if 0 910 uint8_t picType = data[4]; 911 if (picType != 0x03) { 912 // Front Cover Art 913 it.next(); 914 continue; 915 } 916 #endif 917 918 size_t descLen = StringSize(&data[5], encoding); 919 920 *length = size - 5 - descLen; 921 922 return &data[5 + descLen]; 923 } 924 } 925 926 return NULL; 927 } 928 929 bool ID3::parseV1(const sp<DataSource> &source) { 930 const size_t V1_TAG_SIZE = 128; 931 932 off64_t size; 933 if (source->getSize(&size) != OK || size < (off64_t)V1_TAG_SIZE) { 934 return false; 935 } 936 937 mData = (uint8_t *)malloc(V1_TAG_SIZE); 938 if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE) 939 != (ssize_t)V1_TAG_SIZE) { 940 free(mData); 941 mData = NULL; 942 943 return false; 944 } 945 946 if (memcmp("TAG", mData, 3)) { 947 free(mData); 948 mData = NULL; 949 950 return false; 951 } 952 953 mSize = V1_TAG_SIZE; 954 mFirstFrameOffset = 3; 955 956 if (mData[V1_TAG_SIZE - 3] != 0) { 957 mVersion = ID3_V1; 958 } else { 959 mVersion = ID3_V1_1; 960 } 961 962 return true; 963 } 964 965 } // namespace android 966