src/header_tag.cpp

Go to the documentation of this file.
00001 // $Id: header_tag.cpp,v 1.25 2003/03/02 14:30:46 t1mpy Exp $
00002 
00003 // id3lib: a C++ library for creating and manipulating id3v1/v2 tags
00004 // Copyright 1999, 2000  Scott Thomas Haug
00005 // Copyright 2002  Thijmen Klok (thijmen@id3lib.org)
00006 
00007 // This library is free software; you can redistribute it and/or modify it
00008 // under the terms of the GNU Library General Public License as published by
00009 // the Free Software Foundation; either version 2 of the License, or (at your
00010 // option) any later version.
00011 //
00012 // This library is distributed in the hope that it will be useful, but WITHOUT
00013 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00015 // License for more details.
00016 //
00017 // You should have received a copy of the GNU Library General Public License
00018 // along with this library; if not, write to the Free Software Foundation,
00019 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 
00021 // The id3lib authors encourage improvements and optimisations to be sent to
00022 // the id3lib coordinator.  Please see the README file for details on where to
00023 // send such submissions.  See the AUTHORS file for a list of people who have
00024 // contributed to id3lib.  See the ChangeLog file for a list of changes to
00025 // id3lib.  These files are distributed with id3lib at
00026 // http://download.sourceforge.net/id3lib/
00027 
00028 
00029 #include "header_tag.h"
00030 #include "id3/utils.h" // has <config.h> "id3/id3lib_streams.h" "id3/globals.h" "id3/id3lib_strings.h"
00031 #include "tag.h"
00032 #include "io_helpers.h"
00033 #include "spec.h"
00034 
00035 using namespace dami;
00036 
00037 const char* const ID3_TagHeader::ID = "ID3";
00038 
00039 bool ID3_TagHeader::SetSpec(ID3_V2Spec spec)
00040 {
00041   bool changed = this->ID3_Header::SetSpec(spec);
00042   if (changed)
00043   {
00044     if (_info)
00045     {
00046       _flags.set(HEADER_FLAG_EXPERIMENTAL, _info->is_experimental);
00047       _flags.set(HEADER_FLAG_EXTENDED,     _info->is_extended);
00048     }
00049   }
00050   return changed;
00051 }
00052 
00053 size_t ID3_TagHeader::Size() const
00054 {
00055   size_t bytesUsed = ID3_TagHeader::SIZE;
00056 
00057   if (_info->is_extended)
00058   {
00059     bytesUsed += _info->extended_bytes;
00060   }
00061 
00062   return bytesUsed;
00063 }
00064 
00065 
00066 void ID3_TagHeader::Render(ID3_Writer& writer) const
00067 {
00068   writer.writeChars((uchar *) ID, strlen(ID));
00069 
00070   writer.writeChar(ID3_V2SpecToVer(ID3V2_LATEST));
00071   writer.writeChar(ID3_V2SpecToRev(ID3V2_LATEST));
00072 
00073   // set the flags byte in the header
00074   writer.writeChar(static_cast<uchar>(_flags.get() & MASK8));
00075   io::writeUInt28(writer, this->GetDataSize()); //now includes the extended header
00076 
00077   // now we render the extended header
00078   if (_flags.test(HEADER_FLAG_EXTENDED))
00079   {
00080     if (this->GetSpec() == ID3V2_4_0)
00081     {
00082       io::writeUInt28(writer, 6); //write 4 bytes of v2.4.0 ext header containing size '6'
00083       io::writeBENumber(writer, 1, 1); //write that it has only one flag byte (value '1')
00084       io::writeBENumber(writer, 0, 1); //write flag byte with value '0'
00085     }
00086     else if (this->GetSpec() == ID3V2_3_0)
00087     {
00088       io::writeBENumber(writer, 6, sizeof(uint32));
00089       for (size_t i = 0; i < 6; ++i)
00090       {
00091         if (writer.writeChar('\0') == ID3_Writer::END_OF_WRITER)
00092         {
00093           break;
00094         }
00095       }
00096     }
00097   //  else //not implemented
00098   }
00099 }
00100 
00101 bool ID3_TagHeader::Parse(ID3_Reader& reader)
00102 {
00103   io::ExitTrigger et(reader);
00104   if (!ID3_Tag::IsV2Tag(reader))
00105   {
00106     ID3D_NOTICE( "ID3_TagHeader::Parse(): not an id3v2 header" );
00107     return false;
00108   }
00109 
00110   uchar id[3];
00111   reader.readChars(id, 3);
00112   // The spec version is determined with the MAJOR and MINOR OFFSETs
00113   uchar major = reader.readChar();
00114   uchar minor = reader.readChar();
00115   this->SetSpec(ID3_VerRevToV2Spec(major, minor));
00116 
00117   // Get the flags at the appropriate offset
00118   _flags.set(static_cast<ID3_Flags::TYPE>(reader.readChar()));
00119 
00120   // set the data size
00121   this->SetDataSize(io::readUInt28(reader));
00122 
00123   if (_flags.test(HEADER_FLAG_EXTENDED) && this->GetSpec() == ID3V2_2_1)
00124   {
00125     //couldn't find anything about this in the draft specifying 2.2.1 -> http://www.id3.org/pipermail/id3v2/2000-April/000126.html
00126     _flags.set(HEADER_FLAG_EXTENDED, false);
00127     _info->extended_bytes = 0;
00128     // rest is checked at ParseExtended()
00129   }
00130   et.setExitPos(reader.getCur());
00131   return true;
00132 }
00133 
00134 void ID3_TagHeader::ParseExtended(ID3_Reader& reader)
00135 {
00136   if (this->GetSpec() == ID3V2_3_0)
00137   {
00138 /*
00139     Extended header size   $xx xx xx xx
00140     Extended Flags         $xx xx
00141     Size of padding        $xx xx xx xx
00142 */
00143     // skip over header size, we are not using it anyway, we calculate it
00144     reader.setCur(reader.getCur()+4); //Extended header size
00145     //io::readBENumber(reader, 4); //Extended header size
00146     uint16 tmpval = io::readBENumber(reader, 2); //Extended Flags
00147     // skip over padding size, we are not using it anyway
00148     reader.setCur(reader.getCur()+4); //Size of padding
00149     // io::readBENumber(reader, 4); //Size of padding
00150     if (tmpval != 0) //there is only one flag defined in ID3V2_3_0: crc
00151     {
00152       //skip over crc data, we are not using it anyway
00153       reader.setCur(reader.getCur()+4); //Crc
00154       //io::readBENumber(reader, 4); //Crc
00155       _info->extended_bytes = 14;
00156     }
00157     else
00158       _info->extended_bytes = 10;
00159   }
00160   if (this->GetSpec() == ID3V2_4_0)
00161   {
00162 /*
00163     Extended header size   4 * %0xxxxxxx
00164     Number of flag bytes       $01
00165     Extended Flags             $xx
00166 */
00167     uint16 i;
00168     uint16 extrabytes;
00169 
00170     io::readUInt28(reader);
00171     const int extflagbytes = reader.readChar(); //Number of flag bytes
00172     ID3_Flags* extflags[1]; // ID3V2_4_0 has 1 flag byte, extflagbytes should be equal to 1
00173     for (i = 0; i < extflagbytes; ++i)
00174     {
00175       extflags[i] = new ID3_Flags;
00176       extflags[i]->set(reader.readChar()); //flags
00177     }
00178     extrabytes = 0;
00179     //extflags[0]->test(EXT_HEADER_FLAG_BIT1); // ID3V2_4_0 ext header flag bit 1 *should* be 0
00180     if (extflags[0]->test(EXT_HEADER_FLAG_BIT2))
00181     {
00182       // ID3V2_4_0 ext header flag bit 2 = Tag is an update
00183       // read size
00184       extrabytes += 1; // add a byte for the char containing the extflagdatasize
00185       const int extheaderflagdatasize = reader.readChar();
00186       extrabytes += extheaderflagdatasize;
00187       // Set the cursor right; we are not parsing the data, no-one is using extended flags anyway
00188       reader.setCur(reader.getCur() + extheaderflagdatasize);
00189       //reader.readChars(buf, extheaderflagdatasize); //buf should be at least 127 bytes = max extended header flagdata size
00190     }
00191    if (extflags[0]->test(EXT_HEADER_FLAG_BIT3))
00192    {
00193       // ID3V2_4_0 ext header flag bit 3 = CRC data present
00194       // read size
00195       extrabytes += 1; // add a byte for the char containing the extflagdatasize
00196       const int extheaderflagdatasize = reader.readChar();
00197       extrabytes += extheaderflagdatasize;
00198       // Set the cursor right; we are not parsing the data, no-one is using extended flags anyway
00199       reader.setCur(reader.getCur() + extheaderflagdatasize);
00200       //reader.readChars(buf, extheaderflagdatasize); //buf should be at least 127 bytes = max extended header flagdata size
00201     }
00202     if (extflags[0]->test(EXT_HEADER_FLAG_BIT4))
00203     {
00204       // ID3V2_4_0 ext header flag bit 4 = Tag restrictions
00205       // read size
00206       extrabytes += 1; // add a byte for the char containing the extflagdatasize
00207       const int extheaderflagdatasize = reader.readChar();
00208       extrabytes += extheaderflagdatasize;
00209       // Set the cursor right; we are not parsing the data, no-one is using extended flags anyway
00210       reader.setCur(reader.getCur() + extheaderflagdatasize);
00211       //reader.readChars(buf, extheaderflagdatasize); //buf should be at least 127 bytes = max extended header flagdata size
00212     }
00213     _info->extended_bytes = 5 + extflagbytes + extrabytes;
00214   }
00215   // a bit unorthodox, but since we are not using any of the extended header, but were merely
00216   // parsing it to get the cursor right, we delete it. Be Gone !
00217   _flags.set(HEADER_FLAG_EXTENDED, false);
00218   if (_info)
00219   {
00220     _data_size -= _info->extended_bytes;
00221     _info->extended_bytes = 0;
00222   }//else there is a tag with a higher or lower version than supported
00223 }
00224 

Generated on Mon Aug 20 17:48:46 2007 for id3lib by  doxygen 1.5.2