From 520da50bc52bd6cecff5e9c4840682809bd591b6 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 22 Feb 2016 22:27:18 +0900 Subject: [PATCH] Always update the global RIFF size when updating RIFF files. --- taglib/riff/rifffile.cpp | 38 +++++++++++++++++++++++++++----------- taglib/riff/rifffile.h | 5 +++++ tests/test_riff.cpp | 12 +++++++++++- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/taglib/riff/rifffile.cpp b/taglib/riff/rifffile.cpp index b1064cc1..bf52e19e 100644 --- a/taglib/riff/rifffile.cpp +++ b/taglib/riff/rifffile.cpp @@ -48,11 +48,14 @@ class RIFF::File::FilePrivate public: FilePrivate(Endianness endianness) : endianness(endianness), - size(0) {} + size(0), + sizeOffset(0) {} const Endianness endianness; unsigned int size; + long sizeOffset; + std::vector chunks; }; @@ -129,11 +132,6 @@ ByteVector RIFF::File::chunkData(unsigned int i) void RIFF::File::setChunkData(unsigned int i, const ByteVector &data) { - // First we update the global size - - d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding); - insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4); - // Now update the specific chunk writeChunk(chunkName(i), data, d->chunks[i].offset - 8, d->chunks[i].size + d->chunks[i].padding + 8); @@ -145,6 +143,10 @@ void RIFF::File::setChunkData(unsigned int i, const ByteVector &data) for(i++; i < d->chunks.size(); i++) d->chunks[i].offset = d->chunks[i-1].offset + 8 + d->chunks[i-1].size + d->chunks[i-1].padding; + + // Update the global size. + + updateGlobalSize(); } void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data) @@ -177,11 +179,6 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bo unsigned long offset = d->chunks.back().offset + d->chunks.back().size; - // 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(0, length() - offset), (offset & 1) ? 1 : 0); @@ -200,6 +197,10 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bo chunk.padding = (data.size() & 0x01) ? 1 : 0; d->chunks.push_back(chunk); + + // Update the global size. + + updateGlobalSize(); } void RIFF::File::removeChunk(unsigned int i) @@ -216,6 +217,10 @@ void RIFF::File::removeChunk(unsigned int i) for(; it != d->chunks.end(); ++it) it->offset -= removeSize; + + // Update the global size. + + updateGlobalSize(); } void RIFF::File::removeChunk(const ByteVector &name) @@ -237,6 +242,7 @@ void RIFF::File::read() seek(baseOffset + 4); d->size = readBlock(4).toUInt(bigEndian); + d->sizeOffset = baseOffset + 4; seek(baseOffset + 12); @@ -298,3 +304,13 @@ void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, } insert(combined, offset, replace); } + +void RIFF::File::updateGlobalSize() +{ + const Chunk first = d->chunks.front(); + const Chunk last = d->chunks.back(); + d->size = last.offset + last.size + last.padding - first.offset + 12; + + const ByteVector data = ByteVector::fromUInt(d->size, d->endianness == BigEndian); + insert(data, d->sizeOffset, 4); +} diff --git a/taglib/riff/rifffile.h b/taglib/riff/rifffile.h index 52e75134..8425d8c9 100644 --- a/taglib/riff/rifffile.h +++ b/taglib/riff/rifffile.h @@ -148,6 +148,11 @@ namespace TagLib { unsigned long offset, unsigned long replace = 0, unsigned int leadingPadding = 0); + /*! + * Update the global RIFF size based on the current internal structure. + */ + void updateGlobalSize(); + class FilePrivate; FilePrivate *d; }; diff --git a/tests/test_riff.cpp b/tests/test_riff.cpp index 5223e905..f9a20dfb 100644 --- a/tests/test_riff.cpp +++ b/tests/test_riff.cpp @@ -211,7 +211,7 @@ public: CPPUNIT_ASSERT_EQUAL((unsigned int)(3), f.chunkDataSize(3)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(3)); CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(3)); - CPPUNIT_ASSERT_EQUAL((unsigned int)(4411 - 8), f.riffSize()); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4412 - 8), f.riffSize()); } { PublicRIFF f(filename.c_str()); @@ -234,6 +234,8 @@ public: PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(5928U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(5936L, f.length()); CPPUNIT_ASSERT_EQUAL(ByteVector("COMM"), f.chunkName(0)); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x000C + 8), f.chunkOffset(0)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(1)); @@ -243,6 +245,8 @@ public: const ByteVector data(0x400, ' '); f.setChunkData("SSND", data); + CPPUNIT_ASSERT_EQUAL(1070U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(1078L, f.length()); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x000C + 8), f.chunkOffset(0)); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x0026 + 8), f.chunkOffset(1)); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x042E + 8), f.chunkOffset(2)); @@ -255,6 +259,8 @@ public: CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.readBlock(4)); f.setChunkData(0, data); + CPPUNIT_ASSERT_EQUAL(2076U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(2084L, f.length()); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x000C + 8), f.chunkOffset(0)); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x0414 + 8), f.chunkOffset(1)); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x081C + 8), f.chunkOffset(2)); @@ -267,6 +273,8 @@ public: CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.readBlock(4)); f.removeChunk("SSND"); + CPPUNIT_ASSERT_EQUAL(1044U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(1052L, f.length()); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x000C + 8), f.chunkOffset(0)); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x0414 + 8), f.chunkOffset(1)); @@ -276,6 +284,8 @@ public: CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.readBlock(4)); f.removeChunk(0); + CPPUNIT_ASSERT_EQUAL(12U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(20L, f.length()); CPPUNIT_ASSERT_EQUAL((unsigned int)(0x000C + 8), f.chunkOffset(0)); f.seek(f.chunkOffset(0) - 8);