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
00028
00029
00030
00031
00032
00033
00034
00035
00036
#include "tag_impl.h"
00037
00038
#include "io_strings.h"
00039
00040
using namespace dami;
00041
00042
namespace
00043
{
00044
bool parseFrames(
ID3_TagImpl& tag,
ID3_Reader& rdr)
00045 {
00046
ID3_Reader::pos_type beg = rdr.
getCur();
00047
io::ExitTrigger et(rdr, beg);
00048
ID3_Reader::pos_type last_pos = beg;
00049 size_t totalSize = 0;
00050 size_t frameSize = 0;
00051
while (!rdr.
atEnd() && rdr.
peekChar() !=
'\0')
00052 {
00053 ID3D_NOTICE(
"id3::v2::parseFrames(): rdr.getBeg() = " << rdr.
getBeg() );
00054 ID3D_NOTICE(
"id3::v2::parseFrames(): rdr.getCur() = " << rdr.
getCur() );
00055 ID3D_NOTICE(
"id3::v2::parseFrames(): rdr.getEnd() = " << rdr.
getEnd() );
00056 last_pos = rdr.
getCur();
00057
ID3_Frame* f =
new ID3_Frame;
00058 f->SetSpec(tag.
GetSpec());
00059
bool goodParse = f->Parse(rdr);
00060 frameSize = rdr.
getCur() - last_pos;
00061 ID3D_NOTICE(
"id3::v2::parseFrames(): frameSize = " << frameSize );
00062 totalSize += frameSize;
00063
00064
if (frameSize == 0)
00065 {
00066
00067
00068 ID3D_WARNING(
"id3::v2::parseFrames(): frame size is 0, can't " <<
00069
"continue parsing frames");
00070
delete f;
00071
00072
break;
00073 }
00074
else if (!goodParse)
00075 {
00076
00077 ID3D_WARNING(
"id3::v2::parseFrames(): bad parse, deleting frame");
00078
delete f;
00079 }
00080
else if (f->GetID() !=
ID3FID_METACOMPRESSION)
00081 {
00082 ID3D_NOTICE(
"id3::v2::parseFrames(): attaching non-compressed " <<
00083
"frame");
00084
00085 tag.
AttachFrame(f);
00086 }
00087
else
00088 {
00089 ID3D_NOTICE(
"id3::v2::parseFrames(): parsing ID3v2.2.1 " <<
00090
"compressed frame");
00091
00092
00093
ID3_Field* fld = f->GetField(ID3FN_DATA);
00094
if (fld)
00095 {
00096
ID3_MemoryReader mr(fld->
GetRawBinary(), fld->
BinSize());
00097
ID3_Reader::char_type ch = mr.
readChar();
00098
if (ch !=
'z')
00099 {
00100
00101 ID3D_WARNING(
"id3::v2::parseFrames(): unknown compression id " <<
00102
" = '" << ch <<
"'" );
00103 }
00104
else
00105 {
00106 uint32 newSize = io::readBENumber(mr,
sizeof(uint32));
00107 size_t oldSize = f->GetDataSize() -
sizeof(uint32) - 1;
00108
io::CompressedReader cr(mr, newSize);
00109 parseFrames(tag, cr);
00110
if (!cr.
atEnd())
00111 {
00112
00113
00114 ID3D_WARNING(
"id3::v2::parseFrames(): didn't parse entire " <<
00115
"id3v2.2.1 compressed memory stream");
00116 }
00117 }
00118 }
00119
delete f;
00120 }
00121 et.
setExitPos(rdr.
getCur());
00122 }
00123
if (rdr.
peekChar() ==
'\0')
00124 {
00125 ID3D_NOTICE(
"id3::v2::parseFrames: done parsing, padding at postion " <<
00126 rdr.
getCur() );
00127 }
00128
else
00129 {
00130 ID3D_NOTICE(
"id3::v2::parseFrames: done parsing, [cur, end] = [" <<
00131 rdr.
getCur() <<
", " << rdr.
getEnd() <<
"]" );
00132 }
00133
return true;
00134 }
00135 };
00136
00137
bool id3::v2::parse(
ID3_TagImpl& tag,
ID3_Reader& reader)
00138 {
00139
ID3_Reader::pos_type beg = reader.
getCur();
00140
io::ExitTrigger et(reader);
00141
00142
ID3_TagHeader hdr;
00143
00144
io::WindowedReader wr(reader, ID3_TagHeader::SIZE);
00145
00146
if (!hdr.
Parse(wr) || wr.
getCur() == beg)
00147 {
00148 ID3D_NOTICE(
"id3::v2::parse(): parsing header failes" );
00149
return false;
00150 }
00151
if (hdr.
GetExtended())
00152 {
00153 hdr.
ParseExtended(reader);
00154 }
00155 tag.
SetSpec(hdr.
GetSpec());
00156
00157 size_t dataSize = hdr.
GetDataSize();
00158 ID3D_NOTICE(
"ID3_TagImpl::Parse(ID3_Reader&): dataSize = " << dataSize);
00159
00160 wr.
setWindow(wr.
getCur(), dataSize);
00161 et.
setExitPos(wr.
getEnd());
00162
00163 ID3D_NOTICE(
"ID3_TagImpl::Parse(ID3_Reader&): data window beg = " << wr.
getBeg() );
00164 ID3D_NOTICE(
"ID3_TagImpl::Parse(ID3_Reader&): data window cur = " << wr.
getCur() );
00165 ID3D_NOTICE(
"ID3_TagImpl::Parse(ID3_Reader&): data window end = " << wr.
getEnd() );
00166 tag.
SetExtended(hdr.
GetExtended());
00167
if (!hdr.
GetUnsync())
00168 {
00169 tag.
SetUnsync(
false);
00170 parseFrames(tag, wr);
00171 }
00172
else
00173 {
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 tag.
SetUnsync(
true);
00185 BString raw = io::readAllBinary(wr);
00186
io::BStringReader bsr(raw);
00187
io::UnsyncedReader ur(bsr);
00188 ID3D_NOTICE(
"ID3_TagImpl::Parse(ID3_Reader&): unsync beg = " << ur.
getBeg() );
00189 ID3D_NOTICE(
"ID3_TagImpl::Parse(ID3_Reader&): unsync cur = " << ur.
getCur() );
00190 ID3D_NOTICE(
"ID3_TagImpl::Parse(ID3_Reader&): unsync end = " << ur.
getEnd() );
00191
00192
00193
00194
00195
00196
00197 BString synced = io::readAllBinary(ur);
00198
io::BStringReader sr(synced);
00199 parseFrames(tag, sr);
00200 }
00201
00202
return true;
00203 }
00204
00205 void ID3_TagImpl::ParseFile()
00206 {
00207 ifstream file;
00208
if (
ID3E_NoError != openReadableFile(this->GetFileName(), file))
00209 {
00210
00211
return;
00212 }
00213
ID3_IFStreamReader ifsr(file);
00214
ParseReader(ifsr);
00215 file.close();
00216 }
00217
00218
00219 void ID3_TagImpl::ParseReader(
ID3_Reader &reader)
00220 {
00221 size_t mp3_core_size;
00222 size_t bytes_till_sync;
00223
00224
io::WindowedReader wr(reader);
00225 wr.
setBeg(wr.
getCur());
00226
00227 _file_tags.
clear();
00228 _file_size = reader.
getEnd();
00229
00230
ID3_Reader::pos_type beg = wr.
getBeg();
00231 ID3_Reader::pos_type cur = wr.
getCur();
00232 ID3_Reader::pos_type
end = wr.
getEnd();
00233
00234 ID3_Reader::pos_type last = cur;
00235
00236
if (_tags_to_parse.
test(
ID3TT_ID3V2))
00237 {
00238
do
00239 {
00240 last = cur;
00241
00242
if (id3::v2::parse(*
this, wr))
00243 {
00244 _file_tags.
add(
ID3TT_ID3V2);
00245 }
00246 cur = wr.
getCur();
00247 wr.
setBeg(cur);
00248 }
while (!wr.
atEnd() && cur > last);
00249 }
00250
00251
if (!wr.
atEnd() && wr.
peekChar() ==
'\0')
00252 {
00253 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): found padding outside tag" );
00254
do
00255 {
00256 last = cur;
00257 cur = wr.
getCur() + 1;
00258 wr.
setBeg(cur);
00259 wr.
setCur(cur);
00260 }
while (!wr.
atEnd() && cur > last && wr.
peekChar() ==
'\0');
00261 }
00262
if (!wr.
atEnd() && _file_size - (cur - beg) > 4 && wr.
peekChar() == 255)
00263 {
00264 wr.
setCur(cur + 1);
00265
if (wr.
readChar() ==
'\0' && wr.
readChar() ==
'\0' && wr.
peekChar() ==
'\0')
00266 {
00267 cur += 3;
00268
do
00269 {
00270 last = cur;
00271 cur = wr.
getCur() + 1;
00272 wr.
setBeg(cur);
00273 wr.
setCur(cur);
00274 }
while (!wr.
atEnd() && cur > last && wr.
peekChar() ==
'\0');
00275 }
00276
else
00277 wr.
setCur(cur);
00278 }
00279 _prepended_bytes = cur - beg;
00280
00281
00282
00283 beg = wr.
getBeg();
00284
if (!wr.
atEnd() && wr.
peekChar() != 0xFF)
00285 {
00286 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): Didn't find mp3 sync byte" );
00287
if ((_file_size - (cur - beg)) >= 4)
00288 {
00289
unsigned char buf[5];
00290 wr.
readChars(buf, 4);
00291 buf[4] =
'\0';
00292
00293
if (strncmp((
char*)buf,
"RIFF", 4) == 0 || strncmp((
char*)buf,
"RIFX", 4) == 0)
00294 {
00295
00296 cur = wr.
getCur() + 4;
00297 wr.
setCur(cur);
00298
00299
if (!wr.
atEnd() && wr.
peekChar() != 0xFF)
00300 {
00301
do
00302 {
00303 last = cur;
00304 cur = wr.
getCur() + 1;
00305 wr.
setCur(cur);
00306 }
while (!wr.
atEnd() && cur > last && wr.
peekChar() != 0xFF);
00307 }
00308 }
00309
else if (strncmp((
char*)buf,
"fLaC", 4) == 0)
00310 {
00311 beg = cur;
00312 }
00313
else
00314 {
00315
00316 cur = cur + 1;
00317 wr.
setCur(cur);
00318
00319
if (!wr.
atEnd() && wr.
peekChar() != 0xFF)
00320 {
00321
do
00322 {
00323 last = cur;
00324 cur = wr.
getCur() + 1;
00325 wr.
setCur(cur);
00326 }
while (!wr.
atEnd() && cur > last && wr.
peekChar() != 0xFF);
00327 }
00328 }
00329 }
00330
else
00331 {
00332 beg = cur;
00333
00334
00335 }
00336 }
00337 bytes_till_sync = cur - beg;
00338
00339 cur = wr.
setCur(end);
00340
if (_file_size > _prepended_bytes)
00341 {
00342
do
00343 {
00344 last = cur;
00345 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): beg = " << wr.
getBeg() );
00346 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): cur = " << wr.
getCur() );
00347 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): end = " << wr.
getEnd() );
00348
00349 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): musicmatch? cur = " << wr.
getCur() );
00350
if (_tags_to_parse.
test(
ID3TT_MUSICMATCH) && mm::parse(*
this, wr))
00351 {
00352 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): musicmatch! cur = " << wr.
getCur() );
00353 _file_tags.
add(
ID3TT_MUSICMATCH);
00354 wr.
setEnd(wr.
getCur());
00355 }
00356 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): lyr3v1? cur = " << wr.
getCur() );
00357
if (_tags_to_parse.
test(
ID3TT_LYRICS3) && lyr3::v1::parse(*
this, wr))
00358 {
00359 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): lyr3v1! cur = " << wr.
getCur() );
00360 _file_tags.
add(
ID3TT_LYRICS3);
00361 wr.
setEnd(wr.
getCur());
00362 }
00363 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): lyr3v2? cur = " << wr.
getCur() );
00364
if (_tags_to_parse.
test(
ID3TT_LYRICS3V2) && lyr3::v2::parse(*
this, wr))
00365 {
00366 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): lyr3v2! cur = " << wr.
getCur() );
00367 _file_tags.
add(
ID3TT_LYRICS3V2);
00368 cur = wr.
getCur();
00369 wr.
setCur(wr.
getEnd());
00370
00371 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): id3v1? cur = " << wr.
getCur() );
00372
if (_tags_to_parse.
test(
ID3TT_ID3V1) && id3::v1::parse(*
this, wr))
00373 {
00374 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): id3v1! cur = " << wr.
getCur() );
00375 _file_tags.
add(
ID3TT_ID3V1);
00376 }
00377 wr.
setCur(cur);
00378 wr.
setEnd(cur);
00379 }
00380 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): id3v1? cur = " << wr.
getCur() );
00381
if (_tags_to_parse.
test(
ID3TT_ID3V1) && id3::v1::parse(*
this, wr))
00382 {
00383 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): id3v1! cur = " << wr.
getCur() );
00384 wr.
setEnd(wr.
getCur());
00385 _file_tags.
add(
ID3TT_ID3V1);
00386 }
00387 cur = wr.
getCur();
00388 }
while (cur != last);
00389 _appended_bytes = end - cur;
00390
00391
00392 mp3_core_size = (_file_size - _appended_bytes) - (_prepended_bytes + bytes_till_sync);
00393
if (mp3_core_size >= 4)
00394 {
00395 wr.
setBeg(_prepended_bytes + bytes_till_sync);
00396 wr.
setCur(_prepended_bytes + bytes_till_sync);
00397 wr.
setEnd(_file_size - _appended_bytes);
00398
00399 _mp3_info =
new Mp3Info;
00400 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): mp3header? cur = " << wr.
getCur() );
00401
00402
if (_mp3_info->
Parse(wr, mp3_core_size))
00403 {
00404 ID3D_NOTICE(
"ID3_TagImpl::ParseReader(): mp3header! cur = " << wr.
getCur() );
00405 }
00406
else
00407 {
00408
delete _mp3_info;
00409 _mp3_info =
NULL;
00410 }
00411 }
00412 }
00413
else
00414 this->
SetPadding(
false);
00415 }
00416