#include <tdebug.h>
#include <tagunion.h>
#include <id3v1tag.h>
+#include <id3v2header.h>
#include <tpropertymap.h>
#include "apefile.h"
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;
}
long ID3v1Location;
+ ID3v2::Header *ID3v2Header;
+ long ID3v2Location;
+ uint ID3v2Size;
+
TagUnion tag;
Properties *properties;
bool hasAPE;
bool hasID3v1;
+ bool hasID3v2;
};
////////////////////////////////////////////////////////////////////////////////
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();
// 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);
}
}
return -1;
}
+
+long APE::File::findID3v2()
+{
+ if(!isValid())
+ return -1;
+
+ seek(0);
+
+ if(readBlock(3) == ID3v2::Header::fileIdentifier())
+ return 0;
+
+ return -1;
+}
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()
// 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);
return;
}
- if(!commonHeader.startsWith("MAC ")) {
- debug("APE::Properties::read() -- invalid header signiture.");
- return;
- }
-
d->version = commonHeader.toUShort(4, false);
if(d->version >= 3980)
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);
}
}
-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
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.
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);