std::vector<ByteVector> chunkNames;
std::vector<uint> chunkOffsets;
std::vector<uint> chunkSizes;
+ std::vector<char> chunkPadding;
};
////////////////////////////////////////////////////////////////////////////////
long begin = 12 + 8;
for(uint it = 0; it < i; it++)
- begin += 8 + d->chunkSizes[it];
+ begin += 8 + d->chunkSizes[it] + d->chunkPadding[it];
seek(begin);
// Now update the specific chunk
- writeChunk(name, data, d->chunkOffsets[i] - 8, d->chunkSizes[i] + 8);
+ writeChunk(name, data, d->chunkOffsets[i] - 8, d->chunkSizes[i] + d->chunkPadding[i] + 8);
+
+ d->chunkSizes[i] = data.size();
+ d->chunkPadding[i] = (data.size() & 0x01) ? 1 : 0;
// Now update the internal offsets
for(i++; i < d->chunkNames.size(); i++)
- d->chunkOffsets[i] += sizeDifference;
+ d->chunkOffsets[i] = d->chunkOffsets[i-1] + 8 + d->chunkSizes[i-1] + d->chunkPadding[i-1];
return;
}
d->size = readBlock(4).toUInt(bigEndian);
d->format = readBlock(4);
- while(tell() < length()) {
+ // + 8: chunk header at least, fix for additional junk bytes
+ while(tell() + 8 <= length()) {
ByteVector chunkName = readBlock(4);
uint chunkSize = readBlock(4).toUInt(bigEndian);
+ if(tell() + chunkSize > length()) {
+ // something wrong
+ break;
+ }
+
d->chunkNames.push_back(chunkName);
d->chunkSizes.push_back(chunkSize);
d->chunkOffsets.push_back(tell());
seek(chunkSize, Current);
+
+ // check padding
+ char paddingSize = 0;
+ long uPosNotPadded = tell();
+ if((uPosNotPadded & 0x01) != 0) {
+ ByteVector iByte = readBlock(1);
+ if((iByte.size() != 1) || (iByte[0] != 0)) {
+ // not well formed, re-seek
+ seek(uPosNotPadded, Beginning);
+ }
+ else {
+ paddingSize = 1;
+ }
+ }
+ d->chunkPadding.push_back(paddingSize);
+
}
}
ByteVector combined = name;
combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian));
combined.append(data);
+ if((data.size() & 0x01) != 0) {
+ // padding
+ combined.append('\x00');
+ }
insert(combined, offset, replace);
}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2/frames
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mp4
+ ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff
+ ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff/aiff
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/trueaudio
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg
)
test_id3v1.cpp
test_id3v2.cpp
test_xiphcomment.cpp
+ test_aiff.cpp
+ test_riff.cpp
)
IF(WITH_MP4)
SET(test_runner_SRCS ${test_runner_SRCS} test_mp4.cpp)
--- /dev/null
+#include <cppunit/extensions/HelperMacros.h>
+#include <string>
+#include <stdio.h>
+#include <tag.h>
+#include <tbytevectorlist.h>
+#include <aifffile.h>
+#include "utils.h"
+
+using namespace std;
+using namespace TagLib;
+
+class TestAIFF : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestAIFF);
+ CPPUNIT_TEST(testReading);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ void testReading()
+ {
+ string filename = copyFile("empty", ".aiff");
+
+ RIFF::AIFF::File *f = new RIFF::AIFF::File(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(689, f->audioProperties()->bitrate());
+
+ deleteFile(filename);
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestAIFF);
--- /dev/null
+#include <cppunit/extensions/HelperMacros.h>
+#include <string>
+#include <stdio.h>
+#include <tag.h>
+#include <tbytevectorlist.h>
+#include <rifffile.h>
+#include "utils.h"
+
+using namespace std;
+using namespace TagLib;
+
+class PublicRIFF : public RIFF::File
+{
+public:
+ PublicRIFF(FileName file) : RIFF::File(file, BigEndian) {};
+ TagLib::uint chunkCount() { return RIFF::File::chunkCount(); };
+ TagLib::uint chunkOffset(TagLib::uint i) { return RIFF::File::chunkOffset(i); };
+ ByteVector chunkName(TagLib::uint i) { return RIFF::File::chunkName(i); };
+ ByteVector chunkData(TagLib::uint i) { return RIFF::File::chunkData(i); };
+ void setChunkData(const ByteVector &name, const ByteVector &data) {
+ RIFF::File::setChunkData(name, data);
+ };
+ virtual TagLib::Tag* tag() const { return 0; };
+ virtual TagLib::AudioProperties* audioProperties() const { return 0;};
+ virtual bool save() { return false; };
+};
+
+class TestRIFF : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestRIFF);
+ CPPUNIT_TEST(testPadding);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ void testPadding()
+ {
+ string filename = copyFile("empty", ".aiff");
+
+ PublicRIFF *f = new PublicRIFF(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0x1728 + 8), f->chunkOffset(2));
+
+ f->setChunkData("TEST", "foo");
+ delete f;
+
+ f = new PublicRIFF(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0x1728 + 8), f->chunkOffset(2));
+
+ f->setChunkData("SSND", "abcd");
+
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(1));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->chunkData(1));
+
+ f->seek(f->chunkOffset(1));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->readBlock(4));
+
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2));
+
+ f->seek(f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->readBlock(3));
+
+ delete f;
+
+ f = new PublicRIFF(filename.c_str());
+
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(1));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->chunkData(1));
+
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2));
+
+ deleteFile(filename);
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestRIFF);