kwave  18.07.70
RIFFChunk.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  RIFFChunk.cpp - information about a RIFF chunk
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 <QList>
21 #include <QString>
22 
23 #include "libkwave/String.h"
24 
25 #include "RIFFChunk.h"
26 
27 //***************************************************************************
28 Kwave::RIFFChunk::RIFFChunk(RIFFChunk *parent, const QByteArray &name,
29  const QByteArray &format, quint32 length,
30  quint32 phys_offset, quint32 phys_length)
31  :m_type(Sub), m_name(name), m_format(format), m_parent(parent),
32  m_chunk_length(length), m_phys_offset(phys_offset),
33  m_phys_length(phys_length), m_sub_chunks()
34 {
35 }
36 
37 //***************************************************************************
39 {
40  while (!m_sub_chunks.isEmpty()) {
41  Kwave::RIFFChunk *chunk = m_sub_chunks.takeLast();
42  if (chunk) delete chunk;
43  }
44 }
45 
46 //***************************************************************************
47 // #define CHECK(x) Q_ASSERT(!(x)); if (x) return false;
48 #define CHECK(x) if (x) return false;
50 {
51  CHECK(m_type == Empty);
52  CHECK(m_type == Garbage);
53  CHECK((m_type == Main) && m_sub_chunks.isEmpty());
54  CHECK((m_type == Root) && m_sub_chunks.isEmpty());
55 
56 #ifdef DEBUG
57  if (m_phys_length & 0x1) {
58  // size is not an even number: no criterium for insanity
59  // but worth a warning
60  qWarning("%s: physical length is not an even number: %u",
61  path().data(), m_phys_length);
62  }
63 #endif /* DEBUG */
64 
65  unsigned int datalen = dataLength();
66  if (m_type == Main) datalen += 4;
67  if (((datalen + 1) < m_phys_length) || (datalen > m_phys_length)) {
68  qWarning("%s: dataLength=%u, phys_length=%u",
69  path().data(), datalen, m_phys_length);
70  return false;
71  }
72 
73  foreach (const Kwave::RIFFChunk *chunk, subChunks())
74  if (chunk && !chunk->isSane()) return false;
75  return true;
76 }
77 
78 //***************************************************************************
80 {
81  quint32 end = m_phys_offset + m_phys_length;
82  if (m_phys_length) --end;
83  if ((m_type != Root) && (m_type != Garbage)) end += 8;
84  return end;
85 }
86 
87 //***************************************************************************
88 const QByteArray Kwave::RIFFChunk::path() const
89 {
90  QByteArray p = "";
91 
92  if (m_parent) p += m_parent->path() + '/';
93  p += m_name;
94  if (m_type == Main) p += ':' + m_format;
95 
96  if (m_parent) {
97  QListIterator<Kwave::RIFFChunk *> it(m_parent->subChunks());
98  unsigned int before = 0;
99  unsigned int after = 0;
100  const Kwave::RIFFChunk *chunk = Q_NULLPTR;
101  while (it.hasNext()) {
102  chunk = it.next();
103  if (!chunk) continue;
104  if (chunk == this) break;
105  if (chunk->name() != m_name) continue;
106  if (chunk->type() != m_type) continue;
107  if ((m_type == Main) && (chunk->format() != m_format)) continue;
108  before++;
109  }
110  if ((chunk == this) && (it.hasNext())) chunk = it.next();
111  while ((chunk != this) && (it.hasNext())) {
112  chunk = it.next();
113  if (!chunk) continue;
114  if (chunk->name() != m_name) continue;
115  if (chunk->type() != m_type) continue;
116  if ((m_type == Main) && (chunk->format() != m_format)) continue;
117  after++;
118  }
119  if (before + after != 0) {
120  QByteArray index;
121  index.setNum(before);
122  p += '(' + index + ')';
123  }
124  }
125 
126  return p;
127 }
128 
129 //***************************************************************************
131 {
132  return m_phys_offset + ((m_type == Main) ? 12 : 8);
133 }
134 
135 //***************************************************************************
137 {
138  return m_chunk_length - ((m_type == Main) ? 4 : 0);
139 }
140 
141 //***************************************************************************
143 {
146 }
147 
148 //***************************************************************************
150 {
151  if (!chunk) return (m_type == Root); // only root has null as parent
152  if (chunk == m_parent) return true;
153  if (m_parent) return m_parent->isChildOf(chunk);
154  return false;
155 }
156 
157 //***************************************************************************
159 {
160  // pass one: fix sizes of sub chunks recursively
161  foreach (Kwave::RIFFChunk *chunk, subChunks())
162  if (chunk) chunk->fixSize();
163 
164  // pass two: sum up sub-chunks if type is main or root.
165  if ((m_type == Main) || (m_type == Root)) {
166  quint32 old_length = m_phys_length;
167  m_phys_length = 0;
168  if (m_type == Main) m_phys_length += 4;
169 
170  foreach (Kwave::RIFFChunk *chunk, subChunks()) {
171  if (!chunk) continue;
172  quint32 len = chunk->physEnd() - chunk->physStart() + 1;
173  m_phys_length += len;
174  }
175  if (m_phys_length != old_length) {
176  qDebug("%s: setting size from %u to %u",
177  path().data(), old_length, m_phys_length);
178  }
179  // chunk length is always equal to physical length for
180  // main and root !
182  } else {
183  // just round up if no main or root chunk
184  if (m_phys_length & 0x1) {
185  m_phys_length++;
186  qDebug("%s: rounding up size to %u", path().data(), m_phys_length);
187  }
188 
189  // adjust chunk size to physical size if not long enough
190  if ((m_chunk_length+1 != m_phys_length) &&
192  {
193  qDebug("%s: resizing chunk from %u to %u",
194  path().data(), m_chunk_length, m_phys_length);
196  }
197 
198  }
199 
200 }
201 
202 //***************************************************************************
204 {
205  // translate the type into a user-readable string
206  const char *t = "?unknown?";
207  switch (m_type) {
208  case Root: t = "ROOT"; break;
209  case Main: t = "MAIN"; break;
210  case Sub: t = "SUB"; break;
211  case Garbage: t = "GARBAGE"; break;
212  case Empty: t = "EMPTY"; break;
213  }
214 
215  // dump this chunk
216  qDebug("[0x%08X-0x%08X] (%10u/%10u) %7s, '%s'",
218  t, path().data()
219  );
220 
221  // recursively dump all sub-chunks
222  foreach (Kwave::RIFFChunk *chunk, m_sub_chunks)
223  if (chunk) chunk->dumpStructure();
224 
225 }
226 
227 //***************************************************************************
228 //***************************************************************************
quint32 m_phys_offset
Definition: RIFFChunk.h:195
quint32 physEnd() const
Definition: RIFFChunk.cpp:79
Kwave::RIFFChunkList m_sub_chunks
Definition: RIFFChunk.h:201
quint32 physStart() const
Definition: RIFFChunk.h:135
#define CHECK(x)
Definition: RIFFChunk.cpp:48
quint32 physLength() const
Definition: RIFFChunk.h:146
quint32 length() const
Definition: RIFFChunk.h:123
QByteArray m_format
Definition: RIFFChunk.h:186
const QByteArray path() const
Definition: RIFFChunk.cpp:88
quint32 dataStart() const
Definition: RIFFChunk.cpp:130
const char name[16]
Definition: memcpy.c:510
ChunkType type() const
Definition: RIFFChunk.h:85
ChunkType m_type
Definition: RIFFChunk.h:180
void dumpStructure()
Definition: RIFFChunk.cpp:203
quint32 m_chunk_length
Definition: RIFFChunk.h:192
quint32 dataLength() const
Definition: RIFFChunk.cpp:136
quint32 m_phys_length
Definition: RIFFChunk.h:198
Kwave::RIFFChunkList & subChunks()
Definition: RIFFChunk.h:151
bool isChildOf(Kwave::RIFFChunk *chunk)
Definition: RIFFChunk.cpp:149
virtual ~RIFFChunk()
Definition: RIFFChunk.cpp:38
Kwave::RIFFChunk * m_parent
Definition: RIFFChunk.h:189
RIFFChunk(Kwave::RIFFChunk *parent, const QByteArray &name, const QByteArray &format, quint32 length, quint32 phys_offset, quint32 phys_length)
Definition: RIFFChunk.cpp:28
QByteArray m_name
Definition: RIFFChunk.h:183
const QByteArray & name() const
Definition: RIFFChunk.h:91
const QByteArray & format() const
Definition: RIFFChunk.h:97
void setLength(quint32 length)
Definition: RIFFChunk.cpp:142
bool isSane() const
Definition: RIFFChunk.cpp:49