ID3.cpp revision 632a7dfdab89ffa79846ad37718d0582fd36affe
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/DataSource.h> 24#include <media/stagefright/MediaDebug.h> 25#include <media/stagefright/Utils.h> 26#include <utils/String8.h> 27#include <byteswap.h> 28 29namespace android { 30 31ID3::ID3(const sp<DataSource> &source) 32 : mIsValid(false), 33 mData(NULL), 34 mSize(0), 35 mFirstFrameOffset(0), 36 mVersion(ID3_UNKNOWN) { 37 mIsValid = parseV2(source); 38 39 if (!mIsValid) { 40 mIsValid = parseV1(source); 41 } 42} 43 44ID3::~ID3() { 45 if (mData) { 46 free(mData); 47 mData = NULL; 48 } 49} 50 51bool ID3::isValid() const { 52 return mIsValid; 53} 54 55ID3::Version ID3::version() const { 56 return mVersion; 57} 58 59bool ID3::parseV2(const sp<DataSource> &source) { 60 struct id3_header { 61 char id[3]; 62 uint8_t version_major; 63 uint8_t version_minor; 64 uint8_t flags; 65 uint8_t enc_size[4]; 66 }; 67 68 id3_header header; 69 if (source->readAt( 70 0, &header, sizeof(header)) != (ssize_t)sizeof(header)) { 71 return false; 72 } 73 74 if (memcmp(header.id, "ID3", 3)) { 75 return false; 76 } 77 78 if (header.version_major == 0xff || header.version_minor == 0xff) { 79 return false; 80 } 81 82 if (header.version_major == 2) { 83 if (header.flags & 0x3f) { 84 // We only support the 2 high bits, if any of the lower bits are 85 // set, we cannot guarantee to understand the tag format. 86 return false; 87 } 88 89 if (header.flags & 0x40) { 90 // No compression scheme has been decided yet, ignore the 91 // tag if compression is indicated. 92 93 return false; 94 } 95 } else if (header.version_major == 3) { 96 if (header.flags & 0x1f) { 97 // We only support the 3 high bits, if any of the lower bits are 98 // set, we cannot guarantee to understand the tag format. 99 return false; 100 } 101 } else { 102 return false; 103 } 104 105 size_t size = 0; 106 for (int32_t i = 0; i < 4; ++i) { 107 if (header.enc_size[i] & 0x80) { 108 return false; 109 } 110 111 size = (size << 7) | header.enc_size[i]; 112 } 113 114 mData = (uint8_t *)malloc(size); 115 116 if (mData == NULL) { 117 return false; 118 } 119 120 mSize = size; 121 122 if (source->readAt(sizeof(header), mData, mSize) != (ssize_t)mSize) { 123 return false; 124 } 125 126 if (header.flags & 0x80) { 127 LOGV("removing unsynchronization"); 128 removeUnsynchronization(); 129 } 130 131 mFirstFrameOffset = 0; 132 if (header.version_major == 3 && (header.flags & 0x40)) { 133 // Version 2.3 has an optional extended header. 134 135 if (mSize < 4) { 136 free(mData); 137 mData = NULL; 138 139 return false; 140 } 141 142 size_t extendedHeaderSize = U32_AT(&mData[0]) + 4; 143 144 if (extendedHeaderSize > mSize) { 145 free(mData); 146 mData = NULL; 147 148 return false; 149 } 150 151 mFirstFrameOffset = extendedHeaderSize; 152 153 uint16_t extendedFlags = 0; 154 if (extendedHeaderSize >= 6) { 155 extendedFlags = U16_AT(&mData[4]); 156 157 if (extendedHeaderSize >= 10) { 158 size_t paddingSize = U32_AT(&mData[6]); 159 160 if (mFirstFrameOffset + paddingSize > mSize) { 161 free(mData); 162 mData = NULL; 163 164 return false; 165 } 166 167 mSize -= paddingSize; 168 } 169 170 if (extendedFlags & 0x8000) { 171 LOGV("have crc"); 172 } 173 } 174 } 175 176 if (header.version_major == 2) { 177 mVersion = ID3_V2_2; 178 } else { 179 CHECK_EQ(header.version_major, 3); 180 mVersion = ID3_V2_3; 181 } 182 183 return true; 184} 185 186void ID3::removeUnsynchronization() { 187 for (size_t i = 0; i + 1 < mSize; ++i) { 188 if (mData[i] == 0xff && mData[i + 1] == 0x00) { 189 memmove(&mData[i + 1], &mData[i + 2], mSize - i - 2); 190 --mSize; 191 } 192 } 193} 194 195ID3::Iterator::Iterator(const ID3 &parent, const char *id) 196 : mParent(parent), 197 mID(NULL), 198 mOffset(mParent.mFirstFrameOffset), 199 mFrameData(NULL), 200 mFrameSize(0) { 201 if (id) { 202 mID = strdup(id); 203 } 204 205 findFrame(); 206} 207 208ID3::Iterator::~Iterator() { 209 if (mID) { 210 free(mID); 211 mID = NULL; 212 } 213} 214 215bool ID3::Iterator::done() const { 216 return mFrameData == NULL; 217} 218 219void ID3::Iterator::next() { 220 if (mFrameData == NULL) { 221 return; 222 } 223 224 mOffset += mFrameSize; 225 226 findFrame(); 227} 228 229void ID3::Iterator::getID(String8 *id) const { 230 id->setTo(""); 231 232 if (mFrameData == NULL) { 233 return; 234 } 235 236 if (mParent.mVersion == ID3_V2_2) { 237 id->setTo((const char *)&mParent.mData[mOffset], 3); 238 } else if (mParent.mVersion == ID3_V2_3) { 239 id->setTo((const char *)&mParent.mData[mOffset], 4); 240 } else { 241 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); 242 243 switch (mOffset) { 244 case 3: 245 id->setTo("TT2"); 246 break; 247 case 33: 248 id->setTo("TP1"); 249 break; 250 case 63: 251 id->setTo("TAL"); 252 break; 253 case 93: 254 id->setTo("TYE"); 255 break; 256 case 97: 257 id->setTo("COM"); 258 break; 259 case 126: 260 id->setTo("TRK"); 261 break; 262 case 127: 263 id->setTo("TCO"); 264 break; 265 default: 266 CHECK(!"should not be here."); 267 break; 268 } 269 } 270} 271 272static void convertISO8859ToString8( 273 const uint8_t *data, size_t size, 274 String8 *s) { 275 size_t utf8len = 0; 276 for (size_t i = 0; i < size; ++i) { 277 if (data[i] == '\0') { 278 size = i; 279 break; 280 } else if (data[i] < 0x80) { 281 ++utf8len; 282 } else { 283 utf8len += 2; 284 } 285 } 286 287 if (utf8len == size) { 288 // Only ASCII characters present. 289 290 s->setTo((const char *)data, size); 291 return; 292 } 293 294 char *tmp = new char[utf8len]; 295 char *ptr = tmp; 296 for (size_t i = 0; i < size; ++i) { 297 if (data[i] == '\0') { 298 break; 299 } else if (data[i] < 0x80) { 300 *ptr++ = data[i]; 301 } else if (data[i] < 0xc0) { 302 *ptr++ = 0xc2; 303 *ptr++ = data[i]; 304 } else { 305 *ptr++ = 0xc3; 306 *ptr++ = data[i] - 64; 307 } 308 } 309 310 s->setTo(tmp, utf8len); 311 312 delete[] tmp; 313 tmp = NULL; 314} 315 316void ID3::Iterator::getString(String8 *id) const { 317 id->setTo(""); 318 319 if (mFrameData == NULL) { 320 return; 321 } 322 323 if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) { 324 if (mOffset == 126 || mOffset == 127) { 325 // Special treatment for the track number and genre. 326 char tmp[16]; 327 sprintf(tmp, "%d", (int)*mFrameData); 328 329 id->setTo(tmp); 330 return; 331 } 332 333 convertISO8859ToString8(mFrameData, mFrameSize, id); 334 return; 335 } 336 337 size_t n = mFrameSize - getHeaderLength() - 1; 338 339 if (*mFrameData == 0x00) { 340 // ISO 8859-1 341 convertISO8859ToString8(mFrameData + 1, n, id); 342 } else { 343 // UCS-2 344 // API wants number of characters, not number of bytes... 345 int len = n / 2; 346 const char16_t *framedata = (const char16_t *) (mFrameData + 1); 347 char16_t *framedatacopy = NULL; 348 if (*framedata == 0xfffe) { 349 // endianness marker doesn't match host endianness, convert 350 framedatacopy = new char16_t[len]; 351 for (int i = 0; i < len; i++) { 352 framedatacopy[i] = bswap_16(framedata[i]); 353 } 354 framedata = framedatacopy; 355 } 356 // If the string starts with an endianness marker, skip it 357 if (*framedata == 0xfeff) { 358 framedata++; 359 len--; 360 } 361 id->setTo(framedata, len); 362 if (framedatacopy != NULL) { 363 delete[] framedatacopy; 364 } 365 } 366} 367 368const uint8_t *ID3::Iterator::getData(size_t *length) const { 369 *length = 0; 370 371 if (mFrameData == NULL) { 372 return NULL; 373 } 374 375 *length = mFrameSize - getHeaderLength(); 376 377 return mFrameData; 378} 379 380size_t ID3::Iterator::getHeaderLength() const { 381 if (mParent.mVersion == ID3_V2_2) { 382 return 6; 383 } else if (mParent.mVersion == ID3_V2_3) { 384 return 10; 385 } else { 386 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); 387 return 0; 388 } 389} 390 391void ID3::Iterator::findFrame() { 392 for (;;) { 393 mFrameData = NULL; 394 mFrameSize = 0; 395 396 if (mParent.mVersion == ID3_V2_2) { 397 if (mOffset + 6 > mParent.mSize) { 398 return; 399 } 400 401 if (!memcmp(&mParent.mData[mOffset], "\0\0\0", 3)) { 402 return; 403 } 404 405 mFrameSize = 406 (mParent.mData[mOffset + 3] << 16) 407 | (mParent.mData[mOffset + 4] << 8) 408 | mParent.mData[mOffset + 5]; 409 410 mFrameSize += 6; 411 412 if (mOffset + mFrameSize > mParent.mSize) { 413 LOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)", 414 mOffset, mFrameSize, mParent.mSize - mOffset - 6); 415 return; 416 } 417 418 mFrameData = &mParent.mData[mOffset + 6]; 419 420 if (!mID) { 421 break; 422 } 423 424 char id[4]; 425 memcpy(id, &mParent.mData[mOffset], 3); 426 id[3] = '\0'; 427 428 if (!strcmp(id, mID)) { 429 break; 430 } 431 } else if (mParent.mVersion == ID3_V2_3) { 432 if (mOffset + 10 > mParent.mSize) { 433 return; 434 } 435 436 if (!memcmp(&mParent.mData[mOffset], "\0\0\0\0", 4)) { 437 return; 438 } 439 440 mFrameSize = 10 + U32_AT(&mParent.mData[mOffset + 4]); 441 442 if (mOffset + mFrameSize > mParent.mSize) { 443 LOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)", 444 mOffset, mFrameSize, mParent.mSize - mOffset - 10); 445 return; 446 } 447 448 mFrameData = &mParent.mData[mOffset + 10]; 449 450 if (!mID) { 451 break; 452 } 453 454 char id[5]; 455 memcpy(id, &mParent.mData[mOffset], 4); 456 id[4] = '\0'; 457 458 if (!strcmp(id, mID)) { 459 break; 460 } 461 } else { 462 CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); 463 464 if (mOffset >= mParent.mSize) { 465 return; 466 } 467 468 mFrameData = &mParent.mData[mOffset]; 469 470 switch (mOffset) { 471 case 3: 472 case 33: 473 case 63: 474 mFrameSize = 30; 475 break; 476 case 93: 477 mFrameSize = 4; 478 break; 479 case 97: 480 if (mParent.mVersion == ID3_V1) { 481 mFrameSize = 30; 482 } else { 483 mFrameSize = 29; 484 } 485 break; 486 case 126: 487 mFrameSize = 1; 488 break; 489 case 127: 490 mFrameSize = 1; 491 break; 492 default: 493 CHECK(!"Should not be here, invalid offset."); 494 break; 495 } 496 497 if (!mID) { 498 break; 499 } 500 501 String8 id; 502 getID(&id); 503 504 if (id == mID) { 505 break; 506 } 507 } 508 509 mOffset += mFrameSize; 510 } 511} 512 513static size_t StringSize(const uint8_t *start, uint8_t encoding) { 514 if (encoding== 0x00) { 515 // ISO 8859-1 516 return strlen((const char *)start) + 1; 517 } 518 519 // UCS-2 520 size_t n = 0; 521 while (start[n] != '\0' || start[n + 1] != '\0') { 522 n += 2; 523 } 524 525 return n; 526} 527 528const void * 529ID3::getAlbumArt(size_t *length, String8 *mime) const { 530 *length = 0; 531 mime->setTo(""); 532 533 Iterator it(*this, mVersion == ID3_V2_3 ? "APIC" : "PIC"); 534 535 while (!it.done()) { 536 size_t size; 537 const uint8_t *data = it.getData(&size); 538 539 if (mVersion == ID3_V2_3) { 540 uint8_t encoding = data[0]; 541 mime->setTo((const char *)&data[1]); 542 size_t mimeLen = strlen((const char *)&data[1]) + 1; 543 544 uint8_t picType = data[1 + mimeLen]; 545#if 0 546 if (picType != 0x03) { 547 // Front Cover Art 548 it.next(); 549 continue; 550 } 551#endif 552 553 size_t descLen = StringSize(&data[2 + mimeLen], encoding); 554 555 *length = size - 2 - mimeLen - descLen; 556 557 return &data[2 + mimeLen + descLen]; 558 } else { 559 uint8_t encoding = data[0]; 560 561 if (!memcmp(&data[1], "PNG", 3)) { 562 mime->setTo("image/png"); 563 } else if (!memcmp(&data[1], "JPG", 3)) { 564 mime->setTo("image/jpeg"); 565 } else if (!memcmp(&data[1], "-->", 3)) { 566 mime->setTo("text/plain"); 567 } else { 568 return NULL; 569 } 570 571#if 0 572 uint8_t picType = data[4]; 573 if (picType != 0x03) { 574 // Front Cover Art 575 it.next(); 576 continue; 577 } 578#endif 579 580 size_t descLen = StringSize(&data[5], encoding); 581 582 *length = size - 5 - descLen; 583 584 return &data[5 + descLen]; 585 } 586 } 587 588 return NULL; 589} 590 591bool ID3::parseV1(const sp<DataSource> &source) { 592 const size_t V1_TAG_SIZE = 128; 593 594 off_t size; 595 if (source->getSize(&size) != OK || size < (off_t)V1_TAG_SIZE) { 596 return false; 597 } 598 599 mData = (uint8_t *)malloc(V1_TAG_SIZE); 600 if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE) 601 != (ssize_t)V1_TAG_SIZE) { 602 free(mData); 603 mData = NULL; 604 605 return false; 606 } 607 608 if (memcmp("TAG", mData, 3)) { 609 free(mData); 610 mData = NULL; 611 612 return false; 613 } 614 615 mSize = V1_TAG_SIZE; 616 mFirstFrameOffset = 3; 617 618 if (mData[V1_TAG_SIZE - 3] != 0) { 619 mVersion = ID3_V1; 620 } else { 621 mVersion = ID3_V1_1; 622 } 623 624 return true; 625} 626 627} // namespace android 628