GCC Code Coverage Report


Directory: src/
File: src/mpq-wave.c
Date: 2026-09-02 16:40:44
Exec Total Coverage
Lines: 132 208 63.5%
Functions: 4 5 80.0%
Branches: 80 174 46.0%

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 "mpq-internal.h"
29 #include <libmpq/mpq.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 /* Predictor-index adjustments used by the MPQ ADPCM WAVE decoder. */
34 static const uint32_t wave_step_adjustments[] = {
35 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006,
36 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
37 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
38 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008
39 };
40
41 /* Step-size table used by the MPQ ADPCM WAVE decoder. */
42 static const uint32_t wave_step_sizes[] = {
43 0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
44 0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F,
45 0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042,
46 0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F,
47 0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133,
48 0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292,
49 0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583,
50 0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0,
51 0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954,
52 0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B,
53 0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462,
54 0x00007FFF
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 static uint8_t
61 6507 wave_encode_delta(int32_t difference, int32_t *predictor, int32_t *step_index, uint32_t shift)
62 {
63 6507 uint32_t step = wave_step_sizes[*step_index];
64 6507 uint32_t magnitude = (difference < 0) ? (uint32_t)-difference : (uint32_t)difference;
65 6507 uint32_t code = difference < 0 ? 0x40u : 0;
66 uint32_t bit;
67 6507 int32_t delta = (int32_t)(step >> shift);
68
2/2
✓ Branch 0 taken 39042 times.
✓ Branch 1 taken 6507 times.
45549 for (bit = 0; bit < 6; bit++) {
69 39042 uint32_t contribution = step >> bit;
70
2/2
✓ Branch 0 taken 15782 times.
✓ Branch 1 taken 23260 times.
39042 if (magnitude >= (uint32_t)(delta + (int32_t)contribution)) {
71 15782 code |= 1u << bit;
72 15782 delta += (int32_t)contribution;
73 }
74 }
75
2/2
✓ Branch 0 taken 3253 times.
✓ Branch 1 taken 3254 times.
6507 if (difference < 0)
76 3253 *predictor -= delta;
77 else
78 3254 *predictor += delta;
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6507 times.
6507 if (*predictor > 32767)
80 *predictor = 32767;
81
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6507 times.
6507 if (*predictor < -32768)
82 *predictor = -32768;
83 6507 *step_index += (int32_t)wave_step_adjustments[code & 0x1f];
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6507 times.
6507 if (*step_index < 0)
85 *step_index = 0;
86
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6507 times.
6507 if (*step_index > 0x58)
87 *step_index = 0x58;
88 6507 return (uint8_t)code;
89 }
90
91 /* Inspect a RIFF/WAVE prefix and validate its PCM16 channel configuration.
92 * Chunk boundaries, padding, channel count, sample width, and complete PCM
93 * frames are checked before offsets and sizes are returned to the caller. */
94 int32_t
95 libmpq__wave_probe_pcm16(const uint8_t *data, uint32_t size, libmpq_wave_info_s *info)
96 {
97 uint32_t pos = 12;
98 uint32_t end;
99 uint16_t channels = 0;
100 uint16_t format = 0;
101 uint16_t bits = 0;
102 uint32_t data_offset = 0;
103 uint32_t data_size = 0;
104 if (data == NULL || info == NULL || size < 12 || memcmp(data, "RIFF", 4) != 0 ||
105 memcmp(data + 8, "WAVE", 4) != 0)
106 return LIBMPQ_ERROR_FORMAT;
107 end = size;
108
109 /* Walk RIFF chunks while honoring the required even-byte chunk padding. */
110 while (pos + 8 <= end) {
111 uint32_t chunk_size = libmpq__load_le32(data + pos + 4);
112 uint32_t next = pos + 8 + chunk_size + (chunk_size & 1u);
113 if (next < pos || next > end)
114 return LIBMPQ_ERROR_FORMAT;
115 if (memcmp(data + pos, "fmt ", 4) == 0 && chunk_size >= 16) {
116 format = libmpq__load_le16(data + pos + 8);
117 channels = libmpq__load_le16(data + pos + 10);
118 bits = libmpq__load_le16(data + pos + 22);
119 } else if (memcmp(data + pos, "data", 4) == 0) {
120 data_offset = pos + 8;
121 data_size = chunk_size;
122 }
123 pos = next;
124 }
125 if (format != 1 || (channels != 1 && channels != 2) || bits != 16 || data_offset == 0 ||
126 data_offset > size || (data_size % (channels * 2)) != 0)
127 return LIBMPQ_ERROR_FORMAT;
128 info->channels = channels;
129 info->data_offset = data_offset;
130 info->data_size = data_size;
131 return LIBMPQ_SUCCESS;
132 }
133
134 /* Validate a RIFF/WAVE prefix when later PCM bytes are not buffered yet.
135 * The available prefix must contain the format and data chunk headers, while
136 * the declared data range must fit within the complete writer file size. */
137 int32_t
138 2 libmpq__wave_probe_pcm16_prefix(
139 const uint8_t *data, uint32_t prefix_size, uint64_t file_size, libmpq_wave_info_s *info
140 )
141 {
142 2 uint32_t pos = 12;
143 2 uint16_t channels = 0;
144 2 uint16_t format = 0;
145 2 uint16_t bits = 0;
146 2 uint32_t data_offset = 0;
147 2 uint32_t data_size = 0;
148
149
4/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 if (data == NULL || info == NULL || prefix_size < 12 || file_size < prefix_size ||
150
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 memcmp(data, "RIFF", 4) != 0 || memcmp(data + 8, "WAVE", 4) != 0)
151 return LIBMPQ_ERROR_FORMAT;
152
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 while (pos + 8 <= prefix_size) {
153 4 uint32_t chunk_size = libmpq__load_le32(data + pos + 4);
154 4 uint64_t next = (uint64_t)pos + 8 + chunk_size + (chunk_size & 1u);
155
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
4 if (next < pos || next > file_size)
156 1 return LIBMPQ_ERROR_FORMAT;
157
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
3 if (memcmp(data + pos, "fmt ", 4) == 0 && chunk_size >= 16) {
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ((uint64_t)pos + 24 > prefix_size)
159 return LIBMPQ_ERROR_FORMAT;
160 2 format = libmpq__load_le16(data + pos + 8);
161 2 channels = libmpq__load_le16(data + pos + 10);
162 2 bits = libmpq__load_le16(data + pos + 22);
163
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (memcmp(data + pos, "data", 4) == 0) {
164 1 data_offset = pos + 8;
165 1 data_size = chunk_size;
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if ((uint64_t)data_offset + data_size > file_size)
167 return LIBMPQ_ERROR_FORMAT;
168 1 break;
169 }
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (next > prefix_size)
171 break;
172 2 pos = (uint32_t)next;
173 }
174
5/12
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 if (format != 1 || (channels != 1 && channels != 2) || bits != 16 || data_offset == 0 ||
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 data_offset > prefix_size || (data_size % (channels * 2)) != 0)
176 return LIBMPQ_ERROR_FORMAT;
177 1 info->channels = channels;
178 1 info->data_offset = data_offset;
179 1 info->data_size = data_size;
180 1 return LIBMPQ_SUCCESS;
181 }
182
183 /* Encode one complete PCM sector using the MPQ mono/stereo ADPCM format.
184 * The first sample of each channel seeds the predictor header, and subsequent
185 * interleaved samples are reduced to adaptive six-bit delta codes. */
186 int32_t
187 7 libmpq__wave_compress(
188 const uint8_t *in_buf, uint32_t in_size, uint8_t **out_buf, uint32_t *out_size,
189 uint32_t channels
190 )
191 {
192 uint32_t samples;
193 uint32_t i;
194 7 uint32_t shift = 4;
195 uint32_t pos;
196
197 7 int32_t predictor[2] = { 0, 0 };
198 7 int32_t index[2] = { 0x2c, 0x2c };
199
200 uint8_t *out;
201
6/10
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
7 if (out_buf == NULL || out_size == NULL || in_buf == NULL || (channels != 1 && channels != 2) ||
202
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 in_size < channels * 2 || (in_size % (channels * 2)) != 0)
203 return LIBMPQ_ERROR_FORMAT;
204 7 samples = in_size / (channels * 2);
205 7 out = malloc(2 + channels * 2 + samples * channels);
206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (out == NULL)
207 return LIBMPQ_ERROR_MALLOC;
208 7 libmpq__store_le16(out, 0);
209 7 out[1] = (uint8_t)shift;
210 7 pos = 2;
211
212 /* Store one initial predictor sample per channel in the compressed header. */
213
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 7 times.
16 for (i = 0; i < channels; i++) {
214 9 predictor[i] = (int16_t)libmpq__load_le16(in_buf + i * 2);
215 9 libmpq__store_le16(out + pos, (uint16_t)predictor[i]);
216 9 pos += 2;
217 }
218
219 /* Encode the remaining interleaved frames using shared channel state. */
220
2/2
✓ Branch 0 taken 5995 times.
✓ Branch 1 taken 7 times.
6002 for (i = 1; i < samples; i++) {
221 uint32_t channel;
222
2/2
✓ Branch 0 taken 6507 times.
✓ Branch 1 taken 5995 times.
12502 for (channel = 0; channel < channels; channel++) {
223 6507 int32_t sample = (int16_t)libmpq__load_le16(in_buf + (i * channels + channel) * 2);
224 6507 out[pos++] = wave_encode_delta(
225 6507 sample - predictor[channel], &predictor[channel], &index[channel], shift
226 );
227 }
228 }
229 7 *out_buf = out;
230 7 *out_size = pos;
231 7 return LIBMPQ_SUCCESS;
232 }
233
234 /* Decompress mono or stereo MPQ WAVE predictor data into PCM bytes.
235 * It restores channel seed samples first, then applies control and delta
236 * bytes until the input or caller-provided output capacity is exhausted. */
237 int32_t
238 7 libmpq__wave_decompress(
239 uint8_t *out_buf, int32_t out_length, uint8_t *in_buf, int32_t in_length, int32_t channels
240 )
241 {
242
243 /* Decoder state for channel deltas and transferred bytes. */
244 uint8_t *out_ptr;
245 uint32_t index;
246 int32_t step_indices[2];
247 int32_t predictor_samples[2];
248 7 int32_t count = 0;
249 uint32_t shift;
250
251
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
7 if (channels < 1 || channels > 2 || in_length < 2 + channels * 2) {
252 return 0;
253 }
254
255 7 shift = in_buf[1];
256
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 if (shift >= 32) {
257 2 return 0;
258 }
259
260 /* Stop decoding when the compressed stream cursor reaches this address. */
261 5 uint8_t *in_end = in_buf + in_length;
262
263 5 out_ptr = out_buf;
264 5 step_indices[0] = 0x2C;
265 5 step_indices[1] = 0x2C;
266
267 /* The first word is the MPQ WAVE predictor header, followed by seed samples. */
268 5 in_buf += sizeof(uint16_t);
269
270 /* Emit the initial seed sample for each channel before delta decoding. */
271
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
11 for (count = 0; count < channels; count++) {
272
273 /* Current sample code and output channel for this input byte. */
274 int32_t temp;
275
276 6 temp = (int16_t)libmpq__load_le16(in_buf);
277 6 in_buf += sizeof(uint16_t);
278 6 predictor_samples[count] = temp;
279
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (out_length < 2) {
281 return (int32_t)(out_ptr - out_buf);
282 }
283
284 6 libmpq__store_le16(out_ptr, (uint16_t)temp);
285 6 out_ptr += sizeof(uint16_t);
286 6 out_length -= 2;
287 }
288
289 /* Start with the last channel so stereo data alternates on each emitted sample. */
290 5 index = channels - 1;
291
292 /* Decode interleaved control bytes until input or output capacity is exhausted. */
293
2/2
✓ Branch 0 taken 5739 times.
✓ Branch 1 taken 5 times.
5744 while (in_buf < in_end) {
294 5739 uint8_t one_byte = *in_buf++;
295
296
2/2
✓ Branch 0 taken 512 times.
✓ Branch 1 taken 5227 times.
5739 if (channels == 2) {
297 512 index = (index == 0) ? 1 : 0;
298 }
299
300 /* High-bit control bytes adjust predictor index and do not emit samples. */
301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5739 times.
5739 if (one_byte & 0x80) {
302 switch (one_byte & 0x7F) {
303 case 0:
304
305 if (step_indices[index] != 0) {
306 step_indices[index]--;
307 }
308
309 if (out_length < 2) {
310 break;
311 }
312
313 libmpq__store_le16(out_ptr, (uint16_t)predictor_samples[index]);
314 out_ptr += sizeof(uint16_t);
315 out_length -= 2;
316 continue;
317 case 1:
318
319 step_indices[index] += 8;
320
321 if (step_indices[index] > 0x58) {
322 step_indices[index] = 0x58;
323 }
324
325 if (channels == 2) {
326 index = (index == 0) ? 1 : 0;
327 }
328 continue;
329 case 2:
330 continue;
331 default:
332 step_indices[index] -= 8;
333
334 if (step_indices[index] < 0) {
335 step_indices[index] = 0;
336 }
337
338 if (channels != 2) {
339 continue;
340 }
341 index = (index == 0) ? 1 : 0;
342 continue;
343 }
344 } else {
345
346 /* Low-bit values update the active channel predictor and emit PCM. */
347
348 /* Decode a signed delta from the current step-size table entry. */
349 5739 uint32_t temp1 = wave_step_sizes[step_indices[index]];
350 5739 uint32_t temp2 = temp1 >> shift;
351 5739 int32_t temp3 = predictor_samples[index];
352
353
2/2
✓ Branch 0 taken 4480 times.
✓ Branch 1 taken 1259 times.
5739 if (one_byte & 0x01) {
354 4480 temp2 += (temp1 >> 0);
355 }
356
2/2
✓ Branch 0 taken 1236 times.
✓ Branch 1 taken 4503 times.
5739 if (one_byte & 0x02) {
357 1236 temp2 += (temp1 >> 1);
358 }
359
2/2
✓ Branch 0 taken 1237 times.
✓ Branch 1 taken 4502 times.
5739 if (one_byte & 0x04) {
360 1237 temp2 += (temp1 >> 2);
361 }
362
2/2
✓ Branch 0 taken 1247 times.
✓ Branch 1 taken 4492 times.
5739 if (one_byte & 0x08) {
363 1247 temp2 += (temp1 >> 3);
364 }
365
2/2
✓ Branch 0 taken 2427 times.
✓ Branch 1 taken 3312 times.
5739 if (one_byte & 0x10) {
366 2427 temp2 += (temp1 >> 4);
367 }
368
2/2
✓ Branch 0 taken 3286 times.
✓ Branch 1 taken 2453 times.
5739 if (one_byte & 0x20) {
369 3286 temp2 += (temp1 >> 5);
370 }
371
2/2
✓ Branch 0 taken 2890 times.
✓ Branch 1 taken 2849 times.
5739 if (one_byte & 0x40) {
372 2890 temp3 -= temp2;
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2890 times.
2890 if (temp3 <= (int32_t)0xFFFF8000) {
374 temp3 = (int32_t)0xFFFF8000;
375 }
376 } else {
377 2849 temp3 += temp2;
378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2849 times.
2849 if (temp3 >= 0x7FFF) {
379 temp3 = 0x7FFF;
380 }
381 }
382
383 /* Store the clamped predictor sample for the active channel. */
384 5739 predictor_samples[index] = temp3;
385
386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5739 times.
5739 if (out_length < 2) {
387 break;
388 }
389
390 5739 temp2 = step_indices[index];
391 5739 one_byte &= 0x1F;
392 5739 libmpq__store_le16(out_ptr, (uint16_t)temp3);
393 5739 out_ptr += sizeof(uint16_t);
394 5739 out_length -= 2;
395 5739 temp2 += wave_step_adjustments[one_byte];
396 5739 step_indices[index] = temp2;
397
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5739 times.
5739 if (step_indices[index] < 0) {
399 step_indices[index] = 0;
400 } else {
401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5739 times.
5739 if (step_indices[index] > 0x58) {
402 step_indices[index] = 0x58;
403 }
404 }
405 }
406 }
407
408 5 return (int32_t)(out_ptr - out_buf);
409 }
410