// $Id: frame_parse.cpp,v 1.34 2002/07/06 13:53:18 t1mpy Exp $ // id3lib: a C++ library for creating and manipulating id3v1/v2 tags // Copyright 1999, 2000 Scott Thomas Haug // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by // the Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This library is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public // License for more details. // // You should have received a copy of the GNU Library General Public License // along with this library; if not, write to the Free Software Foundation, // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // The id3lib authors encourage improvements and optimisations to be sent to // the id3lib coordinator. Please see the README file for details on where to // send such submissions. See the AUTHORS file for a list of people who have // contributed to id3lib. See the ChangeLog file for a list of changes to // id3lib. These files are distributed with id3lib at // http://download.sourceforge.net/id3lib/ #if defined HAVE_CONFIG_H #include #endif #include "frame_impl.h" #include "id3/io_decorators.h" //has "readers.h" "io_helpers.h" "utils.h" using namespace dami; namespace { bool parseFields(ID3_Reader& rdr, ID3_FrameImpl& frame) { int iLoop; int iFields; io::ExitTrigger et(rdr); ID3_TextEnc enc = ID3TE_ASCII; // set the default encoding ID3_V2Spec spec = frame.GetSpec(); // parse the frame's fields iFields = frame.NumFields(); ID3D_NOTICE( "ID3_FrameImpl::Parse(): num_fields = " << iFields ); iLoop = 0; for (ID3_FrameImpl::iterator fi = frame.begin(); fi != frame.end(); ++fi) { ID3_Field* fp = *fi; ++iLoop; if (rdr.atEnd()) { // there's no remaining data to parse! ID3D_WARNING( "ID3_FrameImpl::Parse(): out of data at postion " << rdr.getCur() ); if (iLoop == iFields) { //if we are at the last field, (the 'data' field) it's apparently //an empty tag used for filling up padding, it's no problem //break will set the current 'cursor' to the right spot outside the for loop break; } return false; } if (NULL == fp) { // Ack! Why is the field NULL? Log this... ID3D_WARNING( "ID3_FrameImpl::Parse(): field is null" ); continue; } if (!fp->InScope(spec)) { ID3D_NOTICE( "ID3_FrameImpl::Parse(): field is not in scope" ); // continue with the rest of the fields continue; } ID3D_NOTICE( "ID3_FrameImpl::Parse(): setting enc to " << enc ); fp->SetEncoding(enc); ID3_Reader::pos_type beg = rdr.getCur(); et.setExitPos(beg); ID3D_NOTICE( "ID3_FrameImpl::Parse(): parsing field, cur = " << beg ); ID3D_NOTICE( "ID3_FrameImpl::Parse(): parsing field, end = " << rdr.getEnd() ); if (!fp->Parse(rdr) || rdr.getCur() == beg) { // nothing to parse! ack! parse error... ID3D_WARNING( "ID3_FrameImpl::Parse(): no data parsed, bad parse" ); return false; } if (fp->GetID() == ID3FN_TEXTENC) { enc = static_cast(fp->Get()); ID3D_NOTICE( "ID3_FrameImpl::Parse(): found encoding = " << enc ); } } et.setExitPos(rdr.getCur()); return true; } }; 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)); 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; }