File: | read-wav.c |
Warning: | line 245, column 17 This statement is never executed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ |
2 | |
3 | /*** |
4 | This file is part of libkanberra. |
5 | |
6 | Copyright 2008 Lennart Poettering |
7 | |
8 | libkanberra is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU Lesser General Public License as |
10 | published by the Free Software Foundation, either version 2.1 of the |
11 | License, or (at your option) any later version. |
12 | |
13 | libkanberra is distributed in the hope that it will be useful, but |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | Lesser General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU Lesser General Public |
19 | License along with libkanberra. If not, see |
20 | <http://www.gnu.org/licenses/>. |
21 | ***/ |
22 | |
23 | #ifdef HAVE_CONFIG_H1 |
24 | #include <config.h> |
25 | #endif |
26 | |
27 | #include "kanberra.h" |
28 | #include "read-wav.h" |
29 | #include "macro.h" |
30 | #include "malloc.h" |
31 | |
32 | #define FILE_SIZE_MAX(64U*1024U*1024U) (64U*1024U*1024U) |
33 | |
34 | /* Stores the bit indexes in dwChannelMask */ |
35 | enum { |
36 | BIT_FRONT_LEFT, |
37 | BIT_FRONT_RIGHT, |
38 | BIT_FRONT_CENTER, |
39 | BIT_LOW_FREQUENCY, |
40 | BIT_BACK_LEFT, |
41 | BIT_BACK_RIGHT, |
42 | BIT_FRONT_LEFT_OF_CENTER, |
43 | BIT_FRONT_RIGHT_OF_CENTER, |
44 | BIT_BACK_CENTER, |
45 | BIT_SIDE_LEFT, |
46 | BIT_SIDE_RIGHT, |
47 | BIT_TOP_CENTER, |
48 | BIT_TOP_FRONT_LEFT, |
49 | BIT_TOP_FRONT_CENTER, |
50 | BIT_TOP_FRONT_RIGHT, |
51 | BIT_TOP_BACK_LEFT, |
52 | BIT_TOP_BACK_CENTER, |
53 | BIT_TOP_BACK_RIGHT, |
54 | _BIT_MAX |
55 | }; |
56 | |
57 | static const ka_channel_position_t channel_table[_BIT_MAX] = { |
58 | [BIT_FRONT_LEFT] = KA_CHANNEL_FRONT_LEFT, |
59 | [BIT_FRONT_RIGHT] = KA_CHANNEL_FRONT_RIGHT, |
60 | [BIT_FRONT_CENTER] = KA_CHANNEL_FRONT_CENTER, |
61 | [BIT_LOW_FREQUENCY] = KA_CHANNEL_LFE, |
62 | [BIT_BACK_LEFT] = KA_CHANNEL_REAR_LEFT, |
63 | [BIT_BACK_RIGHT] = KA_CHANNEL_REAR_RIGHT, |
64 | [BIT_FRONT_LEFT_OF_CENTER] = KA_CHANNEL_FRONT_LEFT_OF_CENTER, |
65 | [BIT_FRONT_RIGHT_OF_CENTER] = KA_CHANNEL_FRONT_RIGHT_OF_CENTER, |
66 | [BIT_BACK_CENTER] = KA_CHANNEL_REAR_CENTER, |
67 | [BIT_SIDE_LEFT] = KA_CHANNEL_SIDE_LEFT, |
68 | [BIT_SIDE_RIGHT] = KA_CHANNEL_SIDE_RIGHT, |
69 | [BIT_TOP_CENTER] = KA_CHANNEL_TOP_CENTER, |
70 | [BIT_TOP_FRONT_LEFT] = KA_CHANNEL_TOP_FRONT_LEFT, |
71 | [BIT_TOP_FRONT_CENTER] = KA_CHANNEL_TOP_FRONT_CENTER, |
72 | [BIT_TOP_FRONT_RIGHT] = KA_CHANNEL_TOP_FRONT_RIGHT, |
73 | [BIT_TOP_BACK_LEFT] = KA_CHANNEL_TOP_REAR_LEFT, |
74 | [BIT_TOP_BACK_CENTER] = KA_CHANNEL_TOP_REAR_CENTER, |
75 | [BIT_TOP_BACK_RIGHT] = KA_CHANNEL_TOP_REAR_RIGHT |
76 | }; |
77 | |
78 | struct ka_wav { |
79 | FILE *file; |
80 | |
81 | off_t data_size; |
82 | unsigned nchannels; |
83 | unsigned rate; |
84 | unsigned depth; |
85 | uint32_t channel_mask; |
86 | |
87 | ka_channel_position_t channel_map[_BIT_MAX]; |
88 | }; |
89 | |
90 | #define CHUNK_ID_DATA0x61746164U 0x61746164U |
91 | #define CHUNK_ID_FMT0x20746d66U 0x20746d66U |
92 | |
93 | static const uint8_t pcm_guid[16] = { |
94 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, |
95 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 |
96 | }; |
97 | |
98 | static int skip_to_chunk(ka_wav *w, uint32_t id, uint32_t *size) { |
99 | |
100 | ka_return_val_if_fail(w, KA_ERROR_INVALID)do { if ((__builtin_expect((!(w)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "w" , "read-wav.c", 100, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
101 | ka_return_val_if_fail(size, KA_ERROR_INVALID)do { if ((__builtin_expect((!(size)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "size" , "read-wav.c", 101, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
102 | |
103 | for (;;) { |
104 | uint32_t chunk[2]; |
105 | uint32_t s; |
106 | |
107 | if (fread(chunk, sizeof(uint32_t), KA_ELEMENTSOF(chunk)(sizeof(chunk)/sizeof((chunk)[0])), w->file) != KA_ELEMENTSOF(chunk)(sizeof(chunk)/sizeof((chunk)[0]))) |
108 | goto fail_io; |
109 | |
110 | s = KA_UINT32_FROM_LE(chunk[1])((uint32_t)(chunk[1])); |
111 | |
112 | if (s <= 0 || s >= FILE_SIZE_MAX(64U*1024U*1024U)) |
113 | return KA_ERROR_TOOBIG; |
114 | |
115 | if (KA_UINT32_FROM_LE(chunk[0])((uint32_t)(chunk[0])) == id) { |
116 | *size = s; |
117 | break; |
118 | } |
119 | |
120 | if (fseek(w->file, (long) s, SEEK_CUR1) < 0) |
121 | return KA_ERROR_SYSTEM; |
122 | } |
123 | |
124 | return KA_SUCCESS; |
125 | |
126 | fail_io: |
127 | |
128 | if (feof(w->file)) |
129 | return KA_ERROR_CORRUPT; |
130 | else if (ferror(w->file)) |
131 | return KA_ERROR_SYSTEM; |
132 | |
133 | ka_assert_not_reached()do { fprintf(stderr, "Code should not be reached at %s:%u, function %s(). Aborting.\n" , "read-wav.c", 133, __PRETTY_FUNCTION__); abort(); } while ( (0)); |
134 | } |
135 | |
136 | int ka_wav_open(ka_wav **_w, FILE *f) { |
137 | uint32_t header[3], fmt_chunk[10]; |
138 | int ret; |
139 | ka_wav *w; |
140 | uint32_t file_size, fmt_size, data_size; |
141 | ka_bool_t extensible; |
142 | uint32_t format; |
143 | |
144 | ka_return_val_if_fail(_w, KA_ERROR_INVALID)do { if ((__builtin_expect((!(_w)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "_w" , "read-wav.c", 144, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
145 | ka_return_val_if_fail(f, KA_ERROR_INVALID)do { if ((__builtin_expect((!(f)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "f" , "read-wav.c", 145, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
146 | |
147 | if (!(w = ka_new(ka_wav, 1)((ka_wav*) malloc(sizeof(ka_wav)*(1))))) |
148 | return KA_ERROR_OOM; |
149 | |
150 | w->file = f; |
151 | |
152 | if (fread(header, sizeof(uint32_t), KA_ELEMENTSOF(header)(sizeof(header)/sizeof((header)[0])), f) != KA_ELEMENTSOF(header)(sizeof(header)/sizeof((header)[0]))) |
153 | goto fail_io; |
154 | |
155 | if (KA_UINT32_FROM_LE(header[0])((uint32_t)(header[0])) != 0x46464952U || |
156 | KA_UINT32_FROM_LE(header[2])((uint32_t)(header[2])) != 0x45564157U) { |
157 | ret = KA_ERROR_CORRUPT; |
158 | goto fail; |
159 | } |
160 | |
161 | file_size = KA_UINT32_FROM_LE(header[1])((uint32_t)(header[1])); |
162 | |
163 | if (file_size <= 0 || file_size >= FILE_SIZE_MAX(64U*1024U*1024U)) { |
164 | ret = KA_ERROR_TOOBIG; |
165 | goto fail; |
166 | } |
167 | |
168 | /* Skip to the fmt chunk */ |
169 | if ((ret = skip_to_chunk(w, CHUNK_ID_FMT0x20746d66U, &fmt_size)) < 0) |
170 | goto fail; |
171 | |
172 | switch (fmt_size) { |
173 | |
174 | case 14: /* WAVEFORMAT */ |
175 | case 16: |
176 | case 18: /* WAVEFORMATEX */ |
177 | extensible = FALSE(0); |
178 | break; |
179 | |
180 | case 40: /* WAVEFORMATEXTENSIBLE */ |
181 | extensible = TRUE(!(0)); |
182 | break; |
183 | |
184 | default: |
185 | ret = KA_ERROR_NOTSUPPORTED; |
186 | goto fail; |
187 | } |
188 | |
189 | if (fread(fmt_chunk, 1, fmt_size, f) != fmt_size) |
190 | goto fail_io; |
191 | |
192 | /* PCM? or WAVEX? */ |
193 | format = (KA_UINT32_FROM_LE(fmt_chunk[0])((uint32_t)(fmt_chunk[0])) & 0xFFFF); |
194 | if ((!extensible && format != 0x0001) || |
195 | (extensible && format != 0xFFFE)) { |
196 | ret = KA_ERROR_NOTSUPPORTED; |
197 | goto fail; |
198 | } |
199 | |
200 | if (extensible) { |
201 | if (memcmp(fmt_chunk + 6, pcm_guid, 16) != 0) { |
202 | ret = KA_ERROR_NOTSUPPORTED; |
203 | goto fail; |
204 | } |
205 | |
206 | w->channel_mask = KA_UINT32_FROM_LE(fmt_chunk[5])((uint32_t)(fmt_chunk[5])); |
207 | } else |
208 | w->channel_mask = 0; |
209 | |
210 | w->nchannels = KA_UINT32_FROM_LE(fmt_chunk[0])((uint32_t)(fmt_chunk[0])) >> 16; |
211 | w->rate = KA_UINT32_FROM_LE(fmt_chunk[1])((uint32_t)(fmt_chunk[1])); |
212 | w->depth = KA_UINT32_FROM_LE(fmt_chunk[3])((uint32_t)(fmt_chunk[3])) >> 16; |
213 | |
214 | if (w->nchannels <= 0 || w->rate <= 0) { |
215 | ret = KA_ERROR_CORRUPT; |
216 | goto fail; |
217 | } |
218 | |
219 | if (w->depth != 16 && w->depth != 8) { |
220 | ret = KA_ERROR_NOTSUPPORTED; |
221 | goto fail; |
222 | } |
223 | |
224 | /* Skip to the data chunk */ |
225 | if ((ret = skip_to_chunk(w, CHUNK_ID_DATA0x61746164U, &data_size)) < 0) |
226 | goto fail; |
227 | w->data_size = (off_t) data_size; |
228 | |
229 | if ((w->data_size % (w->depth/8)) != 0) { |
230 | ret = KA_ERROR_CORRUPT; |
231 | goto fail; |
232 | } |
233 | |
234 | *_w = w; |
235 | |
236 | return KA_SUCCESS; |
237 | |
238 | fail_io: |
239 | |
240 | if (feof(f)) |
241 | ret = KA_ERROR_CORRUPT; |
242 | else if (ferror(f)) |
243 | ret = KA_ERROR_SYSTEM; |
244 | else |
245 | ka_assert_not_reached()do { fprintf(stderr, "Code should not be reached at %s:%u, function %s(). Aborting.\n" , "read-wav.c", 245, __PRETTY_FUNCTION__); abort(); } while ( (0)); |
This statement is never executed | |
246 | |
247 | fail: |
248 | |
249 | ka_freefree(w); |
250 | |
251 | return ret; |
252 | } |
253 | |
254 | void ka_wav_close(ka_wav *w) { |
255 | ka_assert(w)do { if ((__builtin_expect((!(w)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "w" , "read-wav.c", 255, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
256 | |
257 | fclose(w->file); |
258 | ka_freefree(w); |
259 | } |
260 | |
261 | unsigned ka_wav_get_nchannels(ka_wav *w) { |
262 | ka_assert(w)do { if ((__builtin_expect((!(w)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "w" , "read-wav.c", 262, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
263 | |
264 | return w->nchannels; |
265 | } |
266 | |
267 | unsigned ka_wav_get_rate(ka_wav *w) { |
268 | ka_assert(w)do { if ((__builtin_expect((!(w)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "w" , "read-wav.c", 268, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
269 | |
270 | return w->rate; |
271 | } |
272 | |
273 | const ka_channel_position_t* ka_wav_get_channel_map(ka_wav *w) { |
274 | unsigned c; |
275 | ka_channel_position_t *p; |
276 | |
277 | ka_assert(w)do { if ((__builtin_expect((!(w)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "w" , "read-wav.c", 277, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
278 | |
279 | if (!w->channel_mask) |
280 | return NULL((void*)0); |
281 | |
282 | p = w->channel_map; |
283 | |
284 | for (c = 0; c < _BIT_MAX; c++) |
285 | if ((w->channel_mask & (1 << c))) |
286 | *(p++) = channel_table[c]; |
287 | |
288 | ka_assert(p <= w->channel_map + _BIT_MAX)do { if ((__builtin_expect((!(p <= w->channel_map + _BIT_MAX )),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "p <= w->channel_map + _BIT_MAX" , "read-wav.c", 288, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
289 | |
290 | if (p != w->channel_map + w->nchannels) |
291 | return NULL((void*)0); |
292 | |
293 | return w->channel_map; |
294 | } |
295 | |
296 | ka_sample_type_t ka_wav_get_sample_type(ka_wav *w) { |
297 | ka_assert(w)do { if ((__builtin_expect((!(w)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "w" , "read-wav.c", 297, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
298 | |
299 | return w->depth == 16 ? |
300 | #ifdef WORDS_BIGENDIAN |
301 | KA_SAMPLE_S16RE |
302 | #else |
303 | KA_SAMPLE_S16NE |
304 | #endif |
305 | : KA_SAMPLE_U8; |
306 | } |
307 | |
308 | int ka_wav_read_s16le(ka_wav *w, int16_t *d, size_t *n) { |
309 | off_t remaining; |
310 | |
311 | ka_return_val_if_fail(w, KA_ERROR_INVALID)do { if ((__builtin_expect((!(w)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "w" , "read-wav.c", 311, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
312 | ka_return_val_if_fail(w->depth == 16, KA_ERROR_INVALID)do { if ((__builtin_expect((!(w->depth == 16)),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "w->depth == 16" , "read-wav.c", 312, __PRETTY_FUNCTION__ ); return (KA_ERROR_INVALID); } } while((0)); |
313 | ka_return_val_if_fail(d, KA_ERROR_INVALID)do { if ((__builtin_expect((!(d)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "d" , "read-wav.c", 313, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
314 | ka_return_val_if_fail(n, KA_ERROR_INVALID)do { if ((__builtin_expect((!(n)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "n" , "read-wav.c", 314, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
315 | ka_return_val_if_fail(*n > 0, KA_ERROR_INVALID)do { if ((__builtin_expect((!(*n > 0)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "*n > 0" , "read-wav.c", 315, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID); } } while((0)); |
316 | |
317 | remaining = w->data_size / (off_t) sizeof(int16_t); |
318 | |
319 | if ((off_t) *n > remaining) |
320 | *n = (size_t) remaining; |
321 | |
322 | if (*n > 0) { |
323 | *n = fread(d, sizeof(int16_t), *n, w->file); |
324 | |
325 | if (*n <= 0 && ferror(w->file)) |
326 | return KA_ERROR_SYSTEM; |
327 | |
328 | ka_assert(w->data_size >= (off_t) *n * (off_t) sizeof(int16_t))do { if ((__builtin_expect((!(w->data_size >= (off_t) * n * (off_t) sizeof(int16_t))),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "w->data_size >= (off_t) *n * (off_t) sizeof(int16_t)" , "read-wav.c", 328, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
329 | w->data_size -= (off_t) *n * (off_t) sizeof(int16_t); |
330 | } |
331 | |
332 | return KA_SUCCESS; |
333 | } |
334 | |
335 | int ka_wav_read_u8(ka_wav *w, uint8_t *d, size_t *n) { |
336 | off_t remaining; |
337 | |
338 | ka_return_val_if_fail(w, KA_ERROR_INVALID)do { if ((__builtin_expect((!(w)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "w" , "read-wav.c", 338, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
339 | ka_return_val_if_fail(w->depth == 8, KA_ERROR_INVALID)do { if ((__builtin_expect((!(w->depth == 8)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "w->depth == 8" , "read-wav.c", 339, __PRETTY_FUNCTION__ ); return (KA_ERROR_INVALID); } } while((0)); |
340 | ka_return_val_if_fail(d, KA_ERROR_INVALID)do { if ((__builtin_expect((!(d)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "d" , "read-wav.c", 340, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
341 | ka_return_val_if_fail(n, KA_ERROR_INVALID)do { if ((__builtin_expect((!(n)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "n" , "read-wav.c", 341, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
342 | ka_return_val_if_fail(*n > 0, KA_ERROR_INVALID)do { if ((__builtin_expect((!(*n > 0)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "*n > 0" , "read-wav.c", 342, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID); } } while((0)); |
343 | |
344 | remaining = w->data_size / (off_t) sizeof(uint8_t); |
345 | |
346 | if ((off_t) *n > remaining) |
347 | *n = (size_t) remaining; |
348 | |
349 | if (*n > 0) { |
350 | *n = fread(d, sizeof(uint8_t), *n, w->file); |
351 | |
352 | if (*n <= 0 && ferror(w->file)) |
353 | return KA_ERROR_SYSTEM; |
354 | |
355 | ka_assert(w->data_size >= (off_t) *n * (off_t) sizeof(uint8_t))do { if ((__builtin_expect((!(w->data_size >= (off_t) * n * (off_t) sizeof(uint8_t))),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "w->data_size >= (off_t) *n * (off_t) sizeof(uint8_t)" , "read-wav.c", 355, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
356 | w->data_size -= (off_t) *n * (off_t) sizeof(uint8_t); |
357 | } |
358 | |
359 | return KA_SUCCESS; |
360 | } |
361 | |
362 | off_t ka_wav_get_size(ka_wav *v) { |
363 | ka_return_val_if_fail(v, (off_t) -1)do { if ((__builtin_expect((!(v)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "v" , "read-wav.c", 363, __PRETTY_FUNCTION__); return ((off_t) - 1); } } while((0)); |
364 | |
365 | return v->data_size; |
366 | } |