id3lib
3.8.3
|
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