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