xref: /openbsd/usr.bin/aucat/afile.c (revision b4d5e3c9)
1 /*
2  * Copyright (c) 2008-2014 Alexandre Ratchov <alex@caoua.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <fcntl.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include "afile.h"
21 #include "utils.h"
22 
23 typedef struct {
24 	unsigned char ld[4];
25 } le32_t;
26 
27 typedef struct {
28 	unsigned char lw[2];
29 } le16_t;
30 
31 typedef struct {
32 	unsigned char bd[4];
33 } be32_t;
34 
35 typedef struct {
36 	unsigned char bw[2];
37 } be16_t;
38 
39 struct wav_riff {
40 	char id[4];
41 	le32_t size;
42 	char type[4];
43 };
44 
45 struct wav_chunk {
46 	char id[4];
47 	le32_t size;
48 };
49 
50 struct wav_fmt {
51 #define WAV_FMT_PCM	1
52 #define WAV_FMT_FLOAT	3
53 #define WAV_FMT_ALAW	6
54 #define WAV_FMT_ULAW	7
55 #define WAV_FMT_EXT	0xfffe
56 	le16_t fmt;
57 	le16_t nch;
58 	le32_t rate;
59 	le32_t byterate;
60 	le16_t blkalign;
61 	le16_t bits;
62 #define WAV_FMT_SIZE		 16
63 #define WAV_FMT_EXT_SIZE	(16 + 24)
64 	le16_t extsize;
65 	le16_t valbits;
66 	le32_t chanmask;
67 	le16_t extfmt;
68 	char guid[14];
69 };
70 
71 struct wav_hdr {
72 	struct wav_riff riff;		/* 00..11 */
73 	struct wav_chunk fmt_hdr;	/* 12..20 */
74 	struct wav_fmt fmt;
75 	struct wav_chunk data_hdr;
76 };
77 
78 struct aiff_form {
79 	char id[4];
80 	be32_t size;
81 	char type[4];
82 };
83 
84 struct aiff_chunk {
85 	char id[4];
86 	be32_t size;
87 };
88 
89 struct aiff_comm {
90 	struct aiff_commbase {
91 		be16_t nch;
92 		be32_t nfr;
93 		be16_t bits;
94 		/* rate in 80-bit floating point */
95 		be16_t rate_ex;
96 		be32_t rate_hi;
97 		be32_t rate_lo;
98 	} base;
99 	char comp_id[4];
100 	/* followed by stuff we don't care about */
101 };
102 
103 struct aiff_data {
104 	be32_t offs;
105 	be32_t blksz;
106 };
107 
108 struct aiff_hdr {
109 	struct aiff_form form;
110 	struct aiff_chunk comm_hdr;
111 	struct aiff_commbase comm;
112 	struct aiff_chunk data_hdr;
113 	struct aiff_data data;
114 };
115 
116 struct au_hdr {
117 	char id[4];
118 	be32_t offs;
119 	be32_t size;
120 #define AU_FMT_PCM8	2
121 #define AU_FMT_PCM16	3
122 #define AU_FMT_PCM24	4
123 #define AU_FMT_PCM32	5
124 #define AU_FMT_FLOAT	6
125 #define AU_FMT_ALAW	0x1b
126 #define AU_FMT_ULAW	1
127 	be32_t fmt;
128 	be32_t rate;
129 	be32_t nch;
130 	char desc[8];
131 	/* followed by optional desc[] continuation */
132 };
133 
134 const char wav_id_riff[4] = {'R', 'I', 'F', 'F'};
135 const char wav_id_wave[4] = {'W', 'A', 'V', 'E'};
136 const char wav_id_data[4] = {'d', 'a', 't', 'a'};
137 const char wav_id_fmt[4] = {'f', 'm', 't', ' '};
138 const char wav_guid[14] = {
139 	0x00, 0x00, 0x00, 0x00,
140 	0x10, 0x00, 0x80, 0x00,
141 	0x00, 0xAA, 0x00, 0x38,
142 	0x9B, 0x71
143 };
144 
145 const char aiff_id_form[4] = {'F', 'O', 'R', 'M'};
146 const char aiff_id_aiff[4] = {'A', 'I', 'F', 'F'};
147 const char aiff_id_aifc[4] = {'A', 'I', 'F', 'C'};
148 const char aiff_id_data[4] = {'S', 'S', 'N', 'D'};
149 const char aiff_id_comm[4] = {'C', 'O', 'M', 'M'};
150 const char aiff_id_none[4] = {'N', 'O', 'N', 'E'};
151 const char aiff_id_fl32[4] = {'f', 'l', '3', '2'};
152 const char aiff_id_ulaw[4] = {'u', 'l', 'a', 'w'};
153 const char aiff_id_alaw[4] = {'a', 'l', 'a', 'w'};
154 
155 const char au_id[4] = {'.', 's', 'n', 'd'};
156 
157 static inline unsigned int
le16_get(le16_t * p)158 le16_get(le16_t *p)
159 {
160 	return p->lw[0] | p->lw[1] << 8;
161 }
162 
163 static inline void
le16_set(le16_t * p,unsigned int v)164 le16_set(le16_t *p, unsigned int v)
165 {
166 	p->lw[0] = v;
167 	p->lw[1] = v >> 8;
168 }
169 
170 static inline unsigned int
le32_get(le32_t * p)171 le32_get(le32_t *p)
172 {
173 	return p->ld[0] |
174 	       p->ld[1] << 8 |
175 	       p->ld[2] << 16 |
176 	       p->ld[3] << 24;
177 }
178 
179 static inline void
le32_set(le32_t * p,unsigned int v)180 le32_set(le32_t *p, unsigned int v)
181 {
182 	p->ld[0] = v;
183 	p->ld[1] = v >> 8;
184 	p->ld[2] = v >> 16;
185 	p->ld[3] = v >> 24;
186 }
187 
188 static inline unsigned int
be16_get(be16_t * p)189 be16_get(be16_t *p)
190 {
191 	return p->bw[1] | p->bw[0] << 8;
192 }
193 
194 static inline void
be16_set(be16_t * p,unsigned int v)195 be16_set(be16_t *p, unsigned int v)
196 {
197 	p->bw[1] = v;
198 	p->bw[0] = v >> 8;
199 }
200 
201 static inline unsigned int
be32_get(be32_t * p)202 be32_get(be32_t *p)
203 {
204 	return p->bd[3] |
205 	       p->bd[2] << 8 |
206 	       p->bd[1] << 16 |
207 	       p->bd[0] << 24;
208 }
209 
210 static inline void
be32_set(be32_t * p,unsigned int v)211 be32_set(be32_t *p, unsigned int v)
212 {
213 	p->bd[3] = v;
214 	p->bd[2] = v >> 8;
215 	p->bd[1] = v >> 16;
216 	p->bd[0] = v >> 24;
217 }
218 
219 static int
afile_readhdr(struct afile * f,void * addr,size_t size)220 afile_readhdr(struct afile *f, void *addr, size_t size)
221 {
222 	if (lseek(f->fd, 0, SEEK_SET) == -1) {
223 		logx(1, "%s: failed to seek to beginning of file", f->path);
224 		return 0;
225 	}
226 	if (read(f->fd, addr, size) != size) {
227 		logx(1, "%s: failed to read header", f->path);
228 		return 0;
229 	}
230 	return 1;
231 }
232 
233 static int
afile_writehdr(struct afile * f,void * addr,size_t size)234 afile_writehdr(struct afile *f, void *addr, size_t size)
235 {
236 	if (lseek(f->fd, 0, SEEK_SET) == -1) {
237 		logx(1, "%s: failed to seek back to header", f->path);
238 		return 0;
239 	}
240 	if (write(f->fd, addr, size) != size) {
241 		logx(1, "%s: failed to write header", f->path);
242 		return 0;
243 	}
244 	f->curpos = f->startpos;
245 	return 1;
246 }
247 
248 static int
afile_checkpar(struct afile * f)249 afile_checkpar(struct afile *f)
250 {
251 	if (f->nch == 0 || f->nch > NCHAN_MAX) {
252 		logx(1, "%s: %u: unsupported number of channels", f->path, f->nch);
253 		return 0;
254 	}
255 	if (f->rate < RATE_MIN || f->rate > RATE_MAX) {
256 		logx(1, "%s: %u: unsupported rate", f->path, f->rate);
257 		return 0;
258 	}
259 	if (f->par.bits < BITS_MIN || f->par.bits > BITS_MAX) {
260 		logx(1, "%s: %u: unsupported bits per sample", f->path, f->par.bits);
261 		return 0;
262 	}
263 	if (f->par.bits > f->par.bps * 8) {
264 		logx(1, "%s: bits larger than bytes-per-sample", f->path);
265 		return 0;
266 	}
267 	if (f->fmt == AFILE_FMT_FLOAT && f->par.bits != 32) {
268 		logx(1, "%s: only 32-bit floating points are supported", f->path);
269 		return 0;
270 	}
271 	return 1;
272 }
273 
274 static int
afile_wav_readfmt(struct afile * f,unsigned int csize)275 afile_wav_readfmt(struct afile *f, unsigned int csize)
276 {
277 	struct wav_fmt fmt;
278 	unsigned int wenc;
279 
280 	if (csize < WAV_FMT_SIZE) {
281 		logx(1, "%s: %u: bogus format chunk size", f->path, csize);
282 		return 0;
283 	}
284 	if (csize > WAV_FMT_EXT_SIZE)
285 		csize = WAV_FMT_EXT_SIZE;
286 	if (read(f->fd, &fmt, csize) != csize) {
287 		logx(1, "%s: failed to read format chunk", f->path);
288 		return 0;
289 	}
290 	wenc = le16_get(&fmt.fmt);
291 	f->par.bits = le16_get(&fmt.bits);
292 	if (wenc == WAV_FMT_EXT) {
293 		if (csize != WAV_FMT_EXT_SIZE) {
294 			logx(1, "%s: missing extended format chunk", f->path);
295 			return 0;
296 		}
297 		if (memcmp(fmt.guid, wav_guid, sizeof(wav_guid)) != 0) {
298 			logx(1, "%s: unknown format (GUID)", f->path);
299 			return 0;
300 		}
301 		f->par.bps = (f->par.bits + 7) / 8;
302 		f->par.bits = le16_get(&fmt.valbits);
303 		wenc = le16_get(&fmt.extfmt);
304 	} else
305 		f->par.bps = (f->par.bits + 7) / 8;
306 	f->nch = le16_get(&fmt.nch);
307 	f->rate = le32_get(&fmt.rate);
308 	f->par.le = 1;
309 	f->par.msb = 1;
310 	switch (wenc) {
311 	case WAV_FMT_PCM:
312 		f->fmt = AFILE_FMT_PCM;
313 		f->par.sig = (f->par.bits <= 8) ? 0 : 1;
314 		break;
315 	case WAV_FMT_ALAW:
316 		f->fmt = AFILE_FMT_ALAW;
317 		f->par.bits = 8;
318 		f->par.bps = 1;
319 		break;
320 	case WAV_FMT_ULAW:
321 		f->fmt = AFILE_FMT_ULAW;
322 		f->par.bits = 8;
323 		f->par.bps = 1;
324 		break;
325 	case WAV_FMT_FLOAT:
326 		f->fmt = AFILE_FMT_FLOAT;
327 		break;
328 	default:
329 		logx(1, "%s: %u: unsupported encoding", f->path, wenc);
330 		return 0;
331 	}
332 	return afile_checkpar(f);
333 }
334 
335 static int
afile_wav_readhdr(struct afile * f)336 afile_wav_readhdr(struct afile *f)
337 {
338 	struct wav_riff riff;
339 	struct wav_chunk chunk;
340 	unsigned int csize, rsize, pos = 0;
341 	int fmt_done = 0;
342 
343 	if (!afile_readhdr(f, &riff, sizeof(struct wav_riff)))
344 		return 0;
345 	if (memcmp(&riff.id, &wav_id_riff, 4) != 0 ||
346 	    memcmp(&riff.type, &wav_id_wave, 4) != 0) {
347 		logx(1, "%s: not a .wav file", f->path);
348 		return 0;
349 	}
350 	rsize = le32_get(&riff.size);
351 	for (;;) {
352 		if (pos + sizeof(struct wav_chunk) > rsize) {
353 			logx(1, "%s: missing data chunk", f->path);
354 			return 0;
355 		}
356 		if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
357 			logx(1, "%s: failed to read chunk header", f->path);
358 			return 0;
359 		}
360 		csize = le32_get(&chunk.size);
361 		if (memcmp(chunk.id, wav_id_fmt, 4) == 0) {
362 			if (!afile_wav_readfmt(f, csize))
363 				return 0;
364 			fmt_done = 1;
365 		} else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
366 			f->startpos = pos + sizeof(riff) + sizeof(chunk);
367 			f->endpos = f->startpos + csize;
368 			break;
369 		} else {
370 #ifdef DEBUG
371 			if (log_level >= 2) {
372 				logx(1, "%s: skipped unknown chunk", f->path);
373 			}
374 #endif
375 		}
376 
377 		/*
378 		 * next chunk
379 		 */
380 		pos += sizeof(struct wav_chunk) + csize;
381 		if (lseek(f->fd, sizeof(riff) + pos, SEEK_SET) == -1) {
382 			logx(1, "%s: failed to seek to chunk", f->path);
383 			return 0;
384 		}
385 	}
386 	if (!fmt_done) {
387 		logx(1, "%s: missing format chunk", f->path);
388 		return 0;
389 	}
390 	return 1;
391 }
392 
393 /*
394  * Write header and seek to start position
395  */
396 static int
afile_wav_writehdr(struct afile * f)397 afile_wav_writehdr(struct afile *f)
398 {
399 	struct wav_hdr hdr;
400 
401 	memset(&hdr, 0, sizeof(struct wav_hdr));
402 	memcpy(hdr.riff.id, wav_id_riff, 4);
403 	memcpy(hdr.riff.type, wav_id_wave, 4);
404 	le32_set(&hdr.riff.size, f->endpos - sizeof(hdr.riff));
405 	memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4);
406 	le32_set(&hdr.fmt_hdr.size, sizeof(hdr.fmt));
407 	le16_set(&hdr.fmt.fmt, WAV_FMT_EXT);
408 	le16_set(&hdr.fmt.nch, f->nch);
409 	le32_set(&hdr.fmt.rate, f->rate);
410 	le32_set(&hdr.fmt.byterate, f->rate * f->par.bps * f->nch);
411 	le16_set(&hdr.fmt.blkalign, f->par.bps * f->nch);
412 	le16_set(&hdr.fmt.bits, f->par.bits);
413 	le16_set(&hdr.fmt.extsize,
414 	    WAV_FMT_EXT_SIZE - WAV_FMT_SIZE - sizeof(hdr.fmt.extsize));
415 	le16_set(&hdr.fmt.valbits, f->par.bits);
416 	le16_set(&hdr.fmt.extfmt, 1);
417 	memcpy(&hdr.fmt.guid, wav_guid, sizeof(hdr.fmt.guid));
418 	memcpy(hdr.data_hdr.id, wav_id_data, 4);
419 	le32_set(&hdr.data_hdr.size, f->endpos - f->startpos);
420 	return afile_writehdr(f, &hdr, sizeof(struct wav_hdr));
421 }
422 
423 static int
afile_aiff_readcomm(struct afile * f,unsigned int csize,int comp,unsigned int * nfr)424 afile_aiff_readcomm(struct afile *f, unsigned int csize,
425     int comp, unsigned int *nfr)
426 {
427 	struct aiff_comm comm;
428 	unsigned int csize_min;
429 	unsigned int e, m;
430 
431 	csize_min = comp ?
432 	    sizeof(struct aiff_comm) : sizeof(struct aiff_commbase);
433 	if (csize < csize_min) {
434 		logx(1, "%s: %u: bogus comm chunk size", f->path, csize);
435 		return 0;
436 	}
437 	if (read(f->fd, &comm, csize_min) != csize_min) {
438 		logx(1, "%s: failed to read comm chunk", f->path);
439 		return 0;
440 	}
441 	f->nch = be16_get(&comm.base.nch);
442 	e = be16_get(&comm.base.rate_ex);
443 	m = be32_get(&comm.base.rate_hi);
444 	if (e < 0x3fff || e > 0x3fff + 31) {
445 		logx(1, "%s: malformed sample rate", f->path);
446 		return 0;
447 	}
448 	f->rate = m >> (0x3fff + 31 - e);
449 	if (comp) {
450 		if (memcmp(comm.comp_id, aiff_id_none, 4) == 0) {
451 			f->fmt = AFILE_FMT_PCM;
452 			f->par.bits = be16_get(&comm.base.bits);
453 		} else if (memcmp(comm.comp_id, aiff_id_fl32, 4) == 0) {
454 			f->fmt = AFILE_FMT_FLOAT;
455 			f->par.bits = 32;
456 		} else if (memcmp(comm.comp_id, aiff_id_ulaw, 4) == 0) {
457 			f->fmt = AFILE_FMT_ULAW;
458 			f->par.bits = 8;
459 		} else if (memcmp(comm.comp_id, aiff_id_alaw, 4) == 0) {
460 			f->fmt = AFILE_FMT_ALAW;
461 			f->par.bits = 8;
462 		} else {
463 			logx(1, "%s: unsupported encoding", f->path);
464 			return 0;
465 		}
466 	} else {
467 		f->fmt = AFILE_FMT_PCM;
468 		f->par.bits = be16_get(&comm.base.bits);
469 	}
470 	f->par.le = 0;
471 	f->par.sig = 1;
472 	f->par.msb = 1;
473 	f->par.bps = (f->par.bits + 7) / 8;
474 	*nfr = be32_get(&comm.base.nfr);
475 	return afile_checkpar(f);
476 }
477 
478 static int
afile_aiff_readdata(struct afile * f,unsigned int csize,unsigned int * roffs)479 afile_aiff_readdata(struct afile *f, unsigned int csize, unsigned int *roffs)
480 {
481 	struct aiff_data data;
482 
483 	if (csize < sizeof(struct aiff_data)) {
484 		logx(1, "%s: %u: bogus data chunk size", f->path, csize);
485 		return 0;
486 	}
487 	csize = sizeof(struct aiff_data);
488 	if (read(f->fd, &data, csize) != csize) {
489 		logx(1, "%s: failed to read data chunk", f->path);
490 		return 0;
491 	}
492 	*roffs = csize + be32_get(&data.offs);
493 	return 1;
494 }
495 
496 static int
afile_aiff_readhdr(struct afile * f)497 afile_aiff_readhdr(struct afile *f)
498 {
499 	struct aiff_form form;
500 	struct aiff_chunk chunk;
501 	unsigned int csize, rsize, nfr = 0, pos = 0, offs;
502 	int comm_done = 0, comp;
503 
504 	if (!afile_readhdr(f, &form, sizeof(struct aiff_form)))
505 		return 0;
506 	if (memcmp(&form.id, &aiff_id_form, 4) != 0) {
507 		logx(1, "%s: not an aiff file", f->path);
508 		return 0;
509 	}
510 	if (memcmp(&form.type, &aiff_id_aiff, 4) == 0) {
511 		comp = 0;
512 	} else if (memcmp(&form.type, &aiff_id_aifc, 4) == 0)
513 		comp = 1;
514 	else {
515 		logx(1, "%s: unsupported aiff file sub-type", f->path);
516 		return 0;
517 	}
518 	rsize = be32_get(&form.size);
519 	for (;;) {
520 		if (pos + sizeof(struct aiff_chunk) > rsize) {
521 			logx(1, "%s: missing data chunk", f->path);
522 			return 0;
523 		}
524 		if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
525 			logx(1, "%s: failed to read chunk header", f->path);
526 			return 0;
527 		}
528 		csize = be32_get(&chunk.size);
529 		if (memcmp(chunk.id, aiff_id_comm, 4) == 0) {
530 			if (!afile_aiff_readcomm(f, csize, comp, &nfr))
531 				return 0;
532 			comm_done = 1;
533 		} else if (memcmp(chunk.id, aiff_id_data, 4) == 0) {
534 			if (!afile_aiff_readdata(f, csize, &offs))
535 				return 0;
536 			f->startpos = sizeof(form) + pos +
537 			    sizeof(chunk) + offs;
538 			break;
539 		} else {
540 #ifdef DEBUG
541 			logx(2, "%s: skipped unknown chunk", f->path);
542 #endif
543 		}
544 
545 		/*
546 		 * The aiff spec says "Each Chunk must contain an even
547 		 * number of bytes. For those Chunks whose total
548 		 * contents would yield an odd number of bytes, a zero
549 		 * pad byte must be added at the end of the Chunk. This
550 		 * pad byte is not included in ckDataSize, which
551 		 * indicates the size of the data in the Chunk."
552 		 */
553 		csize = (csize + 1) & ~1;
554 		pos += sizeof(struct aiff_chunk) + csize;
555 
556 		if (lseek(f->fd, sizeof(form) + pos, SEEK_SET) == -1) {
557 			logx(1, "%s: failed to seek to chunk", f->path);
558 			return 0;
559 		}
560 	}
561 	if (!comm_done) {
562 		logx(1, "%s: missing comm chunk", f->path);
563 		return 0;
564 	}
565 	f->endpos = f->startpos + f->par.bps * f->nch * nfr;
566 	return 1;
567 }
568 
569 /*
570  * Write header and seek to start position
571  */
572 static int
afile_aiff_writehdr(struct afile * f)573 afile_aiff_writehdr(struct afile *f)
574 {
575 	struct aiff_hdr hdr;
576 	unsigned int bpf;
577 	unsigned int e, m;
578 
579 	/* convert rate to 80-bit float (exponent and fraction part) */
580 	m = f->rate;
581 	e = 0x3fff + 31;
582 	while ((m & 0x80000000) == 0) {
583 		e--;
584 		m <<= 1;
585 	}
586 
587 	/* bytes per frame */
588 	bpf = f->nch * f->par.bps;
589 
590 	memset(&hdr, 0, sizeof(struct aiff_hdr));
591 	memcpy(hdr.form.id, aiff_id_form, 4);
592 	memcpy(hdr.form.type, aiff_id_aiff, 4);
593 	be32_set(&hdr.form.size, f->endpos - sizeof(hdr.form));
594 
595 	memcpy(hdr.comm_hdr.id, aiff_id_comm, 4);
596 	be32_set(&hdr.comm_hdr.size, sizeof(hdr.comm));
597 	be16_set(&hdr.comm.nch, f->nch);
598 	be16_set(&hdr.comm.bits, f->par.bits);
599 	be16_set(&hdr.comm.rate_ex, e);
600 	be32_set(&hdr.comm.rate_hi, m);
601 	be32_set(&hdr.comm.rate_lo, 0);
602 	be32_set(&hdr.comm.nfr, (f->endpos - f->startpos) / bpf);
603 
604 	memcpy(hdr.data_hdr.id, aiff_id_data, 4);
605 	be32_set(&hdr.data_hdr.size, f->endpos - f->startpos);
606 	be32_set(&hdr.data.offs, 0);
607 	be32_set(&hdr.data.blksz, 0);
608 	return afile_writehdr(f, &hdr, sizeof(struct aiff_hdr));
609 }
610 
611 static int
afile_au_readhdr(struct afile * f)612 afile_au_readhdr(struct afile *f)
613 {
614 	struct au_hdr hdr;
615 	unsigned int fmt;
616 
617 	if (!afile_readhdr(f, &hdr, sizeof(struct au_hdr)))
618 		return 0;
619 	if (memcmp(&hdr.id, &au_id, 4) != 0) {
620 		logx(1, "%s: not a .au file", f->path);
621 		return 0;
622 	}
623 	f->startpos = be32_get(&hdr.offs);
624 	f->endpos = f->startpos + be32_get(&hdr.size);
625 	fmt = be32_get(&hdr.fmt);
626 	switch (fmt) {
627 	case AU_FMT_PCM8:
628 		f->fmt = AFILE_FMT_PCM;
629 		f->par.bits = 8;
630 		break;
631 	case AU_FMT_PCM16:
632 		f->fmt = AFILE_FMT_PCM;
633 		f->par.bits = 16;
634 		break;
635 	case AU_FMT_PCM24:
636 		f->fmt = AFILE_FMT_PCM;
637 		f->par.bits = 24;
638 		break;
639 	case AU_FMT_PCM32:
640 		f->fmt = AFILE_FMT_PCM;
641 		f->par.bits = 32;
642 		break;
643 	case AU_FMT_ULAW:
644 		f->fmt = AFILE_FMT_ULAW;
645 		f->par.bits = 8;
646 		break;
647 	case AU_FMT_ALAW:
648 		f->fmt = AFILE_FMT_ALAW;
649 		f->par.bits = 8;
650 		break;
651 	case AU_FMT_FLOAT:
652 		f->fmt = AFILE_FMT_FLOAT;
653 		f->par.bits = 32;
654 		break;
655 	default:
656 		logx(1, "%s: %u: unsupported encoding", f->path, fmt);
657 		return 0;
658 	}
659 	f->par.le = 0;
660 	f->par.sig = 1;
661 	f->par.bps = f->par.bits / 8;
662 	f->par.msb = 0;
663 	f->rate = be32_get(&hdr.rate);
664 	f->nch = be32_get(&hdr.nch);
665 	if (lseek(f->fd, f->startpos, SEEK_SET) == -1) {
666 		logx(1, "%s: failed to seek to data chunk", f->path);
667 		return 0;
668 	}
669 	return afile_checkpar(f);
670 }
671 
672 /*
673  * Write header and seek to start position
674  */
675 static int
afile_au_writehdr(struct afile * f)676 afile_au_writehdr(struct afile *f)
677 {
678 	struct au_hdr hdr;
679 	unsigned int fmt;
680 
681 	memset(&hdr, 0, sizeof(struct au_hdr));
682 	memcpy(hdr.id, au_id, 4);
683 	be32_set(&hdr.offs, f->startpos);
684 	be32_set(&hdr.size, f->endpos - f->startpos);
685 	switch (f->par.bits) {
686 	case 8:
687 		fmt = AU_FMT_PCM8;
688 		break;
689 	case 16:
690 		fmt = AU_FMT_PCM16;
691 		break;
692 	case 24:
693 		fmt = AU_FMT_PCM24;
694 		break;
695 	case 32:
696 		fmt = AU_FMT_PCM32;
697 		break;
698 #ifdef DEBUG
699 	default:
700 		logx(1, "%s: %u: wrong precision", f->path, f->par.bits);
701 		panic();
702 		return 0;
703 #endif
704 	}
705 	be32_set(&hdr.fmt, fmt);
706 	be32_set(&hdr.rate, f->rate);
707 	be32_set(&hdr.nch, f->nch);
708 	return afile_writehdr(f, &hdr, sizeof(struct au_hdr));
709 }
710 
711 size_t
afile_read(struct afile * f,void * data,size_t count)712 afile_read(struct afile *f, void *data, size_t count)
713 {
714 	off_t maxread;
715 	ssize_t n;
716 
717 	if (f->endpos >= 0) {
718 		maxread = f->endpos - f->curpos;
719 		if (maxread == 0) {
720 #ifdef DEBUG
721 			logx(3, "%s: end reached", f->path);
722 #endif
723 			return 0;
724 		}
725 		if (count > maxread)
726 			count = maxread;
727 	}
728 	n = read(f->fd, data, count);
729 	if (n == -1) {
730 		logx(1, "%s: couldn't read", f->path);
731 		return 0;
732 	}
733 	f->curpos += n;
734 	return n;
735 }
736 
737 size_t
afile_write(struct afile * f,void * data,size_t count)738 afile_write(struct afile *f, void *data, size_t count)
739 {
740 	off_t maxwrite;
741 	int n;
742 
743 	if (f->maxpos >= 0) {
744 		maxwrite = f->maxpos - f->curpos;
745 		if (maxwrite == 0) {
746 #ifdef DEBUG
747 			logx(3, "%s: max file size reached", f->path);
748 #endif
749 			return 0;
750 		}
751 		if (count > maxwrite)
752 			count = maxwrite;
753 	}
754 	n = write(f->fd, data, count);
755 	if (n == -1) {
756 		logx(1, "%s: couldn't write", f->path);
757 		return 0;
758 	}
759 	f->curpos += n;
760 	if (f->endpos < f->curpos)
761 		f->endpos = f->curpos;
762 	return n;
763 }
764 
765 int
afile_seek(struct afile * f,off_t pos)766 afile_seek(struct afile *f, off_t pos)
767 {
768 	pos += f->startpos;
769 	if (f->endpos >= 0 && pos > f->endpos && !f->par.sig) {
770 		logx(1, "%s: attempt to seek outside file boundaries", f->path);
771 		return 0;
772 	}
773 
774 	/*
775 	 * seek only if needed to avoid errors with pipes & sockets
776 	 */
777 	if (pos != f->curpos) {
778 		if (lseek(f->fd, pos, SEEK_SET) == -1) {
779 			logx(1, "%s: couldn't seek", f->path);
780 			return 0;
781 		}
782 		f->curpos = pos;
783 	}
784 	return 1;
785 }
786 
787 void
afile_close(struct afile * f)788 afile_close(struct afile *f)
789 {
790 	if (f->flags & AFILE_FWRITE) {
791 		if (f->hdr == AFILE_HDR_WAV)
792 			afile_wav_writehdr(f);
793 		else if (f->hdr == AFILE_HDR_AIFF)
794 			afile_aiff_writehdr(f);
795 		else if (f->hdr == AFILE_HDR_AU)
796 			afile_au_writehdr(f);
797 	}
798 	close(f->fd);
799 }
800 
801 int
afile_open(struct afile * f,char * path,int hdr,int flags,struct aparams * par,int rate,int nch)802 afile_open(struct afile *f, char *path, int hdr, int flags,
803     struct aparams *par, int rate, int nch)
804 {
805 	char *ext;
806 	static union {
807 		struct wav_hdr wav;
808 		struct aiff_hdr aiff;
809 		struct au_hdr au;
810 	} dummy;
811 
812 	f->par = *par;
813 	f->rate = rate;
814 	f->nch = nch;
815 	f->flags = flags;
816 	f->hdr = hdr;
817 	if (hdr == AFILE_HDR_AUTO) {
818 		f->hdr = AFILE_HDR_RAW;
819 		ext = strrchr(path, '.');
820 		if (ext != NULL) {
821 			ext++;
822 			if (strcasecmp(ext, "aif") == 0 ||
823 			    strcasecmp(ext, "aiff") == 0 ||
824 			    strcasecmp(ext, "aifc") == 0)
825 				f->hdr = AFILE_HDR_AIFF;
826 			else if (strcasecmp(ext, "au") == 0 ||
827 			    strcasecmp(ext, "snd") == 0)
828 				f->hdr = AFILE_HDR_AU;
829 			else if (strcasecmp(ext, "wav") == 0)
830 				f->hdr = AFILE_HDR_WAV;
831 		}
832 	}
833 	if (f->flags == AFILE_FREAD) {
834 		if (strcmp(path, "-") == 0) {
835 			f->path = "stdin";
836 			f->fd = STDIN_FILENO;
837 		} else {
838 			f->path = path;
839 			f->fd = open(f->path, O_RDONLY);
840 			if (f->fd == -1) {
841 				logx(1, "%s: failed to open for reading", f->path);
842 				return 0;
843 			}
844 		}
845 		if (f->hdr == AFILE_HDR_WAV) {
846 			if (!afile_wav_readhdr(f))
847 				goto bad_close;
848 		} else if (f->hdr == AFILE_HDR_AIFF) {
849 			if (!afile_aiff_readhdr(f))
850 				goto bad_close;
851 		} else if (f->hdr == AFILE_HDR_AU) {
852 			if (!afile_au_readhdr(f))
853 				goto bad_close;
854 		} else {
855 			f->startpos = 0;
856 			f->endpos = -1; /* read until EOF */
857 			f->fmt = AFILE_FMT_PCM;
858 		}
859 		f->curpos = f->startpos;
860 	} else if (flags == AFILE_FWRITE) {
861 		if (strcmp(path, "-") == 0) {
862 			f->path = "stdout";
863 			f->fd = STDOUT_FILENO;
864 		} else {
865 			f->path = path;
866 			f->fd = open(f->path,
867 			    O_WRONLY | O_TRUNC | O_CREAT, 0666);
868 			if (f->fd == -1) {
869 				logx(1, "%s: failed to create file", f->path);
870 				return 0;
871 			}
872 		}
873 		if (f->hdr == AFILE_HDR_WAV) {
874 			f->par.bps = (f->par.bits + 7) >> 3;
875 			if (f->par.bits > 8) {
876 				f->par.le = 1;
877 				f->par.sig = 1;
878 			} else
879 				f->par.sig = 0;
880 			if (f->par.bits & 7)
881 				f->par.msb = 1;
882 			f->endpos = f->startpos = sizeof(struct wav_hdr);
883 			f->maxpos = 0x7fffffff;
884 			if (!afile_writehdr(f, &dummy, sizeof(struct wav_hdr)))
885 				goto bad_close;
886 		} else if (f->hdr == AFILE_HDR_AIFF) {
887 			f->par.bps = (f->par.bits + 7) >> 3;
888 			if (f->par.bps > 1)
889 				f->par.le = 0;
890 			f->par.sig = 1;
891 			if (f->par.bits & 7)
892 				f->par.msb = 1;
893 			f->endpos = f->startpos = sizeof(struct aiff_hdr);
894 			f->maxpos = 0x7fffffff;
895 			if (!afile_writehdr(f, &dummy,
896 				sizeof(struct aiff_hdr)))
897 				goto bad_close;
898 		} else if (f->hdr == AFILE_HDR_AU) {
899 			f->par.bits = (f->par.bits + 7) & ~7;
900 			f->par.bps = f->par.bits / 8;
901 			f->par.le = 0;
902 			f->par.sig = 1;
903 			f->par.msb = 1;
904 			f->endpos = f->startpos = sizeof(struct au_hdr);
905 			f->maxpos = 0x7fffffff;
906 			if (!afile_writehdr(f, &dummy, sizeof(struct au_hdr)))
907 				goto bad_close;
908 		} else {
909 			f->endpos = f->startpos = 0;
910 			f->maxpos = -1;
911 		}
912 		f->curpos = f->startpos;
913 	} else {
914 #ifdef DEBUG
915 		logx(1, "afile_open: 0x%x: wrong flags", flags);
916 		panic();
917 #endif
918 	}
919 	return 1;
920 bad_close:
921 	close(f->fd);
922 	return 0;
923 }
924