kwave  18.07.70
RIFFParser.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  RIFFParser.cpp - parser for the RIFF format
3  -------------------
4  begin : Tue Mar 20 2002
5  copyright : (C) 2002 by Thomas Eschenbacher
6  email : Thomas.Eschenbacher@gmx.de
7 ***************************************************************************/
8 
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 
18 #include "config.h"
19 
20 #include <math.h>
21 #include <stdlib.h>
22 
23 #include <limits>
24 
25 #include <QIODevice>
26 #include <QLatin1String>
27 #include <QList>
28 #include <QMutableListIterator>
29 #include <QString>
30 #include <QStringList>
31 #include <QtEndian>
32 #include <QtGlobal>
33 
34 #include <KLocalizedString>
35 
36 #include "libkwave/String.h"
37 
38 #include "RIFFChunk.h"
39 #include "RIFFParser.h"
40 
41 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
42 #define SYSTEM_ENDIANNES Kwave::BigEndian
43 #else
44 #define SYSTEM_ENDIANNES Kwave::LittleEndian
45 #endif
46 
52 static inline quint32 toUint32(quint64 x) {
53  const quint64 max = std::numeric_limits<qint32>::max();
54  return static_cast<quint32>(qMin(x, max));
55 }
56 
57 //***************************************************************************
59  const QStringList &main_chunks,
60  const QStringList &known_subchunks)
61  :m_dev(device),
62  m_root(Q_NULLPTR, "", "", toUint32(device.size()), 0,
63  toUint32(device.size())),
64  m_main_chunk_names(main_chunks), m_sub_chunk_names(known_subchunks),
65  m_endianness(Kwave::UnknownEndian), m_cancel(false)
66 {
68 }
69 
70 //***************************************************************************
72 {
73 }
74 
75 //***************************************************************************
77 {
78  int i;
79  for (i=0; i < 4; ++i) {
80  char c = name[i];
81  if ((c >= 'a') && (c <= 'z')) continue;
82  if ((c >= 'A') && (c <= 'Z')) continue;
83  if ((c >= '0') && (c <= '9')) continue;
84  if ((c == ' ') || (c == '(') || (c == ')'))continue;
85  return false;
86  }
87  return true;
88 }
89 
90 //***************************************************************************
92 {
93  if (!isValidName(name)) return Kwave::RIFFChunk::Garbage;
94  return (m_main_chunk_names.contains(QLatin1String(name))) ?
96 }
97 
98 //***************************************************************************
99 bool Kwave::RIFFParser::isKnownName(const QByteArray &name)
100 {
101  if (m_main_chunk_names.contains(QLatin1String(name))) return true;
102  if (m_sub_chunk_names.contains(QLatin1String(name))) return true;
103  return false;
104 }
105 
106 //***************************************************************************
108 {
109  // first try the easy way, works if file is sane
110  QString sane_name = QLatin1String(read4ByteString(0));
111  if (sane_name == _("RIFF")) {
113  return;
114  }
115  if (sane_name == _("RIFX")) {
117  return;
118  }
119 
120  // ok, our file is damaged at least a bit, try to discover
121  emit action(i18n("Detecting endianness (standard search)..."));
122  emit progress(0);
123 
124  QList<quint32> riff_offsets = scanForName("RIFF",
125  m_root.physStart(), m_root.physLength(), 0, 2);
126  if (m_cancel) return;
127 
128  QList<quint32> rifx_offsets = scanForName("RIFX",
129  m_root.physStart(), m_root.physLength(), 1, 2);
130  if (m_cancel) return;
131 
132  // if RIFF found and RIFX not found -> little endian
133  if (riff_offsets.count() && !rifx_offsets.count()) {
134  qDebug("detected little endian format");
136  emit progress(100);
137  return;
138  }
139 
140  // if RIFX found and RIFF not found -> big endian
141  if (rifx_offsets.count() && !riff_offsets.count()) {
142  qDebug("detected big endian format");
144  emit progress(100);
145  return;
146  }
147 
148  // not detectable -> detect by searching all known chunks and
149  // detect best match
150  emit action(i18n("Detecting endianness (statistic search)..."));
151  qDebug("doing statistic search to determine endianness...");
152  unsigned int le_matches = 0;
153  unsigned int be_matches = 0;
154  QStringList names;
155  names += m_main_chunk_names;
156  names += m_sub_chunk_names;
157 
158  // average length should be approx. half of file size
159  double half = (m_dev.size() >> 1);
160 
161  // loop over all chunk names
162  int count = names.count();
163  int index = 0;
164  foreach (QString chunk_name, names) {
165  // scan all offsets where the name matches
166  QByteArray name = chunk_name.toLatin1();
167  QList<quint32> offsets = scanForName(name,
169  index, count);
170  if (m_cancel) return;
171 
172  // loop over all found offsets
173  foreach (quint32 ofs, offsets) {
174  m_dev.seek(ofs + 4);
175 
176  // read length, assuming little endian
177  quint32 len = 0;
178  m_dev.read(reinterpret_cast<char *>(&len), 4);
179  double dist_le = fabs(half - qFromLittleEndian<quint32>(len));
180  double dist_be = fabs(half - qFromBigEndian<quint32>(len));
181 
182  // evaluate distance to average length
183  if (dist_be > dist_le) ++le_matches;
184  if (dist_le > dist_be) ++be_matches;
185  }
186 
187  emit progress(100 * (++index) / count);
188  }
189  qDebug("big endian matches: %u", be_matches);
190  qDebug("little endian matches: %u", le_matches);
191 
192  if (le_matches > be_matches) {
193  qDebug("assuming little endian");
195  } else if (be_matches > le_matches) {
196  qDebug("assuming big endian");
198  } else {
199  // give up :-(
200  qDebug("unable to determine endianness");
202  }
203 
204  emit progress(100);
205 }
206 
207 //***************************************************************************
208 QByteArray Kwave::RIFFParser::read4ByteString(qint64 offset)
209 {
210  char s[5] = {0, 0, 0, 0, 0};
211 
212  m_dev.seek(offset);
213  m_dev.read(&s[0], 4);
214 
215  return QByteArray(s);
216 }
217 
218 //***************************************************************************
220 {
221  // first of all we have to find out the endianness of our source
223 
224  // not detectable -> no chance of finding anything useful -> give up!
226  qWarning("unable to detect endianness -> giving up!");
227  return false;
228  }
229 
230  // find all primary chunks
231  return parse(&m_root, 0, toUint32(m_dev.size()));
232 }
233 
234 //***************************************************************************
236  Kwave::RIFFChunk *parent, const QByteArray &name,
237  const QByteArray &format, quint32 length,
238  quint32 phys_offset, quint32 phys_length,
240 {
241  // do not add anything to garbage, use the garbage's parent instead
242  while (parent && (parent->type() == Kwave::RIFFChunk::Garbage)) {
243  parent = parent->parent();
244  }
245 
246  // if no parent found, use root
247  if (!parent) {
248  parent = &m_root;
249  }
250  Q_ASSERT(parent);
251 
252  // create a new chunk object
253  Kwave::RIFFChunk *chunk = new Kwave::RIFFChunk(
254  parent, name, format, length, phys_offset, phys_length);
255  Q_ASSERT(chunk);
256  if (!chunk) return Q_NULLPTR;
257  chunk->setType(type);
258 
259  // sort the chunk into the parent, order by physical start
260  Kwave::RIFFChunk *before = Q_NULLPTR;
261  Kwave::RIFFChunkList &chunks = parent->subChunks();
262  foreach (Kwave::RIFFChunk *c, chunks) {
263  if (!c) continue;
264  quint32 pos = c->physStart();
265  if (pos > phys_offset) {
266  before = c;
267  break;
268  }
269  }
270 
271  int index = (before) ? chunks.indexOf(before) : chunks.size();
272  chunks.insert(index, chunk);
273 
274  return chunk;
275 }
276 
277 //***************************************************************************
279  quint32 offset,
280  quint32 length)
281 {
282  qDebug("adding garbage chunk at 0x%08X, length=%u",offset,length);
283 
284  // create the new chunk first
285  QByteArray name(16, 0);
286  qsnprintf(name.data(), name.size(), "[0x%08X]", offset);
287  Kwave::RIFFChunk *chunk = addChunk(parent, name, "", length, offset,
288  length, Kwave::RIFFChunk::Garbage);
289  return (chunk);
290 }
291 
292 //***************************************************************************
294  const QByteArray &name,
295  quint32 offset)
296 {
297  // create the new chunk first
298  Kwave::RIFFChunk *chunk = addChunk(parent, name, "----", 0, offset,
300  return (chunk);
301 }
302 
303 //***************************************************************************
305  quint32 offset, quint32 length)
306 {
307  bool error = false;
308  Kwave::RIFFChunkList found_chunks;
309 
310  Q_ASSERT(parent);
311  if (m_dev.isSequential()) return false;
312  if (!parent) return false;
313 
314  // be more robust if the file has not correctly padded
315  if (length & 1) length++;
316 
317  do {
318 // qDebug("RIFFParser::parse(offset=0x%08X, length=0x%08X)",
319 // offset, length);
320 
321  // make sure that we are still in the source (file)
322  if (offset >= m_dev.size()) {
323  error = true;
324  break;
325  }
326 
327  // abort search if we passed the same position twice
328  // (this might happen if an intensive search is performed
329  // and one position can be reached in two or more ways)
330  // only exception: the root chunk, this always overlaps
331  // with the first chunk at start of search!
332  Kwave::RIFFChunk *prev = chunkAt(offset);
333  if (prev && (m_root.subChunks().count())) break;
334 
335  // chunks with less than 4 bytes are not possible
336  if (length < 4) {
337  qWarning("chunk with less than 4 bytes at offset 0x%08X, "\
338  "length=%u bytes!", offset, length);
339  // too short stuff is "garbage"
340  addGarbageChunk(parent, offset, length);
341  error = true;
342  break;
343  }
344 
345  m_dev.seek(offset);
346 
347  // get the chunk name
348  QByteArray name = read4ByteString(m_dev.pos());
349 
350  // check if the name really contains only ASCII characters
351  if (!isValidName(name)) {
352  qWarning("invalid chunk name at offset 0x%08X", offset);
353  // unreadable name -> make it a "garbage" chunk
354  qDebug("addGarbageChunk(offset=0x%08X, length=0x%08X)",
355  offset, length);
356  addGarbageChunk(parent, offset, length);
357  error = true;
358  break;
359  }
360 
361  // get the length stored in the chunk itself
362  quint32 len = 0;
363  if (length >= 8) {
364  // length information present
365  m_dev.read(reinterpret_cast<char *>(&len), 4);
366  if (m_endianness != SYSTEM_ENDIANNES) len = qbswap<quint32>(len);
367  }
368  if (len == 0) {
369  // valid name but no length information -> badly truncated
370  // -> make it a zero-length chunk
371  qDebug("empty chunk '%s' at 0x%08X", name.data(), offset);
372  addEmptyChunk(parent, name, offset);
373 
374  if (length > 8) {
375  // there's some garbage behind
376  offset += 8;
377  length -= 8;
378  }
379  error = true;
380  continue;
381  }
382 
383  // read the format if present
384  QByteArray format = read4ByteString(m_dev.pos());
385 
386  // calculate the physical length of the chunk
387  quint32 phys_len = (length - 8 < len) ? (length - 8) : len;
388  if (phys_len & 1) phys_len++;
389 
390  // now create a new chunk, per default type is "sub-chunk"
391 /* qDebug("new chunk, name='%s', len=0x%08X, ofs=0x%08X, "\
392  "phys_len=0x%08X (next=0x%08X)",
393  name.data(),
394  len,offset,phys_len, offset+phys_len+8); */
395  Kwave::RIFFChunk *chunk = addChunk(parent, name, format, len, offset,
396  phys_len, Kwave::RIFFChunk::Sub);
397  if (!chunk) break;
398  found_chunks.append(chunk);
399 
400  // if not at the end of the file, parse all further chunks
401  length -= chunk->physLength() + 8;
402  offset = chunk->physEnd() + 1;
403 // qDebug(" parse loop end: offset=0x%08X, length=0x%08X",offset,length);
404  } while (length && !m_cancel);
405 
406  // parse for sub-chunks in the chunks we newly found
407  foreach (Kwave::RIFFChunk *chunk, found_chunks) {
408  if (!chunk) continue;
409  if ( (guessType(chunk->name()) == Kwave::RIFFChunk::Main) &&
410  (chunk->dataLength() >= 4) )
411  {
413 
414  QByteArray path = (parent ? parent->path() : QByteArray("")) +
415  '/' + chunk->name();
416 /* qDebug("scanning for chunks in '%s' (format='%s'), "\
417  "offset=0x%08X, length=0x%08X",
418  path.data(), chunk->format().data(),
419  chunk->dataStart(), chunk->dataLength());*/
420  if (!parse(chunk, chunk->dataStart(), chunk->dataLength())) {
421  error = true;
422  }
423 
424  }
425  }
426 
427  return (!error && !m_cancel);
428 }
429 
430 //***************************************************************************
432 {
434 }
435 
436 //***************************************************************************
438 {
439  return m_root.isSane();
440 }
441 
442 //***************************************************************************
444 {
445  Kwave::RIFFChunkList chunks;
446  listAllChunks(m_root, chunks);
447 
448  foreach (Kwave::RIFFChunk *chunk, chunks) {
449  if (!chunk) continue;
450  if (path.contains("/")) {
451  // search for full path
452  if (chunk->path() == path) return chunk;
453  } else {
454  // search for name only
455  if (chunk->name() == path) return chunk;
456  }
457  }
458 
459  return Q_NULLPTR;
460 }
461 
462 //***************************************************************************
463 unsigned int Kwave::RIFFParser::chunkCount(const QByteArray &path)
464 {
465  unsigned int count = 0;
466  Kwave::RIFFChunkList chunks;
467  listAllChunks(m_root, chunks);
468 
469  foreach (Kwave::RIFFChunk *chunk, chunks) {
470  if (!chunk) continue;
471  if (path.contains("/")) {
472  // search for full path
473  if (chunk->path() == path) ++count;
474  } else {
475  // search for name only
476  if (chunk->name() == path) ++count;
477  }
478  }
479 
480  return count;
481 }
482 
483 //***************************************************************************
484 QList<quint32> Kwave::RIFFParser::scanForName(const QByteArray &name,
485  quint32 offset, quint32 length,
486  int progress_start, int progress_count)
487 {
488  QList<quint32> matches;
489  if (length < 4) return matches;
490  quint32 end = offset + ((length > 4) ? (length - 4) : 0);
491  char buffer[5];
492  memset(buffer, 0x00, sizeof(buffer));
493 
494  m_dev.seek(offset);
495  m_dev.read(&buffer[0], 4);
496 
497  qDebug("scannig for '%s' at [0x%08X...0x%08X] ...", name.data(),
498  offset, end);
499  quint32 pos;
500  int next = 1;
501  for (pos = offset; (pos <= end) && !m_cancel; ++pos) {
502  if (name == buffer) {
503  // found the name
504  matches.append(pos);
505  }
506  // try the next offset
507  buffer[0] = buffer[1];
508  buffer[1] = buffer[2];
509  buffer[2] = buffer[3];
510  m_dev.getChar(&(buffer[3]));
511 
512  // update progress bar
513  if (!--next && progress_count && (end > offset)) {
514  int percent = (((100*progress_start + (100*(pos-offset)) /
515  (end-offset))) / progress_count);
516  emit progress(percent);
517  next = (end-offset)/100;
518  }
519  }
520 
521  return matches;
522 }
523 
524 //***************************************************************************
526  Kwave::RIFFChunkList &list)
527 {
528  list.append(&parent);
529  foreach (Kwave::RIFFChunk *chunk, parent.subChunks())
530  if (chunk) listAllChunks(*chunk, list);
531 }
532 
533 //***************************************************************************
535 {
537  listAllChunks(m_root, list);
538  foreach (Kwave::RIFFChunk *chunk, list)
539  if (chunk && chunk->physStart() == offset) return chunk;
540  return Q_NULLPTR;
541 }
542 
543 //***************************************************************************
545 {
546  emit action(i18n("Searching for missing chunk '%1'...",
547  QLatin1String(name)));
548  emit progress(0);
549 
550  bool found_something = false;
551 
552  // first search in all garbage areas
553  Kwave::RIFFChunkList all_chunks;
554  listAllChunks(m_root, all_chunks);
555 
556  int index = 0;
557  int count = all_chunks.count();
558  foreach (Kwave::RIFFChunk *chunk, all_chunks) {
559  if (m_cancel) break;
560  if (!chunk) continue;
561  if (chunk->type() == Kwave::RIFFChunk::Garbage) {
562  // search for the name
563  qDebug("searching in garbage at 0x%08X", chunk->physStart());
564  QList<quint32> offsets = scanForName(name,
565  chunk->physStart(), chunk->physLength(),
566  index, count);
567  if (offsets.count()) found_something = true;
568 
569  // process the results -> convert them into chunks
570  quint32 end = chunk->physEnd();
571  foreach (quint32 pos, offsets) {
572  if (m_cancel) break;
573  quint32 len = end - pos + 1;
574  qDebug("found at [0x%08X...0x%08X] len=%u", pos, end, len);
575  parse(chunk, pos, len);
576  qDebug("-------------------------------");
577  }
578  }
579  ++index;
580  }
581 
582  // not found in garbage? search over the rest of the file"
583  if (!found_something && !m_cancel) {
584  qDebug("brute-force search from 0x%08X to 0x%08X",
585  0, m_root.physEnd());
586  QList<quint32> offsets = scanForName(name, 0, m_root.physLength());
587 
588  // process the results -> convert them into chunks
589  quint32 end = m_root.physEnd();
590  foreach (quint32 pos, offsets) {
591  if (m_cancel) break;
592  quint32 len = end - pos + 1;
593  qDebug("found at [0x%08X...0x%08X] len=%u", pos, end, len);
594  parse(&m_root, pos, len);
595  qDebug("-------------------------------");
596  }
597  }
598 
599  return Q_NULLPTR;
600 }
601 
602 //***************************************************************************
604 {
605  bool one_more_pass = true;
606 
607  while (one_more_pass && !m_cancel) {
608  // crawl in garbage for all known chunks and sub-chunks
609  // crawlInGarbage();
610 
611  // clear all main chunks that contain only garbage and convert them
612  // into garbage chunks. maybe they were only false hits in a previous
613  // search in garbage
614  collectGarbage();
615 
616  // join garbage to empty chunks
617  if (joinGarbageToEmpty()) continue;
618 
619  // resolve overlaps of garbage with other chunks
620  fixGarbageEnds();
621 
622  // throw away all remaining garbage
623  qDebug("discarding garbage...");
625 
626  // done, no more passes needed
627  one_more_pass = false;
628  }
629 }
630 
631 //***************************************************************************
633 {
634  // clear all main chunks that contain only garbage and convert them
635  // into garbage chunks
636  bool start_over;
637  do {
638  start_over = false;
639  Kwave::RIFFChunkList chunks;
640  listAllChunks(m_root, chunks);
641 
642  foreach (Kwave::RIFFChunk *chunk, chunks) {
643  if (!chunk) continue;
644  if (start_over || m_cancel) break;
645 
646  // skip garbage chunks themselfes
647  if (chunk->type() == Kwave::RIFFChunk::Garbage) continue;
648 
649  Kwave::RIFFChunkList &subchunks = chunk->subChunks();
650  bool contains_only_garbage = true;
651  foreach (Kwave::RIFFChunk *sub, subchunks) {
652  if (m_cancel) break;
653  if (sub && (sub->type() != Kwave::RIFFChunk::Garbage)) {
654  contains_only_garbage = false;
655  break;
656  }
657  }
658 
659  if (subchunks.count() && contains_only_garbage) {
660  quint32 start = chunk->physStart();
661  quint32 end = chunk->physEnd();
662 
663  qDebug("chunk at 0x%08X contains only garbage!", start);
664  // -> convert into a garbage chunk !
666  chunk->setLength(end - start + 4 + 1);
667  while (!subchunks.isEmpty()) {
668  Kwave::RIFFChunk *c = subchunks.takeLast();
669  if (c) delete c;
670  }
671  chunks.clear();
672 
673  // start over the scan...
674  start_over = true;
675  break;
676  }
677  }
678  } while (start_over && !m_cancel);
679 }
680 
681 //***************************************************************************
683 {
684  qDebug("fixing ends of garbage chunks...");
685 
686  Kwave::RIFFChunkList chunks;
687  listAllChunks(m_root, chunks);
688  QListIterator<Kwave::RIFFChunk *> it1(chunks);
689  QListIterator<Kwave::RIFFChunk *> it2(chunks);
690 
691  // try all combinations of chunks
692  if (it1.hasNext()) it1.next();
693  while (it1.hasNext() && !m_cancel) {
694  Kwave::RIFFChunk *c1 = it1.next();
695  it2 = it1;
696  if (it2.hasNext()) it2.next();
697  while (it2.hasNext() && !m_cancel) {
698  Kwave::RIFFChunk *c2 = it2.next();
699 
700  // children always overlap their parents
701  if (c2->isChildOf(c1)) continue;
702 
703  // get ranges
704  quint32 s1 = c1->physStart();
705  quint32 e1 = c1->physEnd();
706  quint32 s2 = c2->physStart();
707  quint32 e2 = c2->physEnd();
708 
709  // check for overlaps
710  if ((s2 <= e1) && (e2 >= s1)) {
711  qDebug("overlap detected:");
712  qDebug(" at 0x%08X...0x%08X '%s'",
713  s1, e1, c1->name().data());
714  qDebug(" at 0x%08X...0x%08X '%s'",
715  s2, e2, c2->name().data());
716 
717  if ((c1->type() == Kwave::RIFFChunk::Garbage) && (s1 < s2)) {
718  // shorten garbage
719  e1 = s2 - 1;
720  quint32 len = e1 - s1 + 1;
721  qDebug("shortening garbage to %u bytes", len);
722  c1->setLength(len);
723  }
724  }
725  }
726  }
727 
728 }
729 
730 //***************************************************************************
732 {
733  qDebug("joining garbage to empty chunks (and to garbage)...");
734 
735  Kwave::RIFFChunkList chunks;
736  listAllChunks(m_root, chunks);
737  QMutableListIterator<Kwave::RIFFChunk *> it1(chunks);
738  QMutableListIterator<Kwave::RIFFChunk *> it2(chunks);
739 
740  // join garbage to empty chunks
741  if (it2.hasNext()) it2.next();
742  while (it2.hasNext() && it1.hasNext() && !m_cancel) {
743  Kwave::RIFFChunk *chunk = it1.next();
744  Kwave::RIFFChunk *next = it2.next();
745  if (!chunk || !next) continue;
746  bool join = false;
747 
748  if ( ((chunk->type() == Kwave::RIFFChunk::Empty) ||
749  (chunk->dataLength() == 0)) &&
750  ((next->type() == Kwave::RIFFChunk::Garbage) ||
751  (!isKnownName(next->name())) ) )
752  {
753  // join garbage and unknown stuff to empty
754  join = true;
755  }
756 
757  if ( (chunk->type() == Kwave::RIFFChunk::Garbage) &&
758  (next->type() == Kwave::RIFFChunk::Garbage) )
759  {
760  // join garbage to garbage
761  join = true;
762  }
763 
764  if (join) {
765  if ((next->type() == Kwave::RIFFChunk::Garbage) ||
766  (!isKnownName(next->name())) )
767  {
768  quint32 len = next->physLength() + 4;
769  qDebug("joining garbage to empty chunk '%s' at 0x%08X, %u bytes",
770  chunk->name().data(), chunk->physStart(), len);
771  chunk->setLength(len);
772  chunk->setType(guessType(chunk->name()));
773 
774  // remove the garbage chunk, it's no longer needed
775  it2.remove();
776  if (next->parent())
777  next->parent()->subChunks().removeAll(next);
778  delete next;
779 
780  if (chunk->type() == Kwave::RIFFChunk::Main) {
781  // was joined to a main chunk -> parse again!
782  chunk->setFormat(read4ByteString(chunk->physStart() + 8));
783  parse(chunk, chunk->dataStart(), chunk->dataLength());
784  }
785 
786  // need_one_more_pass !
787  return true;
788  }
789  }
790  }
791 
792  return false;
793 }
794 
795 //***************************************************************************
797 {
798  QMutableListIterator<Kwave::RIFFChunk *> it(chunk.subChunks());
799  while (it.hasNext()) {
800  Kwave::RIFFChunk *ch = it.next();
801  if (m_cancel) break;
802  if (!ch) continue;
803  if (ch->type() == Kwave::RIFFChunk::Garbage) {
804  // garbage found -> deleting it
805  it.remove();
806  delete ch;
807  } else {
808  // recursively delete garbage
809  discardGarbage(*ch);
810  }
811  }
812 
813 }
814 
815 //***************************************************************************
817 {
818  qDebug("RIFFParser: --- cancel ---");
819  m_cancel = true;
820 }
821 
822 //***************************************************************************
823 //***************************************************************************
QStringList m_sub_chunk_names
Definition: RIFFParser.h:265
QByteArray read4ByteString(qint64 offset)
Definition: RIFFParser.cpp:208
void listAllChunks(Kwave::RIFFChunk &parent, Kwave::RIFFChunkList &list)
Definition: RIFFParser.cpp:525
Definition: App.h:33
RIFFParser(QIODevice &device, const QStringList &main_chunks, const QStringList &known_subchunks)
Definition: RIFFParser.cpp:58
bool isValidName(const char *name)
Definition: RIFFParser.cpp:76
#define SYSTEM_ENDIANNES
Definition: RIFFParser.cpp:42
void action(const QString &name)
quint32 physEnd() const
Definition: RIFFChunk.cpp:79
Kwave::RIFFChunk * findMissingChunk(const QByteArray &name)
Definition: RIFFParser.cpp:544
quint32 physStart() const
Definition: RIFFChunk.h:135
quint32 physLength() const
Definition: RIFFChunk.h:146
virtual ~RIFFParser()
Definition: RIFFParser.cpp:71
Kwave::RIFFChunk * parent() const
Definition: RIFFChunk.h:103
bool isKnownName(const QByteArray &name)
Definition: RIFFParser.cpp:99
bool addGarbageChunk(Kwave::RIFFChunk *parent, quint32 offset, quint32 length)
Definition: RIFFParser.cpp:278
bool joinGarbageToEmpty()
Definition: RIFFParser.cpp:731
const QByteArray path() const
Definition: RIFFChunk.cpp:88
Kwave::RIFFChunk * chunkAt(quint32 offset)
Definition: RIFFParser.cpp:534
QStringList m_main_chunk_names
Definition: RIFFParser.h:262
quint32 dataStart() const
Definition: RIFFChunk.cpp:130
const char name[16]
Definition: memcpy.c:510
ChunkType type() const
Definition: RIFFChunk.h:85
void setType(ChunkType type)
Definition: RIFFChunk.h:88
void dumpStructure()
Definition: RIFFChunk.cpp:203
static quint32 toUint32(quint64 x)
Definition: RIFFParser.cpp:52
unsigned int chunkCount(const QByteArray &path)
Definition: RIFFParser.cpp:463
QList< Kwave::RIFFChunk * > RIFFChunkList
Definition: RIFFChunk.h:30
quint32 dataLength() const
Definition: RIFFChunk.cpp:136
Kwave::RIFFChunkList & subChunks()
Definition: RIFFChunk.h:151
void progress(int percent)
bool isChildOf(Kwave::RIFFChunk *chunk)
Definition: RIFFChunk.cpp:149
Kwave::RIFFChunk * findChunk(const QByteArray &path)
Definition: RIFFParser.cpp:443
Kwave::RIFFChunk m_root
Definition: RIFFParser.h:259
bool addEmptyChunk(Kwave::RIFFChunk *parent, const QByteArray &name, quint32 offset)
Definition: RIFFParser.cpp:293
Kwave::RIFFChunk::ChunkType guessType(const QByteArray &name)
Definition: RIFFParser.cpp:91
const QByteArray & name() const
Definition: RIFFChunk.h:91
#define _(m)
Definition: memcpy.c:66
void discardGarbage(Kwave::RIFFChunk &chunk)
Definition: RIFFParser.cpp:796
Kwave::RIFFChunk * addChunk(Kwave::RIFFChunk *parent, const QByteArray &name, const QByteArray &format, quint32 length, quint32 phys_offset, quint32 phys_length, Kwave::RIFFChunk::ChunkType type)
Definition: RIFFParser.cpp:235
void setLength(quint32 length)
Definition: RIFFChunk.cpp:142
Kwave::byte_order_t m_endianness
Definition: RIFFParser.h:268
bool isSane() const
Definition: RIFFChunk.cpp:49
void setFormat(const QByteArray &format)
Definition: RIFFChunk.h:100
QIODevice & m_dev
Definition: RIFFParser.h:256
QList< quint32 > scanForName(const QByteArray &name, quint32 offset, quint32 length, int progress_start=0, int progress_count=1)
Definition: RIFFParser.cpp:484