1 /***************************************************************************
2 copyright : (C) 2002 - 2008 by Scott Wheeler
3 email : wheeler@kde.org
4 ***************************************************************************/
6 /***************************************************************************
7 * This library is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU Lesser General Public License version *
9 * 2.1 as published by the Free Software Foundation. *
11 * This library is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14 * Lesser General Public License for more details. *
16 * You should have received a copy of the GNU Lesser General Public *
17 * License along with this library; if not, write to the Free Software *
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
21 * Alternatively, this file is available under the Mozilla Public *
22 * License Version 1.1. You may obtain a copy of the License at *
23 * http://www.mozilla.org/MPL/ *
24 ***************************************************************************/
26 #include <tbytevector.h>
33 using namespace TagLib;
35 class RIFF::File::FilePrivate
39 endianness(BigEndian),
44 Endianness endianness;
49 std::vector<ByteVector> chunkNames;
50 std::vector<uint> chunkOffsets;
51 std::vector<uint> chunkSizes;
52 std::vector<char> chunkPadding;
55 ////////////////////////////////////////////////////////////////////////////////
57 ////////////////////////////////////////////////////////////////////////////////
64 ////////////////////////////////////////////////////////////////////////////////
66 ////////////////////////////////////////////////////////////////////////////////
68 RIFF::File::File(FileName file, Endianness endianness) : TagLib::File(file)
71 d->endianness = endianness;
77 TagLib::uint RIFF::File::chunkCount() const
79 return d->chunkNames.size();
82 TagLib::uint RIFF::File::chunkOffset(uint i) const
84 return d->chunkOffsets[i];
87 ByteVector RIFF::File::chunkName(uint i) const
90 return ByteVector::null;
92 return d->chunkNames[i];
95 ByteVector RIFF::File::chunkData(uint i)
98 return ByteVector::null;
100 // Offset for the first subchunk's data
104 for(uint it = 0; it < i; it++)
105 begin += 8 + d->chunkSizes[it] + d->chunkPadding[it];
109 return readBlock(d->chunkSizes[i]);
112 void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
114 if(d->chunkNames.size() == 0)
116 debug("RIFF::File::setChunkData - No valid chunks found.");
120 for(uint i = 0; i < d->chunkNames.size(); i++) {
121 if(d->chunkNames[i] == name) {
123 int sizeDifference = data.size() - d->chunkSizes[i];
125 // First we update the global size
127 insert(ByteVector::fromUInt(d->size + sizeDifference,
128 d->endianness == BigEndian), 4, 4);
130 // Now update the specific chunk
132 writeChunk(name, data, d->chunkOffsets[i] - 8, d->chunkSizes[i] + d->chunkPadding[i] + 8);
134 d->chunkSizes[i] = data.size();
135 d->chunkPadding[i] = (data.size() & 0x01) ? 1 : 0;
137 // Now update the internal offsets
139 for(i++; i < d->chunkNames.size(); i++)
140 d->chunkOffsets[i] = d->chunkOffsets[i-1] + 8 + d->chunkSizes[i-1] + d->chunkPadding[i-1];
146 // Couldn't find an existing chunk, so let's create a new one. First update
149 insert(ByteVector::fromUInt(d->size + data.size() + 8, d->endianness == BigEndian), 4, 4);
150 writeChunk(name, data, d->chunkOffsets.back() + d->chunkSizes.back());
153 ////////////////////////////////////////////////////////////////////////////////
155 ////////////////////////////////////////////////////////////////////////////////
157 void RIFF::File::read()
159 bool bigEndian = (d->endianness == BigEndian);
161 d->type = readBlock(4);
162 d->size = readBlock(4).toUInt(bigEndian);
163 d->format = readBlock(4);
165 // + 8: chunk header at least, fix for additional junk bytes
166 while(tell() + 8 <= length()) {
167 ByteVector chunkName = readBlock(4);
168 uint chunkSize = readBlock(4).toUInt(bigEndian);
170 if(tell() + chunkSize > uint(length())) {
175 d->chunkNames.push_back(chunkName);
176 d->chunkSizes.push_back(chunkSize);
178 d->chunkOffsets.push_back(tell());
180 seek(chunkSize, Current);
183 char paddingSize = 0;
184 long uPosNotPadded = tell();
185 if((uPosNotPadded & 0x01) != 0) {
186 ByteVector iByte = readBlock(1);
187 if((iByte.size() != 1) || (iByte[0] != 0)) {
188 // not well formed, re-seek
189 seek(uPosNotPadded, Beginning);
195 d->chunkPadding.push_back(paddingSize);
200 void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
201 ulong offset, ulong replace)
203 ByteVector combined = name;
204 combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian));
205 combined.append(data);
206 if((data.size() & 0x01) != 0) {
208 combined.append('\x00');
210 insert(combined, offset, replace);