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