예제 #1
0
String io::readString(ID3_Reader& reader)
{
  String str;
  while (!reader.atEnd())
  {
    ID3_Reader::char_type ch = static_cast<ID3_Reader::char_type>(reader.readChar());
    if (ch == '\0')
    {
      break;
    }
    str += static_cast<char>(ch);
  }
  return str;
}
uint32 io::readUInt28(ID3_Reader& reader)
{
  uint32 val = 0;
  const unsigned short BITSUSED = 7;
  const uint32 MAXVAL = MASK(BITSUSED * sizeof(uint32));
  // For each byte of the first 4 bytes in the string...
  for (size_t i = 0; i < sizeof(uint32); ++i)
  {
    if (reader.atEnd())
    {
      break;
    }
    // ...append the last 7 bits to the end of the temp integer...
    val = (val << BITSUSED) | static_cast<uint32>(reader.readChar()) & MASK(BITSUSED);
  }

  // We should always parse 4 characters
  return min(val, MAXVAL);
}
예제 #3
0
bool id3::v1::parse(ID3_TagImpl& tag, ID3_Reader& reader)
{
  io::ExitTrigger et(reader);
  
  ID3_Reader::pos_type end = reader.getCur();
  // posn ourselves at 128 bytes from the current position
  if (end < reader.getBeg() + ID3_V1_LEN)
  {
    ID3D_NOTICE( "id3::v1::parse: not enough bytes to parse, pos = " << end );
    return false;
  }
  reader.setCur(end - ID3_V1_LEN);
  ID3_Reader::pos_type beg = reader.getCur();
  //file.seekg(-static_cast<long>(ID3_V1_LEN), ios::cur);
  if (end != beg + ID3_V1_LEN)
  {
    ID3D_WARNING( "id3::v1::parse: failed to reposition " << ID3_V1_LEN << 
                  " bytes" );
    return false;
  }
  
  // read the next 128 bytes in;
  String field = io::readText(reader, ID3_V1_LEN_ID);
  
  // check to see if it was a tag
  if (field != "TAG")
  {
    return false;
  }
  et.setExitPos(beg);
  
  // guess so, let's start checking the v2 tag for frames which are the
  // equivalent of the v1 fields.  When we come across a v1 field that has
  // no current equivalent v2 frame, we create the frame, copy the data
  // from the v1 frame and attach it to the tag

  // (Scott Wheeler) The above comment was nice in theory, but it wasn't
  // first checking (before my hacks) to see if there already was v2 data.

  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String title = io::readTrailingSpaces(reader, ID3_V1_LEN_TITLE);
  field = id3::v2::getTitle(tag);
  if (title.size() > 0 && (field.size() == 0 || field == ""))
  {
    id3::v2::setTitle(tag, title);
  }
  ID3D_NOTICE( "id3::v1::parse: title = \"" << title << "\"" );
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String artist = io::readTrailingSpaces(reader, ID3_V1_LEN_ARTIST);
  field = id3::v2::getArtist(tag);
  if (artist.size() > 0 && (field.size() == 0 || field == ""))
  {
    id3::v2::setArtist(tag, artist);
  }
  ID3D_NOTICE( "id3::v1::parse: artist = \"" << artist << "\"" );
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String album = io::readTrailingSpaces(reader, ID3_V1_LEN_ALBUM);
  field = id3::v2::getAlbum(tag);
  if (album.size() > 0 && (field.size() == 0 || field == ""))
  {
    id3::v2::setAlbum(tag, album);
  }
  ID3D_NOTICE( "id3::v1::parse: album = \"" << title << "\"" );
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String year = io::readTrailingSpaces(reader, ID3_V1_LEN_YEAR);
  field = id3::v2::getYear(tag);
  if (year.size() > 0 && (field.size() == 0 || field == ""))
  {
    id3::v2::setYear(tag, year);
  }
  ID3D_NOTICE( "id3::v1::parse: year = \"" << year << "\"" );
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String comment = io::readTrailingSpaces(reader, ID3_V1_LEN_COMMENT-2);
  // fixes bug for when tracknumber is 0x20
  BString trackno = io::readBinary(reader, ID3_V1_LEN_COMMENT-28);
  if (trackno[0] == '\0')
  {
    if (trackno[1] != '\0')
    { //we've got a tracknumber
      size_t track = trackno[1];
      field = id3::v2::getTrack(tag);
      if (field.size() == 0 || field == "00")
      {
        id3::v2::setTrack(tag, track, 0);
      }
      ID3D_NOTICE( "id3::v1::parse: track = \"" << track << "\"" );
      ID3D_NOTICE( "id3::v1::parse: comment length = \"" << comment.length() << "\"" );
    }
  }
  else
  {
    // trackno[0] != '\0'
    const int paddingsize = (ID3_V1_LEN_COMMENT-2) - comment.size();
    const char * padding = "                            "; //28 spaces

    if (trackno[1] == '\0' || trackno[1] == 0x20 && trackno[0] != 0x20)
    {
      // if there used to be spaces they are gone now, we need to rebuild them
      comment.append(padding, paddingsize);
      comment.append((const char *)trackno.data(), 1);
    }
    else if (trackno[1] != '\0' && trackno[1] != 0x20 &&  trackno[0] != 0x20)
    {
      // if there used to be spaces they are gone now, we need to rebuild them
      comment.append(padding, paddingsize);
      comment.append((const char *)trackno.data(), 2);
    }
  }
  ID3D_NOTICE( "id3::v1::parse: comment = \"" << comment << "\"" );
  if (comment.size() > 0)
  {
    id3::v2::setComment(tag, comment, STR_V1_COMMENT_DESC, "XXX");
  }
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  // the GENRE field/frame
  uchar genre = reader.readChar();
  field = id3::v2::getGenre(tag);
  if (genre != 0xFF && (field.size() == 0 || field == ""))
  {
    id3::v2::setGenre(tag, genre);
  }
  ID3D_NOTICE( "id3::v1::parse: genre = \"" << (int) genre << "\"" );

  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  return true;
}
예제 #4
0
void ID3_TagHeader::ParseExtended(ID3_Reader& reader)
{
  if (this->GetSpec() == ID3V2_3_0)
  {
/*
    Extended header size   $xx xx xx xx
    Extended Flags         $xx xx
    Size of padding        $xx xx xx xx
*/
    // skip over header size, we are not using it anyway, we calculate it
    reader.setCur(reader.getCur()+4); //Extended header size
    //io::readBENumber(reader, 4); //Extended header size
    uint16 tmpval = io::readBENumber(reader, 2); //Extended Flags
    // skip over padding size, we are not using it anyway
    reader.setCur(reader.getCur()+4); //Size of padding
    // io::readBENumber(reader, 4); //Size of padding
    if (tmpval != 0) //there is only one flag defined in ID3V2_3_0: crc
    {
      //skip over crc data, we are not using it anyway
      reader.setCur(reader.getCur()+4); //Crc
      //io::readBENumber(reader, 4); //Crc
      _info->extended_bytes = 14;
    }
    else
      _info->extended_bytes = 10;
  }
  if (this->GetSpec() == ID3V2_4_0)
  {
/*
    Extended header size   4 * %0xxxxxxx
    Number of flag bytes       $01
    Extended Flags             $xx
*/
    uint16 i;
    uint16 extrabytes;

    io::readUInt28(reader);
    const int extflagbytes = reader.readChar(); //Number of flag bytes
    ID3_Flags* extflags[1]; // ID3V2_4_0 has 1 flag byte, extflagbytes should be equal to 1
    for (i = 0; i < extflagbytes; ++i)
    {
      extflags[i] = new ID3_Flags;
      extflags[i]->set(reader.readChar()); //flags
    }
    extrabytes = 0;
    //extflags[0]->test(EXT_HEADER_FLAG_BIT1); // ID3V2_4_0 ext header flag bit 1 *should* be 0
    if (extflags[0]->test(EXT_HEADER_FLAG_BIT2))
    {
      // ID3V2_4_0 ext header flag bit 2 = Tag is an update
      // read size
      extrabytes += 1; // add a byte for the char containing the extflagdatasize
      const int extheaderflagdatasize = reader.readChar();
      extrabytes += extheaderflagdatasize;
      // Set the cursor right; we are not parsing the data, no-one is using extended flags anyway
      reader.setCur(reader.getCur() + extheaderflagdatasize);
      //reader.readChars(buf, extheaderflagdatasize); //buf should be at least 127 bytes = max extended header flagdata size
    }
   if (extflags[0]->test(EXT_HEADER_FLAG_BIT3))
   {
      // ID3V2_4_0 ext header flag bit 3 = CRC data present
      // read size
      extrabytes += 1; // add a byte for the char containing the extflagdatasize
      const int extheaderflagdatasize = reader.readChar();
      extrabytes += extheaderflagdatasize;
      // Set the cursor right; we are not parsing the data, no-one is using extended flags anyway
      reader.setCur(reader.getCur() + extheaderflagdatasize);
      //reader.readChars(buf, extheaderflagdatasize); //buf should be at least 127 bytes = max extended header flagdata size
    }
    if (extflags[0]->test(EXT_HEADER_FLAG_BIT4))
    {
      // ID3V2_4_0 ext header flag bit 4 = Tag restrictions
      // read size
      extrabytes += 1; // add a byte for the char containing the extflagdatasize
      const int extheaderflagdatasize = reader.readChar();
      extrabytes += extheaderflagdatasize;
      // Set the cursor right; we are not parsing the data, no-one is using extended flags anyway
      reader.setCur(reader.getCur() + extheaderflagdatasize);
      //reader.readChars(buf, extheaderflagdatasize); //buf should be at least 127 bytes = max extended header flagdata size
    }
    _info->extended_bytes = 5 + extflagbytes + extrabytes;
  }
  // a bit unorthodox, but since we are not using any of the extended header, but were merely
  // parsing it to get the cursor right, we delete it. Be Gone !
  _flags.set(HEADER_FLAG_EXTENDED, false);
  if (_info)
  {
    _data_size -= _info->extended_bytes;
    _info->extended_bytes = 0;
  }//else there is a tag with a higher or lower version than supported
}
예제 #5
0
bool id3::v1::parse(ID3_TagImpl& tag, ID3_Reader& reader)
{
  io::ExitTrigger et(reader);
  
  ID3_Reader::pos_type end = reader.getCur();
  // posn ourselves at 128 bytes from the current position
  if (end < reader.getBeg() + ID3_V1_LEN)
  {
    ID3D_NOTICE( "id3::v1::parse: not enough bytes to parse, pos = " << end );
    return false;
  }
  reader.setCur(end - ID3_V1_LEN);
  ID3_Reader::pos_type beg = reader.getCur();
  //file.seekg(-static_cast<long>(ID3_V1_LEN), ios::cur);
  if (end != beg + ID3_V1_LEN)
  {
    ID3D_WARNING( "id3::v1::parse: failed to reposition " << ID3_V1_LEN << 
                  " bytes" );
    return false;
  }
  
  // read the next 128 bytes in;
  String id = io::readText(reader, ID3_V1_LEN_ID);
  
  // check to see if it was a tag
  if (id != "TAG")
  {
    return false;
  }
  et.setExitPos(beg);
  
  // guess so, let's start checking the v2 tag for frames which are the
  // equivalent of the v1 fields.  When we come across a v1 field that has
  // no current equivalent v2 frame, we create the frame, copy the data
  // from the v1 frame and attach it to the tag
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String title = io::readTrailingSpaces(reader, ID3_V1_LEN_TITLE);
  if (title.size() > 0)
  {
    id3::v2::setTitle(tag, title);
  }
  ID3D_NOTICE( "id3::v1::parse: title = \"" << title << "\"" );
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String artist = io::readTrailingSpaces(reader, ID3_V1_LEN_ARTIST);
  if (artist.size() > 0)
  {
    id3::v2::setArtist(tag, artist);
  }
  ID3D_NOTICE( "id3::v1::parse: artist = \"" << artist << "\"" );
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String album = io::readTrailingSpaces(reader, ID3_V1_LEN_ALBUM);
  if (album.size() > 0) 
  {
    id3::v2::setAlbum(tag, album);
  }
  ID3D_NOTICE( "id3::v1::parse: album = \"" << title << "\"" );
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String year = io::readTrailingSpaces(reader, ID3_V1_LEN_YEAR);
  if (year.size() > 0)
  {
    id3::v2::setYear(tag, year);
  }
  ID3D_NOTICE( "id3::v1::parse: year = \"" << year << "\"" );
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  String comment = io::readTrailingSpaces(reader, ID3_V1_LEN_COMMENT);
  if (comment.length() == ID3_V1_LEN_COMMENT  &&
      '\0' == comment[ID3_V1_LEN_COMMENT - 2] ||
      '\0' != comment[ID3_V1_LEN_COMMENT - 1])
  {
    // This is an id3v1.1 tag.  The last byte of the comment is the track
    // number.  
    size_t track = comment[ID3_V1_LEN_COMMENT - 1];
    id3::v2::setTrack(tag, track, 0);
    ID3D_NOTICE( "id3::v1::parse: track = \"" << track << "\"" );

    ID3D_NOTICE( "id3::v1::parse: comment length = \"" << comment.length() << "\"" );
    io::StringReader sr(comment);
    comment = io::readTrailingSpaces(sr, ID3_V1_LEN_COMMENT - 2);
  }
  ID3D_NOTICE( "id3::v1::parse: comment = \"" << comment << "\"" );
  if (comment.size() > 0)
  {
    id3::v2::setComment(tag, comment, STR_V1_COMMENT_DESC, "XXX");
  }
  
  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  // the GENRE field/frame
  uchar genre = reader.readChar();
  if (genre != 0xFF) 
  {
    id3::v2::setGenre(tag, genre);
  }
  ID3D_NOTICE( "id3::v1::parse: genre = \"" << (int) genre << "\"" );

  ID3D_NOTICE("id3::v1::parse: read bytes: " << reader.getCur() - beg);
  return true;
}