read();
}
+TagLib::uint RIFF::File::riffSize() const
+{
+ return d->size;
+}
+
TagLib::uint RIFF::File::chunkCount() const
{
return d->chunkNames.size();
return d->chunkOffsets[i];
}
+TagLib::uint RIFF::File::chunkPadding(uint i) const
+{
+ return d->chunkPadding[i];
+}
+
ByteVector RIFF::File::chunkName(uint i) const
{
if(i >= chunkCount())
void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
{
- if(d->chunkNames.size() == 0)
- {
+ if(d->chunkNames.size() == 0) {
debug("RIFF::File::setChunkData - No valid chunks found.");
return;
}
for(uint i = 0; i < d->chunkNames.size(); i++) {
if(d->chunkNames[i] == name) {
- int sizeDifference = data.size() - d->chunkSizes[i];
-
// First we update the global size
- insert(ByteVector::fromUInt(d->size + sizeDifference,
- d->endianness == BigEndian), 4, 4);
+ d->size += ((data.size() + 1) & ~1) - (d->chunkSizes[i] + d->chunkPadding[i]);
+ insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4);
// Now update the specific chunk
}
}
- // Couldn't find an existing chunk, so let's create a new one. First update
- // the global size:
+ // Couldn't find an existing chunk, so let's create a new one.
- insert(ByteVector::fromUInt(d->size + data.size() + 8, d->endianness == BigEndian), 4, 4);
- writeChunk(name, data, d->chunkOffsets.back() + d->chunkSizes.back());
+ uint i = d->chunkNames.size() - 1;
+ ulong offset = d->chunkOffsets[i] + d->chunkSizes[i];
+
+ // First we update the global size
+
+ d->size += (offset & 1) + data.size() + 8;
+ insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4);
+
+ // Now add the chunk to the file
+
+ writeChunk(name, data, offset, std::max(ulong(0), length() - offset), (offset & 1) ? 1 : 0);
+
+ // And update our internal structure
+
+ if (offset & 1) {
+ d->chunkPadding[i] = 1;
+ offset++;
+ }
+ d->chunkNames.push_back(name);
+ d->chunkSizes.push_back(data.size());
+ d->chunkOffsets.push_back(offset + 8);
+ d->chunkPadding.push_back((data.size() & 0x01) ? 1 : 0);
}
////////////////////////////////////////////////////////////////////////////////
}
void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
- ulong offset, ulong replace)
+ ulong offset, ulong replace, uint leadingPadding)
{
- ByteVector combined = name;
+ ByteVector combined;
+ if(leadingPadding) {
+ combined.append(ByteVector(leadingPadding, '\x00'));
+ }
+ combined.append(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);
{
public:
PublicRIFF(FileName file) : RIFF::File(file, BigEndian) {};
+ TagLib::uint riffSize() { return RIFF::File::riffSize(); };
TagLib::uint chunkCount() { return RIFF::File::chunkCount(); };
TagLib::uint chunkOffset(TagLib::uint i) { return RIFF::File::chunkOffset(i); };
+ TagLib::uint chunkPadding(TagLib::uint i) { return RIFF::File::chunkPadding(i); };
TagLib::uint chunkDataSize(TagLib::uint i) { return RIFF::File::chunkDataSize(i); };
ByteVector chunkName(TagLib::uint i) { return RIFF::File::chunkName(i); };
ByteVector chunkData(TagLib::uint i) { return RIFF::File::chunkData(i); };
{
CPPUNIT_TEST_SUITE(TestRIFF);
CPPUNIT_TEST(testPadding);
+ CPPUNIT_TEST(testLastChunkAtEvenPosition);
+ CPPUNIT_TEST(testLastChunkAtEvenPosition2);
+ CPPUNIT_TEST(testLastChunkAtEvenPosition3);
CPPUNIT_TEST_SUITE_END();
public:
CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2));
}
+ void testLastChunkAtEvenPosition()
+ {
+ ScopedFileCopy copy("noise", ".aif");
+ string filename = copy.fileName();
+
+ PublicRIFF *f = new PublicRIFF(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(long(4400), f->length());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize());
+ f->setChunkData("TEST", "abcd");
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4412 - 8), f->riffSize());
+ delete f;
+
+ f = new PublicRIFF(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3));
+ CPPUNIT_ASSERT_EQUAL(long(4412), f->length());
+ delete f;
+ }
+
+ void testLastChunkAtEvenPosition2()
+ {
+ ScopedFileCopy copy("noise_odd", ".aif");
+ string filename = copy.fileName();
+
+ PublicRIFF *f = new PublicRIFF(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(long(4399), f->length());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize());
+ f->setChunkData("TEST", "abcd");
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4412 - 8), f->riffSize());
+ delete f;
+
+ f = new PublicRIFF(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3));
+ CPPUNIT_ASSERT_EQUAL(long(4412), f->length());
+ delete f;
+ }
+
+ void testLastChunkAtEvenPosition3()
+ {
+ ScopedFileCopy copy("noise_odd", ".aif");
+ string filename = copy.fileName();
+
+ PublicRIFF *f = new PublicRIFF(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(long(4399), f->length());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize());
+ f->setChunkData("TEST", "abc");
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f->chunkDataSize(3));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4411 - 8), f->riffSize());
+ delete f;
+
+ f = new PublicRIFF(filename.c_str());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f->chunkDataSize(3));
+ CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3));
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(3));
+ CPPUNIT_ASSERT_EQUAL(long(4412), f->length());
+ delete f;
+ }
+
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestRIFF);