00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #if defined HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030
00031
00032
00033 #include <zlib.h>
00034 #include <string.h>
00035 #include <memory.h>
00036
00037 #include "tag_impl.h"
00038 #include "utils.h"
00039 #include "io_decorators.h"
00040 #include "io_helpers.h"
00041 #include "io_strings.h"
00042 #include "readers.h"
00043
00044 using namespace dami;
00045
00046 namespace
00047 {
00048 bool parseFrames(ID3_TagImpl& tag, ID3_Reader& rdr)
00049 {
00050 ID3_Reader::pos_type beg = rdr.getCur();
00051 io::ExitTrigger et(rdr, beg);
00052 ID3_Reader::pos_type last_pos = beg;
00053 size_t totalSize = 0;
00054 size_t frameSize = 0;
00055 while (!rdr.atEnd() && rdr.peekChar() != '\0')
00056 {
00057 ID3D_NOTICE( "id3::v2::parseFrames(): rdr.getBeg() = " << rdr.getBeg() );
00058 ID3D_NOTICE( "id3::v2::parseFrames(): rdr.getCur() = " << rdr.getCur() );
00059 ID3D_NOTICE( "id3::v2::parseFrames(): rdr.getEnd() = " << rdr.getEnd() );
00060 last_pos = rdr.getCur();
00061 ID3_Frame* f = new ID3_Frame;
00062 f->SetSpec(tag.GetSpec());
00063 bool goodParse = f->Parse(rdr);
00064 frameSize = rdr.getCur() - last_pos;
00065 ID3D_NOTICE( "id3::v2::parseFrames(): frameSize = " << frameSize );
00066 totalSize += frameSize;
00067
00068 if (frameSize == 0)
00069 {
00070
00071
00072 ID3D_WARNING( "id3::v2::parseFrames(): frame size is 0, can't " <<
00073 "continue parsing frames");
00074 delete f;
00075
00076 break;
00077 }
00078 else if (!goodParse)
00079 {
00080
00081 ID3D_WARNING( "id3::v2::parseFrames(): bad parse, deleting frame");
00082 delete f;
00083 }
00084 else if (f->GetID() != ID3FID_METACOMPRESSION)
00085 {
00086 ID3D_NOTICE( "id3::v2::parseFrames(): attaching non-compressed " <<
00087 "frame");
00088
00089 tag.AttachFrame(f);
00090 }
00091 else
00092 {
00093 ID3D_NOTICE( "id3::v2::parseFrames(): parsing ID3v2.2.1 " <<
00094 "compressed frame");
00095
00096
00097 ID3_Field* fld = f->GetField(ID3FN_DATA);
00098 if (fld)
00099 {
00100 ID3_MemoryReader mr(fld->GetRawBinary(), fld->BinSize());
00101 ID3_Reader::char_type ch = mr.readChar();
00102 if (ch != 'z')
00103 {
00104
00105 ID3D_WARNING( "id3::v2::parseFrames(): unknown compression id " <<
00106 " = '" << ch << "'" );
00107 }
00108 else
00109 {
00110 uint32 newSize = io::readBENumber(mr, sizeof(uint32));
00111 size_t oldSize = f->GetDataSize() - sizeof(uint32) - 1;
00112 io::CompressedReader cr(mr, newSize);
00113 parseFrames(tag, cr);
00114 if (!cr.atEnd())
00115 {
00116
00117
00118 ID3D_WARNING( "id3::v2::parseFrames(): didn't parse entire " <<
00119 "id3v2.2.1 compressed memory stream");
00120 }
00121 }
00122 }
00123 delete f;
00124 }
00125 et.setExitPos(rdr.getCur());
00126 }
00127 if (rdr.peekChar() == '\0')
00128 {
00129 ID3D_NOTICE( "id3::v2::parseFrames: done parsing, padding at postion " <<
00130 rdr.getCur() );
00131 }
00132 else
00133 {
00134 ID3D_NOTICE( "id3::v2::parseFrames: done parsing, [cur, end] = [" <<
00135 rdr.getCur() << ", " << rdr.getEnd() << "]" );
00136 }
00137 return true;
00138 }
00139 };
00140
00141 bool id3::v2::parse(ID3_TagImpl& tag, ID3_Reader& reader)
00142 {
00143 ID3_Reader::pos_type beg = reader.getCur();
00144 io::ExitTrigger et(reader);
00145
00146 ID3_TagHeader hdr;
00147
00148 io::WindowedReader wr(reader, ID3_TagHeader::SIZE);
00149
00150 if (!hdr.Parse(wr) || wr.getCur() == beg)
00151 {
00152 ID3D_NOTICE( "id3::v2::parse(): parsing header failes" );
00153 return false;
00154 }
00155
00156 tag.SetSpec(hdr.GetSpec());
00157
00158 size_t dataSize = hdr.GetDataSize();
00159 ID3D_NOTICE( "ID3_TagImpl::Parse(ID3_Reader&): dataSize = " << dataSize);
00160
00161 wr.setWindow(wr.getCur(), dataSize);
00162 et.setExitPos(wr.getEnd());
00163
00164 ID3D_NOTICE( "ID3_TagImpl::Parse(ID3_Reader&): data window beg = " << wr.getBeg() );
00165 ID3D_NOTICE( "ID3_TagImpl::Parse(ID3_Reader&): data window cur = " << wr.getCur() );
00166 ID3D_NOTICE( "ID3_TagImpl::Parse(ID3_Reader&): data window end = " << wr.getEnd() );
00167 tag.SetExtended(hdr.GetExtended());
00168 if (!hdr.GetUnsync())
00169 {
00170 tag.SetUnsync(false);
00171 parseFrames(tag, wr);
00172 }
00173 else
00174 {
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 tag.SetUnsync(true);
00186 BString raw = io::readAllBinary(wr);
00187 io::BStringReader bsr(raw);
00188 io::UnsyncedReader ur(bsr);
00189 ID3D_NOTICE( "ID3_TagImpl::Parse(ID3_Reader&): unsync beg = " << ur.getBeg() );
00190 ID3D_NOTICE( "ID3_TagImpl::Parse(ID3_Reader&): unsync cur = " << ur.getCur() );
00191 ID3D_NOTICE( "ID3_TagImpl::Parse(ID3_Reader&): unsync end = " << ur.getEnd() );
00192
00193
00194
00195
00196
00197
00198 BString synced = io::readAllBinary(ur);
00199 io::BStringReader sr(synced);
00200 parseFrames(tag, sr);
00201 }
00202
00203 return true;
00204 }
00205
00206 void ID3_TagImpl::ParseFile()
00207 {
00208 ifstream file;
00209 if (ID3E_NoError != openReadableFile(this->GetFileName(), file))
00210 {
00211
00212 return;
00213 }
00214 ID3_IFStreamReader ifsr(file);
00215 io::WindowedReader wr(ifsr);
00216 wr.setBeg(wr.getCur());
00217
00218 _file_tags.clear();
00219 _file_size = getFileSize(file);
00220
00221 ID3_Reader::pos_type beg = wr.getBeg();
00222 ID3_Reader::pos_type cur = wr.getCur();
00223 ID3_Reader::pos_type end = wr.getEnd();
00224
00225 ID3_Reader::pos_type last = cur;
00226
00227 if (_tags_to_parse.test(ID3TT_ID3V2))
00228 {
00229 do
00230 {
00231 last = cur;
00232
00233 if (id3::v2::parse(*this, wr))
00234 {
00235 _file_tags.add(ID3TT_ID3V2);
00236 }
00237 cur = wr.getCur();
00238 wr.setBeg(cur);
00239 } while (!wr.atEnd() && cur > last);
00240 }
00241
00242 _prepended_bytes = cur - beg;
00243
00244 cur = wr.setCur(end);
00245 do
00246 {
00247 last = cur;
00248 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): beg = " << wr.getBeg() );
00249 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): cur = " << wr.getCur() );
00250 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): end = " << wr.getEnd() );
00251
00252 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): musicmatch? cur = " << wr.getCur() );
00253 if (_tags_to_parse.test(ID3TT_MUSICMATCH) && mm::parse(*this, wr))
00254 {
00255 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): musicmatch! cur = " << wr.getCur() );
00256 _file_tags.add(ID3TT_MUSICMATCH);
00257 wr.setEnd(wr.getCur());
00258 }
00259 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): lyr3v1? cur = " << wr.getCur() );
00260 if (_tags_to_parse.test(ID3TT_LYRICS3) && lyr3::v1::parse(*this, wr))
00261 {
00262 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): lyr3v1! cur = " << wr.getCur() );
00263 _file_tags.add(ID3TT_LYRICS3);
00264 wr.setEnd(wr.getCur());
00265 }
00266 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): lyr3v2? cur = " << wr.getCur() );
00267 if (_tags_to_parse.test(ID3TT_LYRICS3V2) && lyr3::v2::parse(*this, wr))
00268 {
00269 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): lyr3v2! cur = " << wr.getCur() );
00270 _file_tags.add(ID3TT_ID3V1);
00271 wr.setEnd(wr.getCur());
00272 }
00273 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): id3v1? cur = " << wr.getCur() );
00274 if (_tags_to_parse.test(ID3TT_ID3V1) && id3::v1::parse(*this, wr))
00275 {
00276 ID3D_NOTICE( "ID3_TagImpl::ParseFile(): id3v1! cur = " << wr.getCur() );
00277 wr.setEnd(wr.getCur());
00278 _file_tags.add(ID3TT_ID3V1);
00279 }
00280 cur = wr.getCur();
00281 } while (cur != last);
00282 _appended_bytes = end - cur;
00283 }