Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwavedecoder.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include "qwavedecoder.h"
6
7#include <QtCore/qtimer.h>
8#include <QtCore/qendian.h>
9#include <limits.h>
10#include <qdebug.h>
11
13
14#if QT_DEPRECATED_SINCE(6, 11)
15
16QWaveDecoder::QWaveDecoder(QIODevice *device, QObject *parent)
17 : QIODevice(parent),
18 device(device)
19{
20}
21
22QWaveDecoder::QWaveDecoder(QIODevice *device, const QAudioFormat &format, QObject *parent)
23 : QIODevice(parent),
24 device(device),
25 format(format)
26{
27}
28
29QWaveDecoder::~QWaveDecoder() = default;
30
31bool QWaveDecoder::open(QIODevice::OpenMode mode)
32{
33 bool canOpen = false;
34 if (mode & QIODevice::ReadOnly && mode & ~QIODevice::WriteOnly) {
35 canOpen = QIODevice::open(mode | QIODevice::Unbuffered);
36 if (canOpen && enoughDataAvailable())
37 handleData();
38 else
39 connect(device, &QIODevice::readyRead, this, &QWaveDecoder::handleData);
40 return canOpen;
41 }
42
43 if (mode & QIODevice::WriteOnly) {
44 if (format.sampleFormat() != QAudioFormat::Int16)
45 return false; // data format is not supported
46 canOpen = QIODevice::open(mode);
47 if (canOpen && writeHeader())
48 haveHeader = true;
49 return canOpen;
50 }
51 return QIODevice::open(mode);
52}
53
54void QWaveDecoder::close()
55{
56 if (isOpen() && (openMode() & QIODevice::WriteOnly)) {
57 Q_ASSERT(dataSize < INT_MAX);
58 if (!device->isOpen() || !writeDataLength())
59 qWarning() << "Failed to finalize wav file";
60 }
61 QIODevice::close();
62}
63
64bool QWaveDecoder::seek(qint64 pos)
65{
66 return device->seek(pos);
67}
68
69qint64 QWaveDecoder::pos() const
70{
71 return device->pos();
72}
73
74void QWaveDecoder::setIODevice(QIODevice * /* device */)
75{
76}
77
78QAudioFormat QWaveDecoder::audioFormat() const
79{
80 return format;
81}
82
83QIODevice* QWaveDecoder::getDevice()
84{
85 return device;
86}
87
88int QWaveDecoder::duration() const
89{
90 if (openMode() & QIODevice::WriteOnly)
91 return 0;
92 int bytesPerSec = format.bytesPerFrame() * format.sampleRate();
93 return bytesPerSec ? size() * 1000 / bytesPerSec : 0;
94}
95
96qint64 QWaveDecoder::size() const
97{
98 if (openMode() & QIODevice::ReadOnly) {
99 if (!haveFormat)
100 return 0;
101 if (bps == 24)
102 return dataSize*2/3;
103 return dataSize;
104 } else {
105 return device->size();
106 }
107}
108
109bool QWaveDecoder::isSequential() const
110{
111 return device->isSequential();
112}
113
114qint64 QWaveDecoder::bytesAvailable() const
115{
116 return haveFormat ? device->bytesAvailable() : 0;
117}
118
119qint64 QWaveDecoder::headerLength()
120{
121 return HeaderLength;
122}
123
124qint64 QWaveDecoder::readData(char *data, qint64 maxlen)
125{
126 const int bytesPerSample = format.bytesPerSample();
127 if (!haveFormat || bytesPerSample == 0)
128 return 0;
129
130 if (bps == 24) {
131 // 24 bit WAV, read in as 16 bit
132 qint64 l = 0;
133 while (l < maxlen - 1) {
134 char tmp[3];
135 device->read(tmp, 3);
136 if (byteSwap)
137 qSwap(tmp[0], tmp[2]);
138#if Q_BYTE_ORDER == Q_BIG_ENDIAN
139 data[0] = tmp[0];
140 data[1] = tmp[1];
141#else
142 data[0] = tmp[1];
143 data[1] = tmp[2];
144#endif
145 data += 2;
146 l += 2;
147 }
148 return l;
149 }
150
151 qint64 nSamples = maxlen / bytesPerSample;
152 maxlen = nSamples * bytesPerSample;
153 int read = device->read(data, maxlen);
154
155 if (!byteSwap || format.bytesPerFrame() == 1)
156 return read;
157
158 nSamples = read / bytesPerSample;
159 switch (bytesPerSample) {
160 case 2:
161 qbswap<2>(data, nSamples, data);
162 break;
163 case 4:
164 qbswap<4>(data, nSamples, data);
165 break;
166 default:
167 Q_UNREACHABLE();
168 }
169 return read;
170
171}
172
173qint64 QWaveDecoder::writeData(const char *data, qint64 len)
174{
175 if (!haveHeader)
176 return 0;
177 qint64 written = device->write(data, len);
178 dataSize += written;
179 return written;
180}
181
182bool QWaveDecoder::writeHeader()
183{
184 if (device->size() != 0)
185 return false;
186
187#ifndef Q_LITTLE_ENDIAN
188 // only implemented for LITTLE ENDIAN
189 return false;
190#endif
191
192 CombinedHeader header;
193
194 memset(&header, 0, HeaderLength);
195
196 // RIFF header
197 memcpy(header.riff.descriptor.id,"RIFF",4);
198 qToLittleEndian<quint32>(quint32(dataSize + HeaderLength - 8),
199 reinterpret_cast<unsigned char*>(&header.riff.descriptor.size));
200 memcpy(header.riff.type, "WAVE",4);
201
202 // WAVE header
203 memcpy(header.wave.descriptor.id,"fmt ",4);
204 qToLittleEndian<quint32>(quint32(16),
205 reinterpret_cast<unsigned char*>(&header.wave.descriptor.size));
206 qToLittleEndian<quint16>(quint16(1),
207 reinterpret_cast<unsigned char*>(&header.wave.audioFormat));
208 qToLittleEndian<quint16>(quint16(format.channelCount()),
209 reinterpret_cast<unsigned char*>(&header.wave.numChannels));
210 qToLittleEndian<quint32>(quint32(format.sampleRate()),
211 reinterpret_cast<unsigned char*>(&header.wave.sampleRate));
212 qToLittleEndian<quint32>(quint32(format.sampleRate() * format.bytesPerFrame()),
213 reinterpret_cast<unsigned char*>(&header.wave.byteRate));
214 qToLittleEndian<quint16>(quint16(format.channelCount() * format.bytesPerSample()),
215 reinterpret_cast<unsigned char*>(&header.wave.blockAlign));
216 qToLittleEndian<quint16>(quint16(format.bytesPerSample() * 8),
217 reinterpret_cast<unsigned char*>(&header.wave.bitsPerSample));
218
219 // DATA header
220 memcpy(header.data.descriptor.id,"data",4);
221 qToLittleEndian<quint32>(quint32(dataSize),
222 reinterpret_cast<unsigned char*>(&header.data.descriptor.size));
223
224 return device->write(reinterpret_cast<const char *>(&header), HeaderLength);
225}
226
227bool QWaveDecoder::writeDataLength()
228{
229#ifndef Q_LITTLE_ENDIAN
230 // only implemented for LITTLE ENDIAN
231 return false;
232#endif
233
234 if (isSequential())
235 return false;
236
237 // seek to RIFF header size, see header.riff.descriptor.size above
238 if (!device->seek(4)) {
239 qDebug() << "can't seek";
240 return false;
241 }
242
243 quint32 length = dataSize + HeaderLength - 8;
244 if (device->write(reinterpret_cast<const char *>(&length), 4) != 4)
245 return false;
246
247 // seek to DATA header size, see header.data.descriptor.size above
248 if (!device->seek(40))
249 return false;
250
251 return device->write(reinterpret_cast<const char *>(&dataSize), 4);
252}
253
254void QWaveDecoder::parsingFailed()
255{
256 Q_ASSERT(device);
257 disconnect(device, &QIODevice::readyRead, this, &QWaveDecoder::handleData);
258 emit parsingError();
259}
260
261void QWaveDecoder::handleData()
262{
263 if (openMode() == QIODevice::WriteOnly)
264 return;
265
266 // As a special "state", if we have junk to skip, we do
267 if (junkToSkip > 0) {
268 discardBytes(junkToSkip); // this also updates junkToSkip
269
270 // If we couldn't skip all the junk, return
271 if (junkToSkip > 0) {
272 // We might have run out
273 if (device->atEnd())
274 parsingFailed();
275 return;
276 }
277 }
278
279 if (state == QWaveDecoder::InitialState) {
280 if (device->bytesAvailable() < qint64(sizeof(RIFFHeader)))
281 return;
282
283 RIFFHeader riff;
284 device->read(reinterpret_cast<char *>(&riff), sizeof(RIFFHeader));
285
286 // RIFF = little endian RIFF, RIFX = big endian RIFF
287 if (((qstrncmp(riff.descriptor.id, "RIFF", 4) != 0) && (qstrncmp(riff.descriptor.id, "RIFX", 4) != 0))
288 || qstrncmp(riff.type, "WAVE", 4) != 0) {
289 parsingFailed();
290 return;
291 }
292
293 state = QWaveDecoder::WaitingForFormatState;
294 bigEndian = (qstrncmp(riff.descriptor.id, "RIFX", 4) == 0);
295 byteSwap = (bigEndian != (QSysInfo::ByteOrder == QSysInfo::BigEndian));
296 }
297
298 if (state == QWaveDecoder::WaitingForFormatState) {
299 if (findChunk("fmt ")) {
300 chunk descriptor;
301 const bool peekSuccess = peekChunk(&descriptor);
302 Q_ASSERT(peekSuccess);
303
304 quint32 rawChunkSize = descriptor.size + sizeof(chunk);
305 if (device->bytesAvailable() < qint64(rawChunkSize))
306 return;
307
308 WAVEHeader wave;
309 device->read(reinterpret_cast<char *>(&wave), sizeof(WAVEHeader));
310
311 if (rawChunkSize > sizeof(WAVEHeader))
312 discardBytes(rawChunkSize - sizeof(WAVEHeader));
313
314 // Swizzle this
315 if (bigEndian) {
316 wave.audioFormat = qFromBigEndian<quint16>(wave.audioFormat);
317 } else {
318 wave.audioFormat = qFromLittleEndian<quint16>(wave.audioFormat);
319 }
320
321 if (wave.audioFormat != 0 && wave.audioFormat != 1) {
322 // 32bit wave files have format == 0xFFFE (WAVE_FORMAT_EXTENSIBLE).
323 // but don't support them at the moment.
324 parsingFailed();
325 return;
326 }
327
328 int rate;
329 int channels;
330 if (bigEndian) {
331 bps = qFromBigEndian<quint16>(wave.bitsPerSample);
332 rate = qFromBigEndian<quint32>(wave.sampleRate);
333 channels = qFromBigEndian<quint16>(wave.numChannels);
334 } else {
335 bps = qFromLittleEndian<quint16>(wave.bitsPerSample);
336 rate = qFromLittleEndian<quint32>(wave.sampleRate);
337 channels = qFromLittleEndian<quint16>(wave.numChannels);
338 }
339
340 QAudioFormat::SampleFormat fmt = QAudioFormat::Unknown;
341 switch(bps) {
342 case 8:
343 fmt = QAudioFormat::UInt8;
344 break;
345 case 16:
346 fmt = QAudioFormat::Int16;
347 break;
348 case 24:
349 fmt = QAudioFormat::Int16;
350 break;
351 case 32:
352 fmt = QAudioFormat::Int32;
353 break;
354 }
355 if (fmt == QAudioFormat::Unknown || rate == 0 || channels == 0) {
356 parsingFailed();
357 return;
358 }
359
360 format.setSampleFormat(fmt);
361 format.setSampleRate(rate);
362 format.setChannelCount(channels);
363
364 state = QWaveDecoder::WaitingForDataState;
365 }
366 }
367
368 if (state == QWaveDecoder::WaitingForDataState) {
369 if (findChunk("data")) {
370 disconnect(device, &QIODevice::readyRead, this, &QWaveDecoder::handleData);
371
372 chunk descriptor;
373 device->read(reinterpret_cast<char *>(&descriptor), sizeof(chunk));
374 if (bigEndian)
375 descriptor.size = qFromBigEndian<quint32>(descriptor.size);
376 else
377 descriptor.size = qFromLittleEndian<quint32>(descriptor.size);
378
379 dataSize = descriptor.size; //means the data size from the data header, not the actual file size
380 if (!dataSize)
381 dataSize = device->size() - headerLength();
382
383 haveFormat = true;
384 connect(device, &QIODevice::readyRead, this, &QIODevice::readyRead);
385 emit formatKnown();
386
387 return;
388 }
389 }
390
391 // If we hit the end without finding data, it's a parsing error
392 if (device->atEnd()) {
393 parsingFailed();
394 }
395}
396
397bool QWaveDecoder::enoughDataAvailable()
398{
399 chunk descriptor;
400 if (!peekChunk(&descriptor, false))
401 return false;
402
403 // This is only called for the RIFF/RIFX header, before bigEndian is set,
404 // so we have to manually swizzle
405 if (qstrncmp(descriptor.id, "RIFX", 4) == 0)
406 descriptor.size = qFromBigEndian<quint32>(descriptor.size);
407 if (qstrncmp(descriptor.id, "RIFF", 4) == 0)
408 descriptor.size = qFromLittleEndian<quint32>(descriptor.size);
409
410 if (device->bytesAvailable() < qint64(sizeof(chunk)) + descriptor.size)
411 return false;
412
413 return true;
414}
415
416bool QWaveDecoder::findChunk(const char *chunkId)
417{
418 chunk descriptor;
419
420 do {
421 if (!peekChunk(&descriptor))
422 return false;
423
424 if (qstrncmp(descriptor.id, chunkId, 4) == 0)
425 return true;
426
427 // A program reading a RIFF file can skip over any chunk whose chunk
428 // ID it doesn't recognize; it simply skips the number of bytes specified
429 // by ckSize plus the pad byte, if present. See Multimedia Programming
430 // Interface and Data Specifications 1.0. IBM / Microsoft. August 1991. pp. 10-11.
431 const quint32 sizeWithPad = descriptor.size + (descriptor.size & 1);
432
433 // It's possible that bytes->available() is less than the chunk size
434 // if it's corrupt.
435 junkToSkip = qint64(sizeof(chunk) + sizeWithPad);
436
437 // Skip the current amount
438 if (junkToSkip > 0)
439 discardBytes(junkToSkip);
440
441 // If we still have stuff left, just exit and try again later
442 // since we can't call peekChunk
443 if (junkToSkip > 0)
444 return false;
445
446 } while (device->bytesAvailable() > 0);
447
448 return false;
449}
450
451bool QWaveDecoder::peekChunk(chunk *pChunk, bool handleEndianness)
452{
453 if (device->bytesAvailable() < qint64(sizeof(chunk)))
454 return false;
455
456 if (!device->peek(reinterpret_cast<char *>(pChunk), sizeof(chunk)))
457 return false;
458
459 if (handleEndianness) {
460 if (bigEndian)
461 pChunk->size = qFromBigEndian<quint32>(pChunk->size);
462 else
463 pChunk->size = qFromLittleEndian<quint32>(pChunk->size);
464 }
465 return true;
466}
467
468void QWaveDecoder::discardBytes(qint64 numBytes)
469{
470 // Discards a number of bytes
471 // If the iodevice doesn't have this many bytes in it,
472 // remember how much more junk we have to skip.
473 if (device->isSequential()) {
474 QByteArray r = device->read(qMin(numBytes, qint64(16384))); // uggh, wasted memory, limit to a max of 16k
475 if (r.size() < numBytes)
476 junkToSkip = numBytes - r.size();
477 else
478 junkToSkip = 0;
479 } else {
480 quint64 origPos = device->pos();
481 device->seek(device->pos() + numBytes);
482 junkToSkip = origPos + numBytes - device->pos();
483 }
484}
485
486#endif // QT_DEPRECATED_SINCE(6, 11)
487
488QT_END_NAMESPACE
489
490#include "moc_qwavedecoder.cpp"