예제 #1
0
bool ID3_FieldImpl::ParseText(ID3_Reader& reader)
{
  ID3D_NOTICE( "ID3_Field::ParseText(): reader.getBeg() = " << reader.getBeg() );
  ID3D_NOTICE( "ID3_Field::ParseText(): reader.getCur() = " << reader.getCur() );
  ID3D_NOTICE( "ID3_Field::ParseText(): reader.getEnd() = " << reader.getEnd() );
  this->Clear();

  ID3_TextEnc enc = this->GetEncoding();
  size_t fixed_size = this->Size();
  if (fixed_size)
  {
    ID3D_NOTICE( "ID3_Field::ParseText(): fixed size string" );
    // The string is of fixed length
    String text = readEncodedText(reader, fixed_size, enc);
    this->SetText(text);
    ID3D_NOTICE( "ID3_Field::ParseText(): fixed size string = " << text );
  }
  else if (_flags & ID3FF_LIST)
  {
    ID3D_NOTICE( "ID3_Field::ParseText(): text list" );
    // lists are always the last field in a frame.  parse all remaining 
    // characters in the reader
    while (!reader.atEnd())
    {
      String text = readEncodedString(reader, enc);
      this->AddText(text);
      ID3D_NOTICE( "ID3_Field::ParseText(): adding string = " << text );
    }
  }
  else if (_flags & ID3FF_CSTR)
  {
    ID3D_NOTICE( "ID3_Field::ParseText(): null terminated string" );
    String text = readEncodedString(reader, enc);
    this->SetText(text);
    ID3D_NOTICE( "ID3_Field::ParseText(): null terminated string = " << text );
  }
  else
  {
    ID3D_NOTICE( "ID3_Field::ParseText(): last field string" );
    String text = readEncodedText(reader, reader.remainingBytes(), enc);
    // not null terminated.  
    this->AddText(text);
    ID3D_NOTICE( "ID3_Field::ParseText(): last field string = " << text );
  }
  
  _changed = false;
  return true;
}
예제 #2
0
bool ID3_FieldImpl::ParseInteger(ID3_Reader& reader)
{
  ID3D_NOTICE( "ID3_FieldImpl::ParseInteger(): beg = " << reader.getBeg() );
  ID3D_NOTICE( "ID3_FieldImpl::ParseInteger(): cur = " << reader.getCur() );
  ID3D_NOTICE( "ID3_FieldImpl::ParseInteger(): end = " << reader.getEnd() );
  bool success = false;
  if (!reader.atEnd())
  {
    this->Clear();
    size_t fixed = this->Size();
    size_t nBytes = (fixed > 0) ? fixed : sizeof(uint32);
    this->Set(io::readBENumber(reader, nBytes));
    _changed = false;
    success = true;
  }
  return success;
}
예제 #3
0
bool ID3_FrameHeader::Parse(ID3_Reader& reader)
{
  ID3D_NOTICE( "ID3_FrameHeader::Parse(): getCur() = " << reader.getCur() );
  io::ExitTrigger et(reader);
  if (!_info)
  {
    return false;
  }
  if (reader.getEnd() < reader.getCur() + 10)
  {
    return false;
  }

  String textID = io::readText(reader, _info->frame_bytes_id);

  ID3D_NOTICE( "ID3_FrameHeader::Parse: textID = " << textID );
  ID3D_NOTICE( "ID3_FrameHeader::Parse: getCur() = " << reader.getCur() );

  ID3_FrameID fid = ID3_FindFrameID(textID.c_str());
  if (ID3FID_NOFRAME == fid)
  {
    this->SetUnknownFrame(textID.c_str());
    ID3D_NOTICE( "ID3_FrameHeader::Parse: unknown frame id" );
  }
  else
  {
    this->SetFrameID(fid);
  }

  uint32 dataSize = io::readBENumber(reader, _info->frame_bytes_size);
  ID3D_NOTICE( "ID3_FrameHeader::Parse: dataSize = " << dataSize );
  ID3D_NOTICE( "ID3_FrameHeader::Parse: getCur() = " << reader.getCur() );
  this->SetDataSize(dataSize);

  uint32 flags = io::readBENumber(reader, _info->frame_bytes_flags);
  _flags.add(flags);

  ID3D_NOTICE( "ID3_FrameHeader::Parse: flags = " << flags );
  ID3D_NOTICE( "ID3_FrameHeader::Parse: getCur() = " << reader.getCur() );
  et.setExitPos(reader.getCur());

  return true;
}
예제 #4
0
bool ID3_FrameImpl::Parse(ID3_Reader& reader) 
{ 
  io::ExitTrigger et(reader);
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): reader.getBeg() = " << reader.getBeg() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): reader.getCur() = " << reader.getCur() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): reader.getEnd() = " << reader.getEnd() );
  ID3_Reader::pos_type beg = reader.getCur();

  if (!_hdr.Parse(reader) || reader.getCur() == beg)  
  { 
    ID3D_WARNING( "ID3_FrameImpl::Parse(): no header to parse" );
    return false; 
  }
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): after hdr, getCur() = " << reader.getCur() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): found frame! id = " << _hdr.GetTextID() );

  // data is the part of the frame buffer that appears after the header  
  const size_t dataSize = _hdr.GetDataSize();
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): dataSize = " << dataSize );
  if (reader.getEnd() < beg + dataSize)
  {
    ID3D_WARNING( "ID3_FrameImpl::Parse(): not enough data to parse frame" );
    return false;
  }

  if (dataSize > 16777216) //Klenotic: The max frame size is 16MB according to http://www.id3.org/easy.html.  A corrupted tag that reports a frame size of (-1) will crash the program.
  {
    ID3D_WARNING( "ID3_FrameImpl::Parse(): frame size too large" );
    return false;
  }


  io::WindowedReader wr(reader, dataSize);
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): window getBeg() = " << wr.getBeg() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): window getCur() = " << wr.getCur() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): window getEnd() = " << wr.getEnd() );
  
  unsigned long origSize = 0;
  if (_hdr.GetCompression())
  {
    origSize = io::readBENumber(reader, sizeof(uint32));
	// allocate 2MB instead 4GB max in the decompressor later on (TODO decompressor should actually do the sanitycheck)
	if (origSize > 2 * 1024 * 1024){
		ID3D_WARNING( "ID3_FrameImpl::Parse(): _hdr.GetCompression() exeeds sanity limit" );
		return false;
	}
    ID3D_NOTICE( "ID3_FrameImpl::Parse(): frame is compressed, origSize = " << origSize );
  }

  if (_hdr.GetEncryption())
  {
    char ch = static_cast<char>(wr.readChar());
    this->SetEncryptionID(ch);
    ID3D_NOTICE( "ID3_FrameImpl::Parse(): frame is encrypted, encryption_id = " << (int) ch );
  }

  if (_hdr.GetGrouping())
  {
    char ch = static_cast<char>(wr.readChar());
    this->SetGroupingID(ch);
    ID3D_NOTICE( "ID3_FrameImpl::Parse(): frame is encrypted, grouping_id = " << (int) ch );
  }

  // set the type of frame based on the parsed header  
  this->_ClearFields(); 
  this->_InitFields(); 

  bool success = false;
  // expand out the data if it's compressed 
  if (!_hdr.GetCompression())
  {
    success = parseFields(wr, *this);
  }
  else
  {
    io::CompressedReader csr(wr, origSize);
    success = parseFields(csr, *this);
  }
  et.setExitPos(wr.getCur());

  _changed = false;
  return true;
} 
예제 #5
0
//used for streaming media
void ID3_TagImpl::ParseReader(ID3_Reader &reader)
{
  size_t mp3_core_size;
  size_t bytes_till_sync;

  io::WindowedReader wr(reader);
  wr.setBeg(wr.getCur());

  _file_tags.clear();
  _file_size = reader.getEnd();

  ID3_Reader::pos_type beg  = wr.getBeg();
  ID3_Reader::pos_type cur  = wr.getCur();
  ID3_Reader::pos_type end  = wr.getEnd();

  ID3_Reader::pos_type last = cur;

  if (_tags_to_parse.test(ID3TT_ID3V2))
  {
    do
    {
      last = cur;
      // Parse tags at the beginning of the file first...
      if (id3::v2::parse(*this, wr))
      {
        _file_tags.add(ID3TT_ID3V2);
      }
      cur  = wr.getCur();
      wr.setBeg(cur);
    } while (!wr.atEnd() && cur > last);
  }
  // add silly padding outside the tag to _prepended_bytes
  if (!wr.atEnd() && wr.peekChar() == '\0')
  {
    ID3D_NOTICE( "ID3_TagImpl::ParseReader(): found padding outside tag" );
    do
    {
      last = cur;
      cur = wr.getCur() + 1;
      wr.setBeg(cur);
      wr.setCur(cur);
    } while (!wr.atEnd() &&  cur > last && wr.peekChar() == '\0');
  }
  if (!wr.atEnd() && _file_size - (cur - beg) > 4 && wr.peekChar() == 255)
  { //unfortunatly, this is necessary for finding an invalid padding
    wr.setCur(cur + 1); //cur is known by peekChar
    if (wr.readChar() == '\0' && wr.readChar() == '\0' && wr.peekChar() == '\0')
    { //three empty bytes found, enough for me, this is stupid padding
      cur += 3; //those are now allready read in (excluding the peekChar, since it will be added by do{})
      do
      {
        last = cur;
        cur = wr.getCur() + 1;
        wr.setBeg(cur);
        wr.setCur(cur);
      } while (!wr.atEnd() &&  cur > last && wr.peekChar() == '\0');
    }
    else
      wr.setCur(cur);
  }
  _prepended_bytes = cur - beg;
  // go looking for the first sync byte to add to bytes_till_sync
  // by not adding it to _prepended_bytes, we preserve this 'unknown' data
  // The routine's only effect is helping the lib to find things as bitrate etc.
  beg  = wr.getBeg();
  if (!wr.atEnd() && wr.peekChar() != 0xFF) //no sync byte, so, either this is not followed by a mp3 file or it's a fLaC file, or an encapsulating format, better check it
  {
    ID3D_NOTICE( "ID3_TagImpl::ParseReader(): Didn't find mp3 sync byte" );
    if ((_file_size - (cur - beg)) >= 4)
    { //there is room to search for some kind of ID
      unsigned char buf[5];
      wr.readChars(buf, 4);
      buf[4] = '\0';
      // check for RIFF (an encapsulating format) ID
      if (strncmp((char*)buf, "RIFF", 4) == 0 || strncmp((char*)buf, "RIFX", 4) == 0)
      {
        // next 4 bytes are RIFF size, skip them
        cur = wr.getCur() + 4;
        wr.setCur(cur);
        // loop until first possible sync byte
        if (!wr.atEnd() && wr.peekChar() != 0xFF)
        {
          do
          {
            last = cur;
            cur = wr.getCur() + 1;
            wr.setCur(cur);
          } while (!wr.atEnd() &&  cur > last && wr.peekChar() != 0xFF);
        }
      }
      else if (strncmp((char*)buf, "fLaC", 4) == 0)
      { //a FLAC file, no need looking for a sync byte
        beg = cur;
      }
      else
      { //since we set the cursor 4 bytes ahead for looking for RIFF, RIFX or fLaC, better set it back
        // but peekChar allready checked the first one, so we add one
        cur = cur + 1;
        wr.setCur(cur);
        //go looking for a sync byte
        if (!wr.atEnd() && wr.peekChar() != 0xFF) //no sync byte, we have an unknown byte
        {
          do
          {
            last = cur;
            cur = wr.getCur() + 1;
            wr.setCur(cur);
          } while (!wr.atEnd() &&  cur > last && wr.peekChar() != 0xFF);
        }
      }
    } //if ((_file_size - (cur - beg)) >= 4)
    else
    { //remaining size is smaller than 4 bytes, can't be useful, but leave it for now
      beg = cur;
      //file.close();
      //return;
    }
  }
  bytes_till_sync = cur - beg;

  cur = wr.setCur(end);
  if (_file_size > _prepended_bytes)
  {
    do
    {
      last = cur;
      ID3D_NOTICE( "ID3_TagImpl::ParseReader(): beg = " << wr.getBeg() );
      ID3D_NOTICE( "ID3_TagImpl::ParseReader(): cur = " << wr.getCur() );
      ID3D_NOTICE( "ID3_TagImpl::ParseReader(): end = " << wr.getEnd() );
      // ...then the tags at the end
      ID3D_NOTICE( "ID3_TagImpl::ParseReader(): musicmatch? cur = " << wr.getCur() );
      if (_tags_to_parse.test(ID3TT_MUSICMATCH) && mm::parse(*this, wr))
      {
        ID3D_NOTICE( "ID3_TagImpl::ParseReader(): musicmatch! cur = " << wr.getCur() );
        _file_tags.add(ID3TT_MUSICMATCH);
        wr.setEnd(wr.getCur());
      }
      ID3D_NOTICE( "ID3_TagImpl::ParseReader(): lyr3v1? cur = " << wr.getCur() );
      if (_tags_to_parse.test(ID3TT_LYRICS3) && lyr3::v1::parse(*this, wr))
      {
        ID3D_NOTICE( "ID3_TagImpl::ParseReader(): lyr3v1! cur = " << wr.getCur() );
        _file_tags.add(ID3TT_LYRICS3);
        wr.setEnd(wr.getCur());
      }
      ID3D_NOTICE( "ID3_TagImpl::ParseReader(): lyr3v2? cur = " << wr.getCur() );
      if (_tags_to_parse.test(ID3TT_LYRICS3V2) && lyr3::v2::parse(*this, wr))
      {
        ID3D_NOTICE( "ID3_TagImpl::ParseReader(): lyr3v2! cur = " << wr.getCur() );
        _file_tags.add(ID3TT_LYRICS3V2);
        cur = wr.getCur();
        wr.setCur(wr.getEnd());//set to end to seek id3v1 tag
        //check for id3v1 tag and set End accordingly
        ID3D_NOTICE( "ID3_TagImpl::ParseReader(): id3v1? cur = " << wr.getCur() );
        if (_tags_to_parse.test(ID3TT_ID3V1) && id3::v1::parse(*this, wr))
        {
          ID3D_NOTICE( "ID3_TagImpl::ParseReader(): id3v1! cur = " << wr.getCur() );
          _file_tags.add(ID3TT_ID3V1);
        }
        wr.setCur(cur);
        wr.setEnd(cur);
      }
      ID3D_NOTICE( "ID3_TagImpl::ParseReader(): id3v1? cur = " << wr.getCur() );
      if (_tags_to_parse.test(ID3TT_ID3V1) && id3::v1::parse(*this, wr))
      {
        ID3D_NOTICE( "ID3_TagImpl::ParseReader(): id3v1! cur = " << wr.getCur() );
        wr.setEnd(wr.getCur());
        _file_tags.add(ID3TT_ID3V1);
      }
      cur = wr.getCur();
    } while (cur != last);
    _appended_bytes = end - cur;

    // Now get the mp3 header
    mp3_core_size = (_file_size - _appended_bytes) - (_prepended_bytes + bytes_till_sync);
    if (mp3_core_size >= 4)
    { //it has at least the size for a mp3 header (a mp3 header is 4 bytes)
      wr.setBeg(_prepended_bytes + bytes_till_sync);
      wr.setCur(_prepended_bytes + bytes_till_sync);
      wr.setEnd(_file_size - _appended_bytes);

      _mp3_info = new Mp3Info;
      ID3D_NOTICE( "ID3_TagImpl::ParseReader(): mp3header? cur = " << wr.getCur() );

      if (_mp3_info->Parse(wr, mp3_core_size))
      {
        ID3D_NOTICE( "ID3_TagImpl::ParseReader(): mp3header! cur = " << wr.getCur() );
      }
      else
      {
        delete _mp3_info;
        _mp3_info = NULL;
      }
    }
  }
  else
    this->SetPadding(false); //no need to pad an empty file
}
예제 #6
0
bool ID3_FrameImpl::Parse(ID3_Reader& reader) 
{ 
  io::ExitTrigger et(reader);
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): reader.getBeg() = " << reader.getBeg() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): reader.getCur() = " << reader.getCur() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): reader.getEnd() = " << reader.getEnd() );
  ID3_Reader::pos_type beg = reader.getCur();

  if (!_hdr.Parse(reader) || reader.getCur() == beg)  
  { 
    ID3D_WARNING( "ID3_FrameImpl::Parse(): no header to parse" );
    return false; 
  }
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): after hdr, getCur() = " << reader.getCur() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): found frame! id = " << _hdr.GetTextID() );

  // data is the part of the frame buffer that appears after the header  
  const size_t dataSize = _hdr.GetDataSize();
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): dataSize = " << dataSize );
  if (reader.getEnd() < beg + dataSize)
  {
    ID3D_WARNING( "ID3_FrameImpl::Parse(): not enough data to parse frame" );
    return false;
  }
  io::WindowedReader wr(reader, dataSize);
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): window getBeg() = " << wr.getBeg() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): window getCur() = " << wr.getCur() );
  ID3D_NOTICE( "ID3_FrameImpl::Parse(): window getEnd() = " << wr.getEnd() );
  
  unsigned long origSize = 0;
  if (_hdr.GetCompression())
  {
    origSize = io::readBENumber(reader, sizeof(uint32));
    ID3D_NOTICE( "ID3_FrameImpl::Parse(): frame is compressed, origSize = " << origSize );
  }

  if (_hdr.GetEncryption())
  {
    char ch = wr.readChar();
    this->SetEncryptionID(ch);
    ID3D_NOTICE( "ID3_FrameImpl::Parse(): frame is encrypted, encryption_id = " << (int) ch );
  }

  if (_hdr.GetGrouping())
  {
    char ch = wr.readChar();
    this->SetGroupingID(ch);
    ID3D_NOTICE( "ID3_FrameImpl::Parse(): frame is encrypted, grouping_id = " << (int) ch );
  }

  // set the type of frame based on the parsed header  
  this->_ClearFields(); 
  this->_InitFields(); 

  bool success = false;
  // expand out the data if it's compressed 
  if (!_hdr.GetCompression())
  {
    success = parseFields(wr, *this);
  }
  else
  {
    io::CompressedReader csr(wr, origSize);
    success = parseFields(csr, *this);
  }
  et.setExitPos(wr.getCur());

  _changed = false;
  return true;
}