Format taglib sources

This commit is contained in:
Jonas Kvinge
2020-06-13 19:02:42 +02:00
parent 72bff7fa35
commit 4ce099294c
224 changed files with 12905 additions and 15623 deletions

View File

@@ -30,128 +30,110 @@
using namespace Strawberry_TagLib::TagLib;
using namespace DSDIFF::DIIN;
class DSDIFF::DIIN::Tag::TagPrivate
{
public:
TagPrivate()
{
class DSDIFF::DIIN::Tag::TagPrivate {
public:
TagPrivate() {
}
String title;
String artist;
};
DSDIFF::DIIN::Tag::Tag() : Strawberry_TagLib::TagLib::Tag()
{
DSDIFF::DIIN::Tag::Tag() : Strawberry_TagLib::TagLib::Tag() {
d = new TagPrivate;
}
DSDIFF::DIIN::Tag::~Tag()
{
DSDIFF::DIIN::Tag::~Tag() {
delete d;
}
String DSDIFF::DIIN::Tag::title() const
{
String DSDIFF::DIIN::Tag::title() const {
return d->title;
}
String DSDIFF::DIIN::Tag::artist() const
{
String DSDIFF::DIIN::Tag::artist() const {
return d->artist;
}
String DSDIFF::DIIN::Tag::album() const
{
String DSDIFF::DIIN::Tag::album() const {
return String();
}
String DSDIFF::DIIN::Tag::comment() const
{
String DSDIFF::DIIN::Tag::comment() const {
return String();
}
String DSDIFF::DIIN::Tag::genre() const
{
String DSDIFF::DIIN::Tag::genre() const {
return String();
}
unsigned int DSDIFF::DIIN::Tag::year() const
{
unsigned int DSDIFF::DIIN::Tag::year() const {
return 0;
}
unsigned int DSDIFF::DIIN::Tag::track() const
{
unsigned int DSDIFF::DIIN::Tag::track() const {
return 0;
}
void DSDIFF::DIIN::Tag::setTitle(const String &title)
{
if(title.isNull() || title.isEmpty())
void DSDIFF::DIIN::Tag::setTitle(const String &title) {
if (title.isNull() || title.isEmpty())
d->title = String();
else
d->title = title;
}
void DSDIFF::DIIN::Tag::setArtist(const String &artist)
{
if(artist.isNull() || artist.isEmpty())
void DSDIFF::DIIN::Tag::setArtist(const String &artist) {
if (artist.isNull() || artist.isEmpty())
d->artist = String();
else
d->artist = artist;
}
void DSDIFF::DIIN::Tag::setAlbum(const String &)
{
void DSDIFF::DIIN::Tag::setAlbum(const String &) {
}
void DSDIFF::DIIN::Tag::setComment(const String &)
{
void DSDIFF::DIIN::Tag::setComment(const String &) {
}
void DSDIFF::DIIN::Tag::setGenre(const String &)
{
void DSDIFF::DIIN::Tag::setGenre(const String &) {
}
void DSDIFF::DIIN::Tag::setYear(unsigned int)
{
void DSDIFF::DIIN::Tag::setYear(unsigned int) {
}
void DSDIFF::DIIN::Tag::setTrack(unsigned int)
{
void DSDIFF::DIIN::Tag::setTrack(unsigned int) {
}
PropertyMap DSDIFF::DIIN::Tag::properties() const
{
PropertyMap DSDIFF::DIIN::Tag::properties() const {
PropertyMap properties;
properties["TITLE"] = d->title;
properties["ARTIST"] = d->artist;
return properties;
}
PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps) {
PropertyMap properties(origProps);
properties.removeEmpty();
StringList oneValueSet;
if(properties.contains("TITLE")) {
if (properties.contains("TITLE")) {
d->title = properties["TITLE"].front();
oneValueSet.append("TITLE");
} else
}
else
d->title = String();
if(properties.contains("ARTIST")) {
if (properties.contains("ARTIST")) {
d->artist = properties["ARTIST"].front();
oneValueSet.append("ARTIST");
} else
}
else
d->artist = String();
// for each tag that has been set above, remove the first entry in the corresponding
// value list. The others will be returned as unsupported by this format.
for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
if(properties[*it].size() == 1)
for (StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
if (properties[*it].size() == 1)
properties.erase(*it);
else
properties[*it].erase(properties[*it].begin());
@@ -159,4 +141,3 @@ PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps)
return properties;
}

View File

@@ -31,102 +31,101 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace DSDIFF {
namespace DSDIFF {
namespace DIIN {
namespace DIIN {
/*!
/*!
* Tags from the Edited Master Chunk Info
*
* Only Title and Artist tags are supported
*/
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag
{
public:
Tag();
virtual ~Tag();
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
public:
Tag();
virtual ~Tag();
/*!
/*!
* Returns the track name; if no track name is present in the tag
* String() will be returned.
*/
String title() const;
String title() const;
/*!
/*!
* Returns the artist name; if no artist name is present in the tag
* String() will be returned.
*/
String artist() const;
String artist() const;
/*!
/*!
* Not supported. Therefore always returns String().
*/
String album() const;
String album() const;
/*!
/*!
* Not supported. Therefore always returns String().
*/
String comment() const;
String comment() const;
/*!
/*!
* Not supported. Therefore always returns String().
*/
String genre() const;
String genre() const;
/*!
/*!
* Not supported. Therefore always returns 0.
*/
unsigned int year() const;
unsigned int year() const;
/*!
/*!
* Not supported. Therefore always returns 0.
*/
unsigned int track() const;
unsigned int track() const;
/*!
/*!
* Sets the title to \a title. If \a title is String() then this
* value will be cleared.
*/
void setTitle(const String &title);
void setTitle(const String &title);
/*!
/*!
* Sets the artist to \a artist. If \a artist is String() then this
* value will be cleared.
*/
void setArtist(const String &artist);
void setArtist(const String &artist);
/*!
/*!
* Not supported and therefore ignored.
*/
void setAlbum(const String &album);
void setAlbum(const String &album);
/*!
/*!
* Not supported and therefore ignored.
*/
void setComment(const String &comment);
void setComment(const String &comment);
/*!
/*!
* Not supported and therefore ignored.
*/
void setGenre(const String &genre);
void setGenre(const String &genre);
/*!
/*!
* Not supported and therefore ignored.
*/
void setYear(unsigned int year);
void setYear(unsigned int year);
/*!
/*!
* Not supported and therefore ignored.
*/
void setTrack(unsigned int track);
void setTrack(unsigned int track);
/*!
/*!
* Implements the unified property interface -- export function.
* Since the DIIN tag is very limited, the exported map is as well.
*/
PropertyMap properties() const;
PropertyMap properties() const;
/*!
/*!
* Implements the unified property interface -- import function.
* Because of the limitations of the DIIN file tag, any tags besides
* TITLE and ARTIST, will be
@@ -134,19 +133,18 @@ namespace TagLib {
* all but the first will be contained in the returned map of unsupported
* properties.
*/
PropertyMap setProperties(const PropertyMap &);
PropertyMap setProperties(const PropertyMap &);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TagPrivate *d;
};
}
}
}
}
class TagPrivate;
TagPrivate *d;
};
} // namespace DIIN
} // namespace DSDIFF
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -37,70 +37,62 @@
using namespace Strawberry_TagLib::TagLib;
namespace
{
struct Chunk64
{
ByteVector name;
unsigned long long offset;
unsigned long long size;
char padding;
};
namespace {
struct Chunk64 {
ByteVector name;
unsigned long long offset;
unsigned long long size;
char padding;
};
typedef std::vector<Chunk64> ChunkList;
typedef std::vector<Chunk64> ChunkList;
int chunkIndex(const ChunkList &chunks, const ByteVector &id)
{
for (unsigned long int i = 0 ; i < chunks.size() ; i++) {
if(chunks[i].name == id)
return i;
}
return -1;
int chunkIndex(const ChunkList &chunks, const ByteVector &id) {
for (unsigned long int i = 0; i < chunks.size(); i++) {
if (chunks[i].name == id)
return i;
}
bool isValidChunkID(const ByteVector &name)
{
if(name.size() != 4)
return false;
for (int i = 0 ; i < 4 ; i++) {
if (name[i] < 32)
return false;
}
return true;
}
enum {
ID3v2Index = 0,
DIINIndex = 1
};
enum {
PROPChunk = 0,
DIINChunk = 1
};
return -1;
}
class DSDIFF::File::FilePrivate
{
public:
FilePrivate() :
endianness(BigEndian),
size(0),
isID3InPropChunk(false),
duplicateID3V2chunkIndex(-1),
properties(0),
id3v2TagChunkID("ID3 "),
hasID3v2(false),
hasDiin(false)
{
bool isValidChunkID(const ByteVector &name) {
if (name.size() != 4)
return false;
for (int i = 0; i < 4; i++) {
if (name[i] < 32)
return false;
}
return true;
}
enum {
ID3v2Index = 0,
DIINIndex = 1
};
enum {
PROPChunk = 0,
DIINChunk = 1
};
} // namespace
class DSDIFF::File::FilePrivate {
public:
FilePrivate() : endianness(BigEndian),
size(0),
isID3InPropChunk(false),
duplicateID3V2chunkIndex(-1),
properties(0),
id3v2TagChunkID("ID3 "),
hasID3v2(false),
hasDiin(false) {
childChunkIndex[ID3v2Index] = -1;
childChunkIndex[DIINIndex] = -1;
}
~FilePrivate()
{
~FilePrivate() {
delete properties;
}
@@ -135,12 +127,11 @@ public:
// static members
////////////////////////////////////////////////////////////////////////////////
bool DSDIFF::File::isSupported(IOStream *stream)
{
// A DSDIFF file has to start with "FRM8????????DSD ".
bool DSDIFF::File::isSupported(IOStream *stream) {
// A DSDIFF file has to start with "FRM8????????DSD ".
const ByteVector id = Utils::readHeader(stream, 16, false);
return (id.startsWith("FRM8") && id.containsAt("DSD ", 12));
const ByteVector id = Utils::readHeader(stream, 16, false);
return (id.startsWith("FRM8") && id.containsAt("DSD ", 12));
}
////////////////////////////////////////////////////////////////////////////////
@@ -148,107 +139,93 @@ bool DSDIFF::File::isSupported(IOStream *stream)
////////////////////////////////////////////////////////////////////////////////
DSDIFF::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file)
{
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file) {
d = new FilePrivate;
d->endianness = BigEndian;
if(isOpen())
if (isOpen())
read(readProperties, propertiesStyle);
}
DSDIFF::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream)
{
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream) {
d = new FilePrivate;
d->endianness = BigEndian;
if(isOpen())
if (isOpen())
read(readProperties, propertiesStyle);
}
DSDIFF::File::~File()
{
DSDIFF::File::~File() {
delete d;
}
Strawberry_TagLib::TagLib::Tag *DSDIFF::File::tag() const
{
Strawberry_TagLib::TagLib::Tag *DSDIFF::File::tag() const {
return &d->tag;
}
ID3v2::Tag *DSDIFF::File::ID3v2Tag(bool create) const
{
ID3v2::Tag *DSDIFF::File::ID3v2Tag(bool create) const {
return d->tag.access<ID3v2::Tag>(ID3v2Index, create);
}
bool DSDIFF::File::hasID3v2Tag() const
{
bool DSDIFF::File::hasID3v2Tag() const {
return d->hasID3v2;
}
DSDIFF::DIIN::Tag *DSDIFF::File::DIINTag(bool create) const
{
DSDIFF::DIIN::Tag *DSDIFF::File::DIINTag(bool create) const {
return d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, create);
}
bool DSDIFF::File::hasDIINTag() const
{
bool DSDIFF::File::hasDIINTag() const {
return d->hasDiin;
}
PropertyMap DSDIFF::File::properties() const
{
if(d->hasID3v2)
PropertyMap DSDIFF::File::properties() const {
if (d->hasID3v2)
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties();
return PropertyMap();
}
void DSDIFF::File::removeUnsupportedProperties(const StringList &unsupported)
{
if(d->hasID3v2)
void DSDIFF::File::removeUnsupportedProperties(const StringList &unsupported) {
if (d->hasID3v2)
d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(unsupported);
if(d->hasDiin)
if (d->hasDiin)
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->removeUnsupportedProperties(unsupported);
}
PropertyMap DSDIFF::File::setProperties(const PropertyMap &properties)
{
PropertyMap DSDIFF::File::setProperties(const PropertyMap &properties) {
return d->tag.access<ID3v2::Tag>(ID3v2Index, true)->setProperties(properties);
}
DSDIFF::Properties *DSDIFF::File::audioProperties() const
{
DSDIFF::Properties *DSDIFF::File::audioProperties() const {
return d->properties;
}
bool DSDIFF::File::save()
{
bool DSDIFF::File::save() {
return save(AllTags);
}
bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version)
{
if(readOnly()) {
bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version) {
if (readOnly()) {
debug("DSDIFF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
if (!isValid()) {
debug("DSDIFF::File::save() -- Trying to save invalid file.");
return false;
}
//if(strip == StripOthers || strip == StripAll)
//File::strip(static_cast<TagTypes>(AllTags & ~tags));
//File::strip(static_cast<TagTypes>(AllTags & ~tags));
// First: save ID3V2 chunk
ID3v2::Tag *id3v2Tag = d->tag.access<ID3v2::Tag>(ID3v2Index, false);
if(tags & ID3v2 && id3v2Tag) {
if(d->isID3InPropChunk) {
if(id3v2Tag && !id3v2Tag->isEmpty()) {
if (tags & ID3v2 && id3v2Tag) {
if (d->isID3InPropChunk) {
if (id3v2Tag && !id3v2Tag->isEmpty()) {
setChildChunkData(d->id3v2TagChunkID, id3v2Tag->render(version), PROPChunk);
d->hasID3v2 = true;
}
@@ -259,7 +236,7 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version)
}
}
else {
if(id3v2Tag && !id3v2Tag->isEmpty()) {
if (id3v2Tag && !id3v2Tag->isEmpty()) {
setRootChunkData(d->id3v2TagChunkID, id3v2Tag->render(version));
d->hasID3v2 = true;
}
@@ -275,8 +252,8 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version)
DSDIFF::DIIN::Tag *diinTag = d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false);
if(tags & DIIN && diinTag) {
if(!diinTag->title().isEmpty()) {
if (tags & DIIN && diinTag) {
if (!diinTag->title().isEmpty()) {
ByteVector diinTitle;
diinTitle.append(ByteVector::fromUInt(diinTag->title().size(), d->endianness == BigEndian));
diinTitle.append(ByteVector::fromCString(diinTag->title().toCString()));
@@ -285,7 +262,7 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version)
else
setChildChunkData("DITI", ByteVector(), DIINChunk);
if(!diinTag->artist().isEmpty()) {
if (!diinTag->artist().isEmpty()) {
ByteVector diinArtist;
diinArtist.append(ByteVector::fromUInt(diinTag->artist().size(), d->endianness == BigEndian));
diinArtist.append(ByteVector::fromCString(diinTag->artist().toCString()));
@@ -296,7 +273,7 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version)
}
// Third: remove the duplicate ID3V2 chunk (inside PROP chunk) if any
if(d->duplicateID3V2chunkIndex>=0) {
if (d->duplicateID3V2chunkIndex >= 0) {
setChildChunkData(d->duplicateID3V2chunkIndex, ByteVector(), PROPChunk);
d->duplicateID3V2chunkIndex = -1;
}
@@ -304,9 +281,8 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version)
return true;
}
void DSDIFF::File::strip(TagTypes tags)
{
if(tags & ID3v2) {
void DSDIFF::File::strip(TagTypes tags) {
if (tags & ID3v2) {
removeRootChunk("ID3 ");
removeRootChunk("id3 ");
d->hasID3v2 = false;
@@ -314,7 +290,7 @@ void DSDIFF::File::strip(TagTypes tags)
/// TODO: needs to also account for ID3v2 tags under the PROP chunk
}
if(tags & DIIN) {
if (tags & DIIN) {
removeRootChunk("DITI");
removeRootChunk("DIAR");
d->hasDiin = false;
@@ -326,35 +302,31 @@ void DSDIFF::File::strip(TagTypes tags)
// private members
////////////////////////////////////////////////////////////////////////////////
void DSDIFF::File::removeRootChunk(unsigned int i)
{
unsigned long long chunkSize = d->chunks[i].size + d->chunks[i].padding + 12;
void DSDIFF::File::removeRootChunk(unsigned int i) {
unsigned long long chunkSize = d->chunks[i].size + d->chunks[i].padding + 12;
d->size -= chunkSize;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
d->size -= chunkSize;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
removeBlock(d->chunks[i].offset - 12, chunkSize);
removeBlock(d->chunks[i].offset - 12, chunkSize);
// Update the internal offsets
// Update the internal offsets
for(unsigned long r = i + 1; r < d->chunks.size(); r++)
d->chunks[r].offset = d->chunks[r - 1].offset + 12
+ d->chunks[r - 1].size + d->chunks[r - 1].padding;
for (unsigned long r = i + 1; r < d->chunks.size(); r++)
d->chunks[r].offset = d->chunks[r - 1].offset + 12 + d->chunks[r - 1].size + d->chunks[r - 1].padding;
d->chunks.erase(d->chunks.begin() + i);
d->chunks.erase(d->chunks.begin() + i);
}
void DSDIFF::File::removeRootChunk(const ByteVector &id)
{
void DSDIFF::File::removeRootChunk(const ByteVector &id) {
int i = chunkIndex(d->chunks, id);
if(i >= 0)
if (i >= 0)
removeRootChunk(i);
}
void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data)
{
if(data.isEmpty()) {
void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data) {
if (data.isEmpty()) {
removeRootChunk(i);
return;
}
@@ -368,9 +340,9 @@ void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data)
// Now update the specific chunk
writeChunk(d->chunks[i].name,
data,
d->chunks[i].offset - 12,
d->chunks[i].size + d->chunks[i].padding + 12);
data,
d->chunks[i].offset - 12,
d->chunks[i].size + d->chunks[i].padding + 12);
d->chunks[i].size = data.size();
d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0;
@@ -380,16 +352,15 @@ void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data)
updateRootChunksStructure(i + 1);
}
void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &data)
{
if(d->chunks.size() == 0) {
void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &data) {
if (d->chunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return;
}
int i = chunkIndex(d->chunks, name);
if(i >= 0) {
if (i >= 0) {
setRootChunkData(i, data);
return;
}
@@ -404,10 +375,10 @@ void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &da
// Now add the chunk to the file
writeChunk(name,
data,
offset,
std::max<unsigned long long>(0, length() - offset),
(offset & 1) ? 1 : 0);
data,
offset,
std::max<unsigned long long>(0, length() - offset),
(offset & 1) ? 1 : 0);
Chunk64 chunk;
chunk.name = name;
@@ -418,53 +389,49 @@ void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &da
d->chunks.push_back(chunk);
}
void DSDIFF::File::removeChildChunk(unsigned int i, unsigned int childChunkNum)
{
ChunkList &childChunks = d->childChunks[childChunkNum];
void DSDIFF::File::removeChildChunk(unsigned int i, unsigned int childChunkNum) {
ChunkList &childChunks = d->childChunks[childChunkNum];
// Update global size
// Update global size
unsigned long long removedChunkTotalSize = childChunks[i].size + childChunks[i].padding + 12;
d->size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
unsigned long long removedChunkTotalSize = childChunks[i].size + childChunks[i].padding + 12;
d->size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// Update child chunk size
// Update child chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Remove the chunk
d->chunks[d->childChunkIndex[childChunkNum]].size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Remove the chunk
removeBlock(childChunks[i].offset - 12, removedChunkTotalSize);
removeBlock(childChunks[i].offset - 12, removedChunkTotalSize);
// Update the internal offsets
// For child chunks
// Update the internal offsets
// For child chunks
if((i + 1) < childChunks.size()) {
childChunks[i + 1].offset = childChunks[i].offset;
i++;
for(i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12
+ childChunks[i - 1].size + childChunks[i - 1].padding;
}
if ((i + 1) < childChunks.size()) {
childChunks[i + 1].offset = childChunks[i].offset;
i++;
for (i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12 + childChunks[i - 1].size + childChunks[i - 1].padding;
}
// And for root chunks
// And for root chunks
for(i = d->childChunkIndex[childChunkNum] + 1; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12
+ d->chunks[i - 1].size + d->chunks[i - 1].padding;
for (i = d->childChunkIndex[childChunkNum] + 1; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12 + d->chunks[i - 1].size + d->chunks[i - 1].padding;
childChunks.erase(childChunks.begin() + i);
childChunks.erase(childChunks.begin() + i);
}
void DSDIFF::File::setChildChunkData(unsigned int i,
const ByteVector &data,
unsigned int childChunkNum)
{
const ByteVector &data,
unsigned int childChunkNum) {
ChunkList &childChunks = d->childChunks[childChunkNum];
if(data.isEmpty()) {
if (data.isEmpty()) {
removeChildChunk(i, childChunkNum);
return;
}
@@ -481,42 +448,40 @@ void DSDIFF::File::setChildChunkData(unsigned int i,
d->chunks[d->childChunkIndex[childChunkNum]].size +=
((data.size() + 1) & ~1) - (childChunks[i].size + childChunks[i].padding);
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now update the specific chunk
writeChunk(childChunks[i].name,
data,
childChunks[i].offset - 12,
childChunks[i].size + childChunks[i].padding + 12);
data,
childChunks[i].offset - 12,
childChunks[i].size + childChunks[i].padding + 12);
childChunks[i].size = data.size();
childChunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Now update the internal offsets
// For child Chunks
for(i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12
+ childChunks[i - 1].size + childChunks[i - 1].padding;
for (i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12 + childChunks[i - 1].size + childChunks[i - 1].padding;
// And for root chunks
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
}
void DSDIFF::File::setChildChunkData(const ByteVector &name,
const ByteVector &data,
unsigned int childChunkNum)
{
const ByteVector &data,
unsigned int childChunkNum) {
ChunkList &childChunks = d->childChunks[childChunkNum];
if(childChunks.size() == 0) {
if (childChunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return;
}
for(unsigned int i = 0; i < childChunks.size(); i++) {
if(childChunks[i].name == name) {
for (unsigned int i = 0; i < childChunks.size(); i++) {
if (childChunks[i].name == name) {
setChildChunkData(i, data, childChunkNum);
return;
}
@@ -524,7 +489,7 @@ void DSDIFF::File::setChildChunkData(const ByteVector &name,
// Do not attempt to remove a non existing chunk
if(data.isEmpty())
if (data.isEmpty())
return;
// Couldn't find an existing chunk, so let's create a new one.
@@ -539,21 +504,20 @@ void DSDIFF::File::setChildChunkData(const ByteVector &name,
// And the child chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size += (offset & 1)
+ ((data.size() + 1) & ~1) + 12;
d->chunks[d->childChunkIndex[childChunkNum]].size += (offset & 1) + ((data.size() + 1) & ~1) + 12;
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now add the chunk to the file
unsigned long long nextRootChunkIdx = length();
if((d->childChunkIndex[childChunkNum] + 1) < static_cast<int>(d->chunks.size()))
if ((d->childChunkIndex[childChunkNum] + 1) < static_cast<int>(d->chunks.size()))
nextRootChunkIdx = d->chunks[d->childChunkIndex[childChunkNum] + 1].offset - 12;
writeChunk(name, data, offset,
std::max<unsigned long long>(0, nextRootChunkIdx - offset),
(offset & 1) ? 1 : 0);
std::max<unsigned long long>(0, nextRootChunkIdx - offset),
(offset & 1) ? 1 : 0);
// For root chunks
@@ -568,37 +532,31 @@ void DSDIFF::File::setChildChunkData(const ByteVector &name,
childChunks.push_back(chunk);
}
void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk)
{
for(unsigned int i = startingChunk; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12
+ d->chunks[i - 1].size + d->chunks[i - 1].padding;
void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk) {
for (unsigned int i = startingChunk; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12 + d->chunks[i - 1].size + d->chunks[i - 1].padding;
// Update childchunks structure as well
if(d->childChunkIndex[PROPChunk] >= static_cast<int>(startingChunk)) {
if (d->childChunkIndex[PROPChunk] >= static_cast<int>(startingChunk)) {
ChunkList &childChunksToUpdate = d->childChunks[PROPChunk];
if(childChunksToUpdate.size() > 0) {
if (childChunksToUpdate.size() > 0) {
childChunksToUpdate[0].offset = d->chunks[d->childChunkIndex[PROPChunk]].offset + 12;
for(unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12
+ childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
for (unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12 + childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
}
}
if(d->childChunkIndex[DIINChunk] >= static_cast<int>(startingChunk)) {
if (d->childChunkIndex[DIINChunk] >= static_cast<int>(startingChunk)) {
ChunkList &childChunksToUpdate = d->childChunks[DIINChunk];
if(childChunksToUpdate.size() > 0) {
if (childChunksToUpdate.size() > 0) {
childChunksToUpdate[0].offset = d->chunks[d->childChunkIndex[DIINChunk]].offset + 12;
for(unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12
+ childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
for (unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12 + childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
}
}
}
void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
{
void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) {
bool bigEndian = (d->endianness == BigEndian);
d->type = readBlock(4);
@@ -607,20 +565,19 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
// + 12: chunk header at least, fix for additional junk bytes
while(tell() + 12 <= length()) {
while (tell() + 12 <= length()) {
ByteVector chunkName = readBlock(4);
unsigned long long chunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(chunkName)) {
if (!isValidChunkID(chunkName)) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<unsigned long long>(tell()) + chunkSize >
static_cast<unsigned long long>(length())) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName
+ "' has invalid size (larger than the file size)");
if (static_cast<unsigned long long>(tell()) + chunkSize >
static_cast<unsigned long long>(length())) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)");
setValid(false);
break;
}
@@ -636,9 +593,9 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
if ((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
if ((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
@@ -656,36 +613,35 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
// For DST compressed frames
unsigned short dstFrameRate = 0;
for(unsigned int i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == "DSD ") {
for (unsigned int i = 0; i < d->chunks.size(); i++) {
if (d->chunks[i].name == "DSD ") {
lengthDSDSamplesTimeChannels = d->chunks[i].size * 8;
audioDataSizeinBytes = d->chunks[i].size;
}
else if(d->chunks[i].name == "DST ") {
else if (d->chunks[i].name == "DST ") {
// Now decode the chunks inside the DST chunk to read the DST Frame Information one
long long dstChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset);
audioDataSizeinBytes = d->chunks[i].size;
while(tell() + 12 <= dstChunkEnd) {
while (tell() + 12 <= dstChunkEnd) {
ByteVector dstChunkName = readBlock(4);
long long dstChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(dstChunkName)) {
if (!isValidChunkID(dstChunkName)) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + dstChunkSize > dstChunkEnd) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName
+ "' has invalid size (larger than the DST chunk)");
if (static_cast<long long>(tell()) + dstChunkSize > dstChunkEnd) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName + "' has invalid size (larger than the DST chunk)");
setValid(false);
break;
}
if(dstChunkName == "FRTE") {
if (dstChunkName == "FRTE") {
// Found the DST frame information chunk
dstNumFrames = readBlock(4).toUInt(bigEndian);
dstFrameRate = readBlock(2).toUShort(bigEndian);
@@ -697,33 +653,32 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
// Check padding
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
if ((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
if ((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
}
}
}
else if(d->chunks[i].name == "PROP") {
else if (d->chunks[i].name == "PROP") {
d->childChunkIndex[PROPChunk] = i;
// Now decodes the chunks inside the PROP chunk
long long propChunkEnd = d->chunks[i].offset + d->chunks[i].size;
// +4 to remove the 'SND ' marker at beginning of 'PROP' chunk
seek(d->chunks[i].offset + 4);
while(tell() + 12 <= propChunkEnd) {
while (tell() + 12 <= propChunkEnd) {
ByteVector propChunkName = readBlock(4);
long long propChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(propChunkName)) {
if (!isValidChunkID(propChunkName)) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + propChunkSize > propChunkEnd) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName
+ "' has invalid size (larger than the PROP chunk)");
if (static_cast<long long>(tell()) + propChunkSize > propChunkEnd) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName + "' has invalid size (larger than the PROP chunk)");
setValid(false);
break;
}
@@ -738,9 +693,9 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
if ((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
if ((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
@@ -749,7 +704,7 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
d->childChunks[PROPChunk].push_back(chunk);
}
}
else if(d->chunks[i].name == "DIIN") {
else if (d->chunks[i].name == "DIIN") {
d->childChunkIndex[DIINChunk] = i;
d->hasDiin = true;
@@ -758,19 +713,18 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
long long diinChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset);
while(tell() + 12 <= diinChunkEnd) {
while (tell() + 12 <= diinChunkEnd) {
ByteVector diinChunkName = readBlock(4);
long long diinChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(diinChunkName)) {
if (!isValidChunkID(diinChunkName)) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + diinChunkSize > diinChunkEnd) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName
+ "' has invalid size (larger than the DIIN chunk)");
if (static_cast<long long>(tell()) + diinChunkSize > diinChunkEnd) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName + "' has invalid size (larger than the DIIN chunk)");
setValid(false);
break;
}
@@ -787,9 +741,9 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
if ((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
if ((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
@@ -798,7 +752,7 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
d->childChunks[DIINChunk].push_back(chunk);
}
}
else if(d->chunks[i].name == "ID3 " || d->chunks[i].name == "id3 ") {
else if (d->chunks[i].name == "ID3 " || d->chunks[i].name == "id3 ") {
d->id3v2TagChunkID = d->chunks[i].name;
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->chunks[i].offset));
d->isID3InPropChunk = false;
@@ -806,10 +760,10 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
}
}
if(!isValid())
if (!isValid())
return;
if(d->childChunkIndex[PROPChunk] < 0) {
if (d->childChunkIndex[PROPChunk] < 0) {
debug("DSDIFF::File::read() -- no PROP chunk found");
setValid(false);
return;
@@ -817,13 +771,13 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
// Read properties
unsigned int sampleRate=0;
unsigned short channels=0;
unsigned int sampleRate = 0;
unsigned short channels = 0;
for(unsigned int i = 0; i < d->childChunks[PROPChunk].size(); i++) {
if(d->childChunks[PROPChunk][i].name == "ID3 " ||
d->childChunks[PROPChunk][i].name == "id3 ") {
if(d->hasID3v2) {
for (unsigned int i = 0; i < d->childChunks[PROPChunk].size(); i++) {
if (d->childChunks[PROPChunk][i].name == "ID3 " ||
d->childChunks[PROPChunk][i].name == "id3 ") {
if (d->hasID3v2) {
d->duplicateID3V2chunkIndex = i;
// ID3V2 tag has already been found at root level
continue;
@@ -833,12 +787,12 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
d->isID3InPropChunk = true;
d->hasID3v2 = true;
}
else if(d->childChunks[PROPChunk][i].name == "FS ") {
else if (d->childChunks[PROPChunk][i].name == "FS ") {
// Sample rate
seek(d->childChunks[PROPChunk][i].offset);
sampleRate = readBlock(4).toUInt(0, 4, bigEndian);
}
else if(d->childChunks[PROPChunk][i].name == "CHNL") {
else if (d->childChunks[PROPChunk][i].name == "CHNL") {
// Channels
seek(d->childChunks[PROPChunk][i].offset);
channels = readBlock(2).toShort(0, bigEndian);
@@ -849,20 +803,20 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, true);
if(d->hasDiin) {
for(unsigned int i = 0; i < d->childChunks[DIINChunk].size(); i++) {
if(d->childChunks[DIINChunk][i].name == "DITI") {
if (d->hasDiin) {
for (unsigned int i = 0; i < d->childChunks[DIINChunk].size(); i++) {
if (d->childChunks[DIINChunk][i].name == "DITI") {
seek(d->childChunks[DIINChunk][i].offset);
unsigned int titleStrLength = readBlock(4).toUInt(0, 4, bigEndian);
if(titleStrLength <= d->childChunks[DIINChunk][i].size) {
if (titleStrLength <= d->childChunks[DIINChunk][i].size) {
ByteVector titleStr = readBlock(titleStrLength);
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->setTitle(titleStr);
}
}
else if(d->childChunks[DIINChunk][i].name == "DIAR") {
else if (d->childChunks[DIINChunk][i].name == "DIAR") {
seek(d->childChunks[DIINChunk][i].offset);
unsigned int artistStrLength = readBlock(4).toUInt(0, 4, bigEndian);
if(artistStrLength <= d->childChunks[DIINChunk][i].size) {
if (artistStrLength <= d->childChunks[DIINChunk][i].size) {
ByteVector artistStr = readBlock(artistStrLength);
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->setArtist(artistStr);
}
@@ -870,33 +824,33 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
}
}
if(readProperties) {
if(lengthDSDSamplesTimeChannels == 0) {
if (readProperties) {
if (lengthDSDSamplesTimeChannels == 0) {
// DST compressed signal : need to compute length of DSD uncompressed frames
if(dstFrameRate > 0)
lengthDSDSamplesTimeChannels = (unsigned long long) dstNumFrames *
(unsigned long long) sampleRate /
(unsigned long long) dstFrameRate;
if (dstFrameRate > 0)
lengthDSDSamplesTimeChannels = (unsigned long long)dstNumFrames *
(unsigned long long)sampleRate /
(unsigned long long)dstFrameRate;
else
lengthDSDSamplesTimeChannels = 0;
}
else {
// In DSD uncompressed files, the read number of samples is the total for each channel
if(channels > 0)
if (channels > 0)
lengthDSDSamplesTimeChannels /= channels;
}
int bitrate = 0;
if(lengthDSDSamplesTimeChannels > 0)
if (lengthDSDSamplesTimeChannels > 0)
bitrate = (audioDataSizeinBytes * 8 * sampleRate) / lengthDSDSamplesTimeChannels / 1000;
d->properties = new Properties(sampleRate,
channels,
lengthDSDSamplesTimeChannels,
bitrate,
propertiesStyle);
channels,
lengthDSDSamplesTimeChannels,
bitrate,
propertiesStyle);
}
if(!ID3v2Tag()) {
if (!ID3v2Tag()) {
d->tag.access<ID3v2::Tag>(ID3v2Index, true);
// By default, ID3 chunk is at root level
d->isID3InPropChunk = false;
@@ -905,19 +859,17 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
}
void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace,
unsigned int leadingPadding)
{
unsigned long long offset, unsigned long replace,
unsigned int leadingPadding) {
ByteVector combined;
if(leadingPadding)
if (leadingPadding)
combined.append(ByteVector(leadingPadding, '\x00'));
combined.append(name);
combined.append(ByteVector::fromLongLong(data.size(), d->endianness == BigEndian));
combined.append(data);
if((data.size() & 0x01) != 0)
if ((data.size() & 0x01) != 0)
combined.append('\x00');
insert(combined, offset, replace);
}

View File

@@ -34,9 +34,9 @@
namespace Strawberry_TagLib {
namespace TagLib {
//! An implementation of DSDIFF metadata
//! An implementation of DSDIFF metadata
/*!
/*!
* This is implementation of DSDIFF metadata.
*
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
@@ -48,46 +48,44 @@ namespace TagLib {
* In addition, title and artist info are stored as part of the standard
*/
namespace DSDIFF {
namespace DSDIFF {
//! An implementation of TagLib::File with DSDIFF specific methods
//! An implementation of TagLib::File with DSDIFF specific methods
/*!
/*!
* This implements and provides an interface for DSDIFF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to DSDIFF files.
*/
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File
{
public:
/*!
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public:
/*!
* This set of flags is used for various operations and is suitable for
* being OR-ed together.
*/
enum TagTypes {
//! Empty set. Matches no tag types.
NoTags = 0x0000,
//! Matches DIIN tags.
DIIN = 0x0002,
//! Matches ID3v1 tags.
ID3v2 = 0x0002,
//! Matches all tag types.
AllTags = 0xffff
};
enum TagTypes {
//! Empty set. Matches no tag types.
NoTags = 0x0000,
//! Matches DIIN tags.
DIIN = 0x0002,
//! Matches ID3v1 tags.
ID3v2 = 0x0002,
//! Matches all tag types.
AllTags = 0xffff
};
/*!
/*!
* Constructs an DSDIFF file from \a file. If \a readProperties is true
* the file's audio properties will also be read.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
/*!
* Constructs an DSDIFF file from \a stream. If \a readProperties is true
* the file's audio properties will also be read.
*
@@ -96,15 +94,15 @@ namespace TagLib {
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
/*!
* Destroys this instance of the File.
*/
virtual ~File();
virtual ~File();
/*!
/*!
* Returns a pointer to a tag that is the union of the ID3v2 and DIIN
* tags. The ID3v2 tag is given priority in reading the information -- if
* requested information exists in both the ID3v2 tag and the ID3v1 tag,
@@ -120,9 +118,9 @@ namespace TagLib {
* \see ID3v2Tag()
* \see DIINTag()
*/
virtual Tag *tag() const;
virtual Tag *tag() const;
/*!
/*!
* Returns the ID3V2 Tag for this file.
*
* \note This always returns a valid pointer regardless of whether or not
@@ -131,35 +129,35 @@ namespace TagLib {
*
* \see hasID3v2Tag()
*/
ID3v2::Tag *ID3v2Tag(bool create = false) const;
ID3v2::Tag *ID3v2Tag(bool create = false) const;
/*!
/*!
* Returns the DSDIFF DIIN Tag for this file
*
*/
DSDIFF::DIIN::Tag *DIINTag(bool create = false) const;
DSDIFF::DIIN::Tag *DIINTag(bool create = false) const;
/*!
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const;
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
void removeUnsupportedProperties(const StringList &properties);
/*!
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
PropertyMap setProperties(const PropertyMap &);
/*!
/*!
* Returns the AIFF::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
virtual Properties *audioProperties() const;
/*!
/*!
* Save the file. If at least one tag -- ID3v1 or DIIN -- exists this
* will duplicate its content into the other tag. This returns true
* if saving was successful.
@@ -174,71 +172,72 @@ namespace TagLib {
*
* \see save(int tags)
*/
virtual bool save();
virtual bool save();
/*!
/*!
* Save the file. If \a strip is specified, it is possible to choose if
* tags not specified in \a tags should be stripped from the file or
* retained. With \a version, it is possible to specify whether ID3v2.4
* or ID3v2.3 should be used.
*/
bool save(TagTypes tags, StripTags strip = StripOthers, ID3v2::Version version = ID3v2::v4);
bool save(TagTypes tags, StripTags strip = StripOthers, ID3v2::Version version = ID3v2::v4);
/*!
/*!
* This will strip the tags that match the OR-ed together TagTypes from the
* file. By default it strips all tags. It returns true if the tags are
* successfully stripped.
*
* \note This will update the file immediately.
*/
void strip(TagTypes tags = AllTags);
void strip(TagTypes tags = AllTags);
/*!
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
*
* \see ID3v2Tag()
*/
bool hasID3v2Tag() const;
bool hasID3v2Tag() const;
/*!
/*!
* Returns whether or not the file on disk actually has the DSDIFF
* title and artist tags.
*
* \see DIINTag()
*/
bool hasDIINTag() const;
bool hasDIINTag() const;
/*!
/*!
* Returns whether or not the given \a stream can be opened as a DSDIFF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
static bool isSupported(IOStream *stream);
protected:
enum Endianness { BigEndian, LittleEndian };
protected:
enum Endianness { BigEndian,
LittleEndian };
File(FileName file, Endianness endianness);
File(IOStream *stream, Endianness endianness);
File(FileName file, Endianness endianness);
File(IOStream *stream, Endianness endianness);
private:
File(const File &);
File &operator=(const File &);
private:
File(const File &);
File &operator=(const File &);
void removeRootChunk(const ByteVector &id);
void removeRootChunk(unsigned int chunk);
void removeChildChunk(unsigned int i, unsigned int chunk);
void removeRootChunk(const ByteVector &id);
void removeRootChunk(unsigned int chunk);
void removeChildChunk(unsigned int i, unsigned int chunk);
/*!
/*!
* Sets the data for the the specified chunk at root level to \a data.
*
* \warning This will update the file immediately.
*/
void setRootChunkData(unsigned int i, const ByteVector &data);
void setRootChunkData(unsigned int i, const ByteVector &data);
/*!
/*!
* Sets the data for the root-level chunk \a name to \a data.
* If a root-level chunk with the given name already exists
* it will be overwritten, otherwise it will be
@@ -246,19 +245,19 @@ namespace TagLib {
*
* \warning This will update the file immediately.
*/
void setRootChunkData(const ByteVector &name, const ByteVector &data);
void setRootChunkData(const ByteVector &name, const ByteVector &data);
/*!
/*!
* Sets the data for the the specified child chunk to \a data.
*
* If data is null, then remove the chunk
*
* \warning This will update the file immediately.
*/
void setChildChunkData(unsigned int i, const ByteVector &data,
unsigned int childChunkNum);
void setChildChunkData(unsigned int i, const ByteVector &data,
unsigned int childChunkNum);
/*!
/*!
* Sets the data for the child chunk \a name to \a data. If a chunk with
* the given name already exists it will be overwritten, otherwise it will
* be created after the existing chunks inside child chunk.
@@ -267,22 +266,21 @@ namespace TagLib {
*
* \warning This will update the file immediately.
*/
void setChildChunkData(const ByteVector &name, const ByteVector &data,
unsigned int childChunkNum);
void setChildChunkData(const ByteVector &name, const ByteVector &data,
unsigned int childChunkNum);
void updateRootChunksStructure(unsigned int startingChunk);
void updateRootChunksStructure(unsigned int startingChunk);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace = 0,
unsigned int leadingPadding = 0);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace = 0,
unsigned int leadingPadding = 0);
class FilePrivate;
FilePrivate *d;
};
}
}
}
class FilePrivate;
FilePrivate *d;
};
} // namespace DSDIFF
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -30,17 +30,14 @@
using namespace Strawberry_TagLib::TagLib;
class DSDIFF::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
sampleWidth(0),
sampleCount(0)
{
class DSDIFF::Properties::PropertiesPrivate {
public:
PropertiesPrivate() : length(0),
bitrate(0),
sampleRate(0),
channels(0),
sampleWidth(0),
sampleCount(0) {
}
int length;
@@ -56,65 +53,52 @@ public:
////////////////////////////////////////////////////////////////////////////////
DSDIFF::Properties::Properties(const unsigned int sampleRate,
const unsigned short channels,
const unsigned long long samplesCount,
const int bitrate,
ReadStyle style) : AudioProperties(style)
{
const unsigned short channels,
const unsigned long long samplesCount,
const int bitrate,
ReadStyle style) : AudioProperties(style) {
d = new PropertiesPrivate;
d->channels = channels;
d->channels = channels;
d->sampleCount = samplesCount;
d->sampleWidth = 1;
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0
? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5)
: 0;
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0 ? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5) : 0;
}
DSDIFF::Properties::~Properties()
{
DSDIFF::Properties::~Properties() {
delete d;
}
int DSDIFF::Properties::length() const
{
int DSDIFF::Properties::length() const {
return lengthInSeconds();
}
int DSDIFF::Properties::lengthInSeconds() const
{
int DSDIFF::Properties::lengthInSeconds() const {
return d->length / 1000;
}
int DSDIFF::Properties::lengthInMilliseconds() const
{
int DSDIFF::Properties::lengthInMilliseconds() const {
return d->length;
}
int DSDIFF::Properties::bitrate() const
{
int DSDIFF::Properties::bitrate() const {
return d->bitrate;
}
int DSDIFF::Properties::sampleRate() const
{
int DSDIFF::Properties::sampleRate() const {
return d->sampleRate;
}
int DSDIFF::Properties::channels() const
{
int DSDIFF::Properties::channels() const {
return d->channels;
}
int DSDIFF::Properties::bitsPerSample() const
{
int DSDIFF::Properties::bitsPerSample() const {
return d->sampleWidth;
}
long long DSDIFF::Properties::sampleCount() const
{
long long DSDIFF::Properties::sampleCount() const {
return d->sampleCount;
}

View File

@@ -31,55 +31,53 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace DSDIFF {
namespace DSDIFF {
class File;
class File;
//! An implementation of audio property reading for DSDIFF
//! An implementation of audio property reading for DSDIFF
/*!
/*!
* This reads the data from an DSDIFF stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
/*!
class TAGLIB_EXPORT Properties : public AudioProperties {
public:
/*!
* Create an instance of DSDIFF::Properties with the data read from the
* ByteVector \a data.
*/
Properties(const unsigned int sampleRate, const unsigned short channels,
const unsigned long long samplesCount, const int bitrate,
ReadStyle style);
Properties(const unsigned int sampleRate, const unsigned short channels,
const unsigned long long samplesCount, const int bitrate,
ReadStyle style);
/*!
/*!
* Destroys this DSDIFF::Properties instance.
*/
virtual ~Properties();
virtual ~Properties();
// Reimplementations.
// Reimplementations.
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
int bitsPerSample() const;
long long sampleCount() const;
int bitsPerSample() const;
long long sampleCount() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
}
class PropertiesPrivate;
PropertiesPrivate *d;
};
} // namespace DSDIFF
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif