GCC Code Coverage Report


Directory: src/
File: src/mpq-wave.c
Date: 2026-10-06 13:47:41
Exec Total Coverage
Lines: 133 208 63.9%
Functions: 4 5 80.0%
Branches: 83 174 47.7%

Line Branch Exec Source
1 /*
2 * mpq-wave.c -- WAVE decompression helpers for MPQ audio payloads.
3 *
4 * Copyright (c) 2003-2026 Maik Broemme <mbroemme@libmpq.org>
5 *
6 * This source was adapted from the C++ version of wave.cpp included
7 * in stormlib. The C++ version belongs to the following authors:
8 *
9 * Ladislav Zezula <ladik@zezula.net>
10 * Tom Amigo <tomamigo@apexmail.com>
11 *
12 * This file is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
16 *
17 * This file is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this file; if not, see <https://www.gnu.org/licenses/>.
24 */
25
26 #include "mpq-wave.h"
27 #include "mpq-endian.h"
28 #include <libmpq/mpq.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 /* Predictor-index adjustments used by the MPQ ADPCM WAVE decoder. */
33 static const uint32_t wave_step_adjustments[] = {
34 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006,
35 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
36 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
37 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008
38 };
39
40 /* Step-size table used by the MPQ ADPCM WAVE decoder. */
41 static const uint32_t wave_step_sizes[] = {
42 0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
43 0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F,
44 0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042,
45 0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F,
46 0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133,
47 0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292,
48 0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583,
49 0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0,
50 0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954,
51 0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B,
52 0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462,
53 0x00007FFF
54 };
55
56 /*
57 * Quantize one PCM predictor difference into the MPQ ADPCM control byte.
58 * The predictor and step index are updated in place so the next sample uses
59 * the same adaptive state as the matching decoder.
60 */
61 static uint8_t
62 35420 wave_encode_delta(int32_t difference, int32_t *predictor, int32_t *step_index, uint32_t shift)
63 {
64 35420 uint32_t step = wave_step_sizes[*step_index];
65 35420 uint32_t magnitude = (difference < 0) ? (uint32_t)-difference : (uint32_t)difference;
66 35420 uint32_t code = difference < 0 ? 0x40u : 0;
67 uint32_t bit;
68 35420 int32_t delta = (int32_t)(step >> shift);
69
2/2
✓ Branch 0 taken 212520 times.
✓ Branch 1 taken 35420 times.
247940 for (bit = 0; bit < 6; bit++) {
70 212520 uint32_t contribution = step >> bit;
71
2/2
✓ Branch 0 taken 85918 times.
✓ Branch 1 taken 126602 times.
212520 if (magnitude >= (uint32_t)(delta + (int32_t)contribution)) {
72 85918 code |= 1u << bit;
73 85918 delta += (int32_t)contribution;
74 }
75 }
76
2/2
✓ Branch 0 taken 17832 times.
✓ Branch 1 taken 17588 times.
35420 if (difference < 0)
77 17832 *predictor -= delta;
78 else
79 17588 *predictor += delta;
80
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35420 times.
35420 if (*predictor > 32767)
81 ✗ *predictor = 32767;
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35420 times.
35420 if (*predictor < -32768)
83 ✗ *predictor = -32768;
84 35420 *step_index += (int32_t)wave_step_adjustments[code & 0x1f];
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35420 times.
35420 if (*step_index < 0)
86 ✗ *step_index = 0;
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35420 times.
35420 if (*step_index > 0x58)
88 ✗ *step_index = 0x58;
89 35420 return (uint8_t)code;
90 }
91
92 /*
93 * Inspect a RIFF/WAVE prefix and validate its PCM16 channel configuration.
94 * Chunk boundaries, padding, channel count, sample width, and complete PCM
95 * frames are checked before offsets and sizes are returned to the caller.
96 */
97 int32_t
98 ✗ libmpq__wave_probe_pcm16(const uint8_t *data, uint32_t size, libmpq_wave_info_s *info)
99 {
100 ✗ uint32_t pos = 12;
101 uint32_t end;
102 ✗ uint16_t channels = 0;
103 ✗ uint16_t format = 0;
104 ✗ uint16_t bits = 0;
105 ✗ uint32_t data_offset = 0;
106 ✗ uint32_t data_size = 0;
107 ✗ if (data == NULL || info == NULL || size < 12 || memcmp(data, "RIFF", 4) != 0 ||
108 ✗ memcmp(data + 8, "WAVE", 4) != 0)
109 ✗ return LIBMPQ_ERROR_FORMAT;
110 ✗ end = size;
111
112 /* Walk RIFF chunks while honoring the required even-byte chunk padding. */
113 ✗ while (pos + 8 <= end) {
114 ✗ uint32_t chunk_size = libmpq__load_le32(data + pos + 4);
115 ✗ uint32_t next = pos + 8 + chunk_size + (chunk_size & 1u);
116 ✗ if (next < pos || next > end)
117 ✗ return LIBMPQ_ERROR_FORMAT;
118 ✗ if (memcmp(data + pos, "fmt ", 4) == 0 && chunk_size >= 16) {
119 ✗ format = libmpq__load_le16(data + pos + 8);
120 ✗ channels = libmpq__load_le16(data + pos + 10);
121 ✗ bits = libmpq__load_le16(data + pos + 22);
122 ✗ } else if (memcmp(data + pos, "data", 4) == 0) {
123 ✗ data_offset = pos + 8;
124 ✗ data_size = chunk_size;
125 }
126 ✗ pos = next;
127 }
128 ✗ if (format != 1 || (channels != 1 && channels != 2) || bits != 16 || data_offset == 0 ||
129 ✗ data_offset > size || (data_size % (channels * 2)) != 0)
130 ✗ return LIBMPQ_ERROR_FORMAT;
131 ✗ info->channels = channels;
132 ✗ info->data_offset = data_offset;
133 ✗ info->data_size = data_size;
134 ✗ return 0;
135 }
136
137 /*
138 * Validate a RIFF/WAVE prefix when later PCM bytes are not buffered yet.
139 * The available prefix must contain the format and data chunk headers, while
140 * the declared data range must fit within the complete writer file size.
141 */
142 int32_t
143 5 libmpq__wave_probe_pcm16_prefix(
144 const uint8_t *data, uint32_t prefix_size, uint64_t file_size, libmpq_wave_info_s *info
145 )
146 {
147 5 uint32_t pos = 12;
148 5 uint16_t channels = 0;
149 5 uint16_t format = 0;
150 5 uint16_t bits = 0;
151 5 uint32_t data_offset = 0;
152 5 uint32_t data_size = 0;
153
154
4/8
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5 if (data == NULL || info == NULL || prefix_size < 12 || file_size < prefix_size ||
155
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 memcmp(data, "RIFF", 4) != 0 || memcmp(data + 8, "WAVE", 4) != 0)
156 ✗ return LIBMPQ_ERROR_FORMAT;
157
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 while (pos + 8 <= prefix_size) {
158 10 uint32_t chunk_size = libmpq__load_le32(data + pos + 4);
159 10 uint64_t next = (uint64_t)pos + 8 + chunk_size + (chunk_size & 1u);
160
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
10 if (next < pos || next > file_size)
161 1 return LIBMPQ_ERROR_FORMAT;
162
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
9 if (memcmp(data + pos, "fmt ", 4) == 0 && chunk_size >= 16) {
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if ((uint64_t)pos + 24 > prefix_size)
164 ✗ return LIBMPQ_ERROR_FORMAT;
165 5 format = libmpq__load_le16(data + pos + 8);
166 5 channels = libmpq__load_le16(data + pos + 10);
167 5 bits = libmpq__load_le16(data + pos + 22);
168
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (memcmp(data + pos, "data", 4) == 0) {
169 4 data_offset = pos + 8;
170 4 data_size = chunk_size;
171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if ((uint64_t)data_offset + data_size > file_size)
172 ✗ return LIBMPQ_ERROR_FORMAT;
173 4 break;
174 }
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (next > prefix_size)
176 ✗ break;
177 5 pos = (uint32_t)next;
178 }
179
7/12
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
4 if (format != 1 || (channels != 1 && channels != 2) || bits != 16 || data_offset == 0 ||
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 data_offset > prefix_size || (data_size % (channels * 2)) != 0)
181 ✗ return LIBMPQ_ERROR_FORMAT;
182 4 info->channels = channels;
183 4 info->data_offset = data_offset;
184 4 info->data_size = data_size;
185 4 return 0;
186 }
187
188 /*
189 * Encode one complete PCM sector using the MPQ mono/stereo ADPCM format.
190 * The first sample of each channel seeds the predictor header, and subsequent
191 * interleaved samples are reduced to adaptive six-bit delta codes.
192 */
193 int32_t
194 30 libmpq__wave_compress(
195 const uint8_t *in_buf, uint32_t in_size, uint8_t **out_buf, uint32_t *out_size,
196 uint32_t channels
197 )
198 {
199 uint32_t samples;
200 uint32_t i;
201 30 uint32_t shift = 4;
202 uint32_t pos;
203
204 30 int32_t predictor[2] = { 0, 0 };
205 30 int32_t index[2] = { 0x2c, 0x2c };
206
207 uint8_t *out;
208
6/10
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
30 if (out_buf == NULL || out_size == NULL || in_buf == NULL || (channels != 1 && channels != 2) ||
209
3/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 26 times.
30 in_size < channels * 2 || (in_size % (channels * 2)) != 0)
210 4 return LIBMPQ_ERROR_FORMAT;
211 26 samples = in_size / (channels * 2);
212 26 out = malloc(2 + channels * 2 + samples * channels);
213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (out == NULL)
214 ✗ return LIBMPQ_ERROR_MALLOC;
215 26 libmpq__store_le16(out, 0);
216 26 out[1] = (uint8_t)shift;
217 26 pos = 2;
218
219 /* Store one initial predictor sample per channel in the compressed header. */
220
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 26 times.
68 for (i = 0; i < channels; i++) {
221 42 predictor[i] = (int16_t)libmpq__load_le16(in_buf + i * 2);
222 42 libmpq__store_le16(out + pos, (uint16_t)predictor[i]);
223 42 pos += 2;
224 }
225
226 /* Encode the remaining interleaved frames using shared channel state. */
227
2/2
✓ Branch 0 taken 22942 times.
✓ Branch 1 taken 26 times.
22968 for (i = 1; i < samples; i++) {
228 uint32_t channel;
229
2/2
✓ Branch 0 taken 35420 times.
✓ Branch 1 taken 22942 times.
58362 for (channel = 0; channel < channels; channel++) {
230 35420 int32_t sample = (int16_t)libmpq__load_le16(in_buf + (i * channels + channel) * 2);
231 35420 out[pos++] = wave_encode_delta(
232 35420 sample - predictor[channel], &predictor[channel], &index[channel], shift
233 );
234 }
235 }
236 26 *out_buf = out;
237 26 *out_size = pos;
238 26 return 0;
239 }
240
241 /*
242 * Decompress mono or stereo MPQ WAVE predictor data into PCM bytes.
243 * It restores channel seed samples first, then applies control and delta
244 * bytes until the input or caller-provided output capacity is exhausted.
245 */
246 int32_t
247 208 libmpq__wave_decompress(
248 uint8_t *out_buf, int32_t out_length, uint8_t *in_buf, int32_t in_length, int32_t channels
249 )
250 {
251
252 /* Decoder state for channel deltas and transferred bytes. */
253 uint8_t *out_ptr;
254 uint32_t index;
255 int32_t step_indices[2];
256 int32_t predictor_samples[2];
257 208 int32_t count = 0;
258 uint32_t shift;
259
260
3/6
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 208 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 208 times.
208 if (channels < 1 || channels > 2 || in_length < 2 + channels * 2) {
261 ✗ return 0;
262 }
263
264 208 shift = in_buf[1];
265
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 206 times.
208 if (shift >= 32) {
266 2 return 0;
267 }
268
269 /* Stop decoding when the compressed stream cursor reaches this address. */
270 206 uint8_t *in_end = in_buf + in_length;
271
272 206 out_ptr = out_buf;
273 206 step_indices[0] = 0x2C;
274 206 step_indices[1] = 0x2C;
275
276 /* The first word is the MPQ WAVE predictor header, followed by seed samples. */
277 206 in_buf += sizeof(uint16_t);
278
279 /* Emit the initial seed sample for each channel before delta decoding. */
280
2/2
✓ Branch 0 taken 339 times.
✓ Branch 1 taken 206 times.
545 for (count = 0; count < channels; count++) {
281
282 /* Current sample code and output channel for this input byte. */
283 int32_t temp;
284
285 339 temp = (int16_t)libmpq__load_le16(in_buf);
286 339 in_buf += sizeof(uint16_t);
287 339 predictor_samples[count] = temp;
288
289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 339 times.
339 if (out_length < 2) {
290 ✗ return (int32_t)(out_ptr - out_buf);
291 }
292
293 339 libmpq__store_le16(out_ptr, (uint16_t)temp);
294 339 out_ptr += sizeof(uint16_t);
295 339 out_length -= 2;
296 }
297
298 /* Start with the last channel so stereo data alternates on each emitted sample. */
299 206 index = channels - 1;
300
301 /* Decode interleaved control bytes until input or output capacity is exhausted. */
302
2/2
✓ Branch 0 taken 383236 times.
✓ Branch 1 taken 206 times.
383442 while (in_buf < in_end) {
303 383236 uint8_t one_byte = *in_buf++;
304
305
2/2
✓ Branch 0 taken 263676 times.
✓ Branch 1 taken 119560 times.
383236 if (channels == 2) {
306 263676 index = (index == 0) ? 1 : 0;
307 }
308
309 /* High-bit control bytes adjust predictor index and do not emit samples. */
310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383236 times.
383236 if (one_byte & 0x80) {
311 ✗ switch (one_byte & 0x7F) {
312 ✗ case 0:
313
314 ✗ if (step_indices[index] != 0) {
315 ✗ step_indices[index]--;
316 }
317
318 ✗ if (out_length < 2) {
319 ✗ break;
320 }
321
322 ✗ libmpq__store_le16(out_ptr, (uint16_t)predictor_samples[index]);
323 ✗ out_ptr += sizeof(uint16_t);
324 ✗ out_length -= 2;
325 ✗ continue;
326 ✗ case 1:
327
328 ✗ step_indices[index] += 8;
329
330 ✗ if (step_indices[index] > 0x58) {
331 ✗ step_indices[index] = 0x58;
332 }
333
334 ✗ if (channels == 2) {
335 ✗ index = (index == 0) ? 1 : 0;
336 }
337 ✗ continue;
338 ✗ case 2:
339 ✗ continue;
340 ✗ default:
341 ✗ step_indices[index] -= 8;
342
343 ✗ if (step_indices[index] < 0) {
344 ✗ step_indices[index] = 0;
345 }
346
347 ✗ if (channels != 2) {
348 ✗ continue;
349 }
350 ✗ index = (index == 0) ? 1 : 0;
351 ✗ continue;
352 }
353 } else {
354
355 /* Low-bit values update the active channel predictor and emit PCM. */
356
357 /* Decode a signed delta from the current step-size table entry. */
358 383236 uint32_t temp1 = wave_step_sizes[step_indices[index]];
359 383236 uint32_t temp2 = temp1 >> shift;
360 383236 int32_t temp3 = predictor_samples[index];
361
362
2/2
✓ Branch 0 taken 299250 times.
✓ Branch 1 taken 83986 times.
383236 if (one_byte & 0x01) {
363 299250 temp2 += (temp1 >> 0);
364 }
365
2/2
✓ Branch 0 taken 82447 times.
✓ Branch 1 taken 300789 times.
383236 if (one_byte & 0x02) {
366 82447 temp2 += (temp1 >> 1);
367 }
368
2/2
✓ Branch 0 taken 82515 times.
✓ Branch 1 taken 300721 times.
383236 if (one_byte & 0x04) {
369 82515 temp2 += (temp1 >> 2);
370 }
371
2/2
✓ Branch 0 taken 83509 times.
✓ Branch 1 taken 299727 times.
383236 if (one_byte & 0x08) {
372 83509 temp2 += (temp1 >> 3);
373 }
374
2/2
✓ Branch 0 taken 161934 times.
✓ Branch 1 taken 221302 times.
383236 if (one_byte & 0x10) {
375 161934 temp2 += (temp1 >> 4);
376 }
377
2/2
✓ Branch 0 taken 219270 times.
✓ Branch 1 taken 163966 times.
383236 if (one_byte & 0x20) {
378 219270 temp2 += (temp1 >> 5);
379 }
380
2/2
✓ Branch 0 taken 193451 times.
✓ Branch 1 taken 189785 times.
383236 if (one_byte & 0x40) {
381 193451 temp3 -= temp2;
382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 193451 times.
193451 if (temp3 <= (int32_t)0xFFFF8000) {
383 ✗ temp3 = (int32_t)0xFFFF8000;
384 }
385 } else {
386 189785 temp3 += temp2;
387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 189785 times.
189785 if (temp3 >= 0x7FFF) {
388 ✗ temp3 = 0x7FFF;
389 }
390 }
391
392 /* Store the clamped predictor sample for the active channel. */
393 383236 predictor_samples[index] = temp3;
394
395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383236 times.
383236 if (out_length < 2) {
396 ✗ break;
397 }
398
399 383236 temp2 = step_indices[index];
400 383236 one_byte &= 0x1F;
401 383236 libmpq__store_le16(out_ptr, (uint16_t)temp3);
402 383236 out_ptr += sizeof(uint16_t);
403 383236 out_length -= 2;
404 383236 temp2 += wave_step_adjustments[one_byte];
405 383236 step_indices[index] = temp2;
406
407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383236 times.
383236 if (step_indices[index] < 0) {
408 ✗ step_indices[index] = 0;
409 } else {
410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383236 times.
383236 if (step_indices[index] > 0x58) {
411 ✗ step_indices[index] = 0x58;
412 }
413 }
414 }
415 }
416
417 206 return (int32_t)(out_ptr - out_buf);
418 }
419