APE: Find an ID3v2 tag and calculate the stream length in APE::File.

This commit is contained in:
Tsuda Kageyu 2015-06-12 16:40:03 +09:00
parent f15fe869a5
commit dfee7020da
4 changed files with 81 additions and 65 deletions

View File

@ -36,6 +36,7 @@
#include <tdebug.h>
#include <tagunion.h>
#include <id3v1tag.h>
#include <id3v2header.h>
#include <tpropertymap.h>
#include "apefile.h"
@ -57,12 +58,17 @@ public:
APELocation(-1),
APESize(0),
ID3v1Location(-1),
ID3v2Header(0),
ID3v2Location(-1),
ID3v2Size(0),
properties(0),
hasAPE(false),
hasID3v1(false) {}
hasID3v1(false),
hasID3v2(false) {}
~FilePrivate()
{
delete ID3v2Header;
delete properties;
}
@ -71,6 +77,10 @@ public:
long ID3v1Location;
ID3v2::Header *ID3v2Header;
long ID3v2Location;
uint ID3v2Size;
TagUnion tag;
Properties *properties;
@ -80,6 +90,7 @@ public:
bool hasAPE;
bool hasID3v1;
bool hasID3v2;
};
////////////////////////////////////////////////////////////////////////////////
@ -251,6 +262,17 @@ bool APE::File::hasID3v1Tag() const
void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
{
// Look for an ID3v2 tag
d->ID3v2Location = findID3v2();
if(d->ID3v2Location >= 0) {
seek(d->ID3v2Location);
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
d->ID3v2Size = d->ID3v2Header->completeTagSize();
d->hasID3v2 = true;
}
// Look for an ID3v1 tag
d->ID3v1Location = findID3v1();
@ -277,7 +299,25 @@ void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesSty
// Look for APE audio properties
if(readProperties) {
d->properties = new Properties(this);
long streamLength;
if(d->hasAPE)
streamLength = d->APELocation;
else if(d->hasID3v1)
streamLength = d->ID3v1Location;
else
streamLength = length();
if(d->hasID3v2) {
seek(d->ID3v2Location + d->ID3v2Size);
streamLength -= (d->ID3v2Location + d->ID3v2Size);
}
else {
seek(0);
}
d->properties = new Properties(this, streamLength);
}
}
@ -312,3 +352,16 @@ long APE::File::findID3v1()
return -1;
}
long APE::File::findID3v2()
{
if(!isValid())
return -1;
seek(0);
if(readBlock(3) == ID3v2::Header::fileIdentifier())
return 0;
return -1;
}

View File

@ -216,8 +216,9 @@ namespace TagLib {
File &operator=(const File &);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
long findID3v1();
long findAPE();
long findID3v1();
long findID3v2();
class FilePrivate;
FilePrivate *d;

View File

@ -67,7 +67,14 @@ APE::Properties::Properties(File *file, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
read(file);
debug("APE::Properties::Properties() -- This constructor is no longer used.");
}
APE::Properties::Properties(File *file, long streamLength, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
read(file, streamLength);
}
APE::Properties::~Properties()
@ -124,12 +131,14 @@ TagLib::uint APE::Properties::sampleFrames() const
// private members
////////////////////////////////////////////////////////////////////////////////
void APE::Properties::read(File *file)
void APE::Properties::read(File *file, long streamLength)
{
// First we are searching the descriptor
const long offset = findDescriptor(file);
if(offset < 0)
const long offset = file->find("MAC ", file->tell());
if(offset < 0) {
debug("APE::Properties::read() -- APE descriptor not found");
return;
}
// Then we read the header common for all versions of APE
file->seek(offset);
@ -139,11 +148,6 @@ void APE::Properties::read(File *file)
return;
}
if(!commonHeader.startsWith("MAC ")) {
debug("APE::Properties::read() -- invalid header signiture.");
return;
}
d->version = commonHeader.toUShort(4, false);
if(d->version >= 3980)
@ -151,14 +155,6 @@ void APE::Properties::read(File *file)
else
analyzeOld(file);
long streamLength = file->length() - offset;
if(file->hasID3v1Tag())
streamLength -= 128;
if(file->hasAPETag())
streamLength -= file->APETag()->footer()->completeTagSize();
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
@ -166,45 +162,6 @@ void APE::Properties::read(File *file)
}
}
long APE::Properties::findDescriptor(File *file)
{
const long ID3v2Location = findID3v2(file);
long ID3v2OriginalSize = 0;
bool hasID3v2 = false;
if(ID3v2Location >= 0) {
const ID3v2::Tag tag(file, ID3v2Location);
ID3v2OriginalSize = tag.header()->completeTagSize();
if(tag.header()->tagSize() > 0)
hasID3v2 = true;
}
long offset = 0;
if(hasID3v2)
offset = file->find("MAC ", ID3v2Location + ID3v2OriginalSize);
else
offset = file->find("MAC ");
if(offset < 0) {
debug("APE::Properties::findDescriptor() -- APE descriptor not found");
return -1;
}
return offset;
}
long APE::Properties::findID3v2(File *file)
{
if(!file->isValid())
return -1;
file->seek(0);
if(file->readBlock(3) == ID3v2::Header::fileIdentifier())
return 0;
return -1;
}
void APE::Properties::analyzeCurrent(File *file)
{
// Read the descriptor

View File

@ -51,9 +51,17 @@ namespace TagLib {
public:
/*!
* Create an instance of APE::Properties with the data read from the
* ByteVector \a data.
* APE::File \a file.
*
* \deprecated
*/
Properties(File *f, ReadStyle style = Average);
Properties(File *file, ReadStyle style = Average);
/*!
* Create an instance of APE::Properties with the data read from the
* APE::File \a file.
*/
Properties(File *file, long streamLength, ReadStyle style = Average);
/*!
* Destroys this APE::Properties instance.
@ -121,10 +129,7 @@ namespace TagLib {
Properties(const Properties &);
Properties &operator=(const Properties &);
void read(File *file);
long findDescriptor(File *file);
long findID3v2(File *file);
void read(File *file, long streamLength);
void analyzeCurrent(File *file);
void analyzeOld(File *file);