GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/aucat/afile.c Lines: 0 512 0.0 %
Date: 2017-11-07 Branches: 0 232 0.0 %

Line Branch Exec Source
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
char wav_id_riff[4] = {'R', 'I', 'F', 'F'};
135
char wav_id_wave[4] = {'W', 'A', 'V', 'E'};
136
char wav_id_data[4] = {'d', 'a', 't', 'a'};
137
char wav_id_fmt[4] = {'f', 'm', 't', ' '};
138
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
char aiff_id_form[4] = {'F', 'O', 'R', 'M'};
146
char aiff_id_aiff[4] = {'A', 'I', 'F', 'F'};
147
char aiff_id_aifc[4] = {'A', 'I', 'F', 'C'};
148
char aiff_id_data[4] = {'S', 'S', 'N', 'D'};
149
char aiff_id_comm[4] = {'C', 'O', 'M', 'M'};
150
char aiff_id_none[4] = {'N', 'O', 'N', 'E'};
151
char aiff_id_fl32[4] = {'f', 'l', '3', '2'};
152
char aiff_id_ulaw[4] = {'u', 'l', 'a', 'w'};
153
char aiff_id_alaw[4] = {'a', 'l', 'a', 'w'};
154
155
char au_id[4] = {'.', 's', 'n', 'd'};
156
157
static inline unsigned int
158
le16_get(le16_t *p)
159
{
160
	return p->lw[0] | p->lw[1] << 8;
161
}
162
163
static inline void
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
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
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
189
be16_get(be16_t *p)
190
{
191
	return p->bw[1] | p->bw[0] << 8;
192
}
193
194
static inline void
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
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
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
220
afile_readhdr(struct afile *f, void *addr, size_t size)
221
{
222
	if (lseek(f->fd, 0, SEEK_SET) < 0) {
223
		log_puts(f->path);
224
		log_puts(": failed to seek to beginning of file\n");
225
		return 0;
226
	}
227
	if (read(f->fd, addr, size) != size) {
228
		log_puts(f->path);
229
		log_puts(": failed to read header\n");
230
		return 0;
231
	}
232
	return 1;
233
}
234
235
static int
236
afile_writehdr(struct afile *f, void *addr, size_t size)
237
{
238
	if (lseek(f->fd, 0, SEEK_SET) < 0) {
239
		log_puts(f->path);
240
		log_puts(": failed to seek back to header\n");
241
		return 0;
242
	}
243
	if (write(f->fd, addr, size) != size) {
244
		log_puts(f->path);
245
		log_puts(": failed to write header\n");
246
		return 0;
247
	}
248
	f->curpos = f->startpos;
249
	return 1;
250
}
251
252
static int
253
afile_checkpar(struct afile *f)
254
{
255
	if (f->nch == 0 || f->nch > NCHAN_MAX) {
256
		log_puts(f->path);
257
		log_puts(": ");
258
		log_putu(f->nch);
259
		log_puts(": unsupported number of channels\n");
260
		return 0;
261
	}
262
	if (f->rate < RATE_MIN || f->rate > RATE_MAX) {
263
		log_puts(f->path);
264
		log_puts(": ");
265
		log_putu(f->rate);
266
		log_puts(": unsupported rate\n");
267
		return 0;
268
	}
269
	if (f->par.bits < BITS_MIN || f->par.bits > BITS_MAX) {
270
		log_puts(f->path);
271
		log_puts(": ");
272
		log_putu(f->par.bits);
273
		log_puts(": unsupported bits per sample\n");
274
		return 0;
275
	}
276
	if (f->par.bits > f->par.bps * 8) {
277
		log_puts(f->path);
278
		log_puts(": bits larger than bytes-per-sample\n");
279
		return 0;
280
	}
281
	if (f->fmt == AFILE_FMT_FLOAT && f->par.bits != 32) {
282
		log_puts(f->path);
283
		log_puts(": only 32-bit floating points are supported\n");
284
		return 0;
285
	}
286
	return 1;
287
}
288
289
static int
290
afile_wav_readfmt(struct afile *f, unsigned int csize)
291
{
292
	struct wav_fmt fmt;
293
	unsigned int wenc;
294
295
	if (csize < WAV_FMT_SIZE) {
296
		log_puts(f->path);
297
		log_puts(": ");
298
		log_putu(csize);
299
		log_puts(": bogus format chunk size\n");
300
		return 0;
301
	}
302
	if (csize > WAV_FMT_EXT_SIZE)
303
		csize = WAV_FMT_EXT_SIZE;
304
	if (read(f->fd, &fmt, csize) != csize) {
305
		log_puts(f->path);
306
		log_puts(": failed to read format chunk\n");
307
		return 0;
308
	}
309
	wenc = le16_get(&fmt.fmt);
310
	f->par.bits = le16_get(&fmt.bits);
311
	if (wenc == WAV_FMT_EXT) {
312
		if (csize != WAV_FMT_EXT_SIZE) {
313
			log_puts(f->path);
314
			log_puts(": missing extended format chunk\n");
315
			return 0;
316
		}
317
		if (memcmp(fmt.guid, wav_guid, sizeof(wav_guid)) != 0) {
318
			log_puts(f->path);
319
			log_puts(": unknown format (GUID)\n");
320
			return 0;
321
		}
322
		f->par.bps = (f->par.bits + 7) / 8;
323
		f->par.bits = le16_get(&fmt.valbits);
324
		wenc = le16_get(&fmt.extfmt);
325
	} else
326
		f->par.bps = (f->par.bits + 7) / 8;
327
	f->nch = le16_get(&fmt.nch);
328
	f->rate = le32_get(&fmt.rate);
329
	f->par.le = 1;
330
	f->par.msb = 1;
331
	switch (wenc) {
332
	case WAV_FMT_PCM:
333
		f->fmt = AFILE_FMT_PCM;
334
		f->par.sig = (f->par.bits <= 8) ? 0 : 1;
335
		break;
336
	case WAV_FMT_ALAW:
337
		f->fmt = AFILE_FMT_ALAW;
338
		f->par.bits = 8;
339
		f->par.bps = 1;
340
		break;
341
	case WAV_FMT_ULAW:
342
		f->fmt = AFILE_FMT_ULAW;
343
		f->par.bits = 8;
344
		f->par.bps = 1;
345
		break;
346
	case WAV_FMT_FLOAT:
347
		f->fmt = AFILE_FMT_FLOAT;
348
		break;
349
	default:
350
		log_putu(wenc);
351
		log_puts(": unsupported encoding\n");
352
		return 0;
353
	}
354
	return afile_checkpar(f);
355
}
356
357
static int
358
afile_wav_readhdr(struct afile *f)
359
{
360
	struct wav_riff riff;
361
	struct wav_chunk chunk;
362
	unsigned int csize, rsize, pos = 0;
363
	int fmt_done = 0;
364
365
	if (!afile_readhdr(f, &riff, sizeof(struct wav_riff)))
366
		return 0;
367
	if (memcmp(&riff.id, &wav_id_riff, 4) != 0 ||
368
	    memcmp(&riff.type, &wav_id_wave, 4)) {
369
		log_puts(f->path);
370
		log_puts(": not a .wav file\n");
371
		return 0;
372
	}
373
	rsize = le32_get(&riff.size);
374
	for (;;) {
375
		if (pos + sizeof(struct wav_chunk) > rsize) {
376
			log_puts(f->path);
377
			log_puts(": missing data chunk\n");
378
			return 0;
379
		}
380
		if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
381
			log_puts(f->path);
382
			log_puts(": failed to read chunk header\n");
383
			return 0;
384
		}
385
		csize = le32_get(&chunk.size);
386
		if (memcmp(chunk.id, wav_id_fmt, 4) == 0) {
387
			if (!afile_wav_readfmt(f, csize))
388
				return 0;
389
			fmt_done = 1;
390
		} else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
391
			f->startpos = pos + sizeof(riff) + sizeof(chunk);
392
			f->endpos = f->startpos + csize;
393
			break;
394
		} else {
395
#ifdef DEBUG
396
			if (log_level >= 2) {
397
				log_puts(f->path);
398
				log_puts(": skipped unknown chunk\n");
399
			}
400
#endif
401
		}
402
403
		/*
404
		 * next chunk
405
		 */
406
		pos += sizeof(struct wav_chunk) + csize;
407
		if (lseek(f->fd, sizeof(riff) + pos, SEEK_SET) < 0) {
408
			log_puts(f->path);
409
			log_puts(": filed to seek to chunk\n");
410
			return 0;
411
		}
412
	}
413
	if (!fmt_done) {
414
		log_puts(f->path);
415
		log_puts(": missing format chunk\n");
416
		return 0;
417
	}
418
	return 1;
419
}
420
421
/*
422
 * Write header and seek to start position
423
 */
424
static int
425
afile_wav_writehdr(struct afile *f)
426
{
427
	struct wav_hdr hdr;
428
429
	memset(&hdr, 0, sizeof(struct wav_hdr));
430
	memcpy(hdr.riff.id, wav_id_riff, 4);
431
	memcpy(hdr.riff.type, wav_id_wave, 4);
432
	le32_set(&hdr.riff.size, f->endpos - sizeof(hdr.riff));
433
	memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4);
434
	le32_set(&hdr.fmt_hdr.size, sizeof(hdr.fmt));
435
	le16_set(&hdr.fmt.fmt, 1);
436
	le16_set(&hdr.fmt.nch, f->nch);
437
	le32_set(&hdr.fmt.rate, f->rate);
438
	le32_set(&hdr.fmt.byterate, f->rate * f->par.bps * f->nch);
439
	le16_set(&hdr.fmt.blkalign, f->par.bps * f->nch);
440
	le16_set(&hdr.fmt.bits, f->par.bits);
441
	memcpy(hdr.data_hdr.id, wav_id_data, 4);
442
	le32_set(&hdr.data_hdr.size, f->endpos - f->startpos);
443
	return afile_writehdr(f, &hdr, sizeof(struct wav_hdr));
444
}
445
446
static int
447
afile_aiff_readcomm(struct afile *f, unsigned int csize,
448
    int comp, unsigned int *nfr)
449
{
450
	struct aiff_comm comm;
451
	unsigned int csize_min;
452
	unsigned int e, m;
453
454
	csize_min = comp ?
455
	    sizeof(struct aiff_comm) : sizeof(struct aiff_commbase);
456
	if (csize < csize_min) {
457
		log_puts(f->path);
458
		log_puts(": ");
459
		log_putu(csize);
460
		log_puts(": bogus comm chunk size\n");
461
		return 0;
462
	}
463
	if (read(f->fd, &comm, csize_min) != csize_min) {
464
		log_puts(f->path);
465
		log_puts(": failed to read comm chunk\n");
466
		return 0;
467
	}
468
	f->nch = be16_get(&comm.base.nch);
469
	e = be16_get(&comm.base.rate_ex);
470
	m = be32_get(&comm.base.rate_hi);
471
	if (e < 0x3fff || e > 0x3fff + 31) {
472
		log_puts(f->path);
473
		log_puts(": malformed sample rate\n");
474
		return 0;
475
	}
476
	f->rate = m >> (0x3fff + 31 - e);
477
	if (comp) {
478
		if (memcmp(comm.comp_id, aiff_id_none, 4) == 0) {
479
			f->fmt = AFILE_FMT_PCM;
480
			f->par.bits = be16_get(&comm.base.bits);
481
		} else if (memcmp(comm.comp_id, aiff_id_fl32, 4) == 0) {
482
			f->fmt = AFILE_FMT_FLOAT;
483
			f->par.bits = 32;
484
		} else if (memcmp(comm.comp_id, aiff_id_ulaw, 4) == 0) {
485
			f->fmt = AFILE_FMT_ULAW;
486
			f->par.bits = 8;
487
		} else if (memcmp(comm.comp_id, aiff_id_alaw, 4) == 0) {
488
			f->fmt = AFILE_FMT_ALAW;
489
			f->par.bits = 8;
490
		} else {
491
			log_puts(f->path);
492
			log_puts(": unsupported encoding\n");
493
			return 0;
494
		}
495
	} else {
496
		f->fmt = AFILE_FMT_PCM;
497
		f->par.bits = be16_get(&comm.base.bits);
498
	}
499
	f->par.le = 0;
500
	f->par.sig = 1;
501
	f->par.msb = 1;
502
	f->par.bps = (f->par.bits + 7) / 8;
503
	*nfr = be32_get(&comm.base.nfr);
504
	return afile_checkpar(f);
505
}
506
507
static int
508
afile_aiff_readdata(struct afile *f, unsigned int csize, unsigned int *roffs)
509
{
510
	struct aiff_data data;
511
512
	if (csize < sizeof(struct aiff_data)) {
513
		log_puts(f->path);
514
		log_puts(": ");
515
		log_putu(csize);
516
		log_puts(": bogus data chunk size\n");
517
		return 0;
518
	}
519
	csize = sizeof(struct aiff_data);
520
	if (read(f->fd, &data, csize) != csize) {
521
		log_puts(f->path);
522
		log_puts(": failed to read data chunk\n");
523
		return 0;
524
	}
525
	*roffs = csize + be32_get(&data.offs);
526
	return 1;
527
}
528
529
static int
530
afile_aiff_readhdr(struct afile *f)
531
{
532
	struct aiff_form form;
533
	struct aiff_chunk chunk;
534
	unsigned int csize, rsize, nfr = 0, pos = 0, offs;
535
	int comm_done = 0, comp;
536
537
	if (!afile_readhdr(f, &form, sizeof(struct aiff_form)))
538
		return 0;
539
	if (memcmp(&form.id, &aiff_id_form, 4) != 0) {
540
		log_puts(f->path);
541
		log_puts(": not an aiff file\n");
542
		return 0;
543
	}
544
	if (memcmp(&form.type, &aiff_id_aiff, 4) == 0) {
545
		comp = 0;
546
	} else if (memcmp(&form.type, &aiff_id_aifc, 4) == 0)
547
		comp = 1;
548
	else {
549
		log_puts(f->path);
550
		log_puts(": unsupported aiff file sub-type\n");
551
		return 0;
552
	}
553
	rsize = be32_get(&form.size);
554
	for (;;) {
555
		if (pos + sizeof(struct aiff_chunk) > rsize) {
556
			log_puts(f->path);
557
			log_puts(": missing data chunk\n");
558
			return 0;
559
		}
560
		if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
561
			log_puts(f->path);
562
			log_puts(": failed to read chunk header\n");
563
			return 0;
564
		}
565
		csize = be32_get(&chunk.size);
566
		if (memcmp(chunk.id, aiff_id_comm, 4) == 0) {
567
			if (!afile_aiff_readcomm(f, csize, comp, &nfr))
568
				return 0;
569
			comm_done = 1;
570
		} else if (memcmp(chunk.id, aiff_id_data, 4) == 0) {
571
			if (!afile_aiff_readdata(f, csize, &offs))
572
				return 0;
573
			f->startpos = sizeof(form) + pos +
574
			    sizeof(chunk) + offs;
575
			break;
576
		} else {
577
#ifdef DEBUG
578
			if (log_level >= 2) {
579
				log_puts(f->path);
580
				log_puts(": skipped unknown chunk\n");
581
			}
582
#endif
583
		}
584
585
		/*
586
		 * The aiff spec says "Each Chunk must contain an even
587
		 * number of bytes. For those Chunks whose total
588
		 * contents would yield an odd number of bytes, a zero
589
		 * pad byte must be added at the end of the Chunk. This
590
		 * pad byte is not included in ckDataSize, which
591
		 * indicates the size of the data in the Chunk."
592
		 */
593
		csize = (csize + 1) & ~1;
594
		pos += sizeof(struct aiff_chunk) + csize;
595
596
		if (lseek(f->fd, sizeof(form) + pos, SEEK_SET) < 0) {
597
			log_puts(f->path);
598
			log_puts(": filed to seek to chunk\n");
599
			return 0;
600
		}
601
	}
602
	if (!comm_done) {
603
		log_puts(f->path);
604
		log_puts(": missing comm chunk\n");
605
		return 0;
606
	}
607
	f->endpos = f->startpos + f->par.bps * f->nch * nfr;
608
	return 1;
609
}
610
611
/*
612
 * Write header and seek to start position
613
 */
614
static int
615
afile_aiff_writehdr(struct afile *f)
616
{
617
	struct aiff_hdr hdr;
618
	unsigned int bpf;
619
	unsigned int e, m;
620
621
	/* convert rate to 80-bit float (exponent and fraction part) */
622
	m = f->rate;
623
	e = 0x3fff + 31;
624
	while ((m & 0x80000000) == 0) {
625
		e--;
626
		m <<= 1;
627
	}
628
629
	/* bytes per frame */
630
	bpf = f->nch * f->par.bps;
631
632
	memset(&hdr, 0, sizeof(struct aiff_hdr));
633
	memcpy(hdr.form.id, aiff_id_form, 4);
634
	memcpy(hdr.form.type, aiff_id_aiff, 4);
635
	be32_set(&hdr.form.size, f->endpos - sizeof(hdr.form));
636
637
	memcpy(hdr.comm_hdr.id, aiff_id_comm, 4);
638
	be32_set(&hdr.comm_hdr.size, sizeof(hdr.comm));
639
	be16_set(&hdr.comm.nch, f->nch);
640
	be16_set(&hdr.comm.bits, f->par.bits);
641
	be16_set(&hdr.comm.rate_ex, e);
642
	be32_set(&hdr.comm.rate_hi, m);
643
	be32_set(&hdr.comm.rate_lo, 0);
644
	be32_set(&hdr.comm.nfr, (f->endpos - f->startpos) / bpf);
645
646
	memcpy(hdr.data_hdr.id, aiff_id_data, 4);
647
	be32_set(&hdr.data_hdr.size, f->endpos - f->startpos);
648
	be32_set(&hdr.data.offs, 0);
649
	be32_set(&hdr.data.blksz, 0);
650
	return afile_writehdr(f, &hdr, sizeof(struct aiff_hdr));
651
}
652
653
static int
654
afile_au_readhdr(struct afile *f)
655
{
656
	struct au_hdr hdr;
657
	unsigned int fmt;
658
659
	if (!afile_readhdr(f, &hdr, sizeof(struct au_hdr)))
660
		return 0;
661
	if (memcmp(&hdr.id, &au_id, 4) != 0) {
662
		log_puts(f->path);
663
		log_puts(": not a .au file\n");
664
		return 0;
665
	}
666
	f->startpos = be32_get(&hdr.offs);
667
	f->endpos = f->startpos + be32_get(&hdr.size);
668
	fmt = be32_get(&hdr.fmt);
669
	switch (fmt) {
670
	case AU_FMT_PCM8:
671
		f->fmt = AFILE_FMT_PCM;
672
		f->par.bits = 8;
673
		break;
674
	case AU_FMT_PCM16:
675
		f->fmt = AFILE_FMT_PCM;
676
		f->par.bits = 16;
677
		break;
678
	case AU_FMT_PCM24:
679
		f->fmt = AFILE_FMT_PCM;
680
		f->par.bits = 24;
681
		break;
682
	case AU_FMT_PCM32:
683
		f->fmt = AFILE_FMT_PCM;
684
		f->par.bits = 32;
685
		break;
686
	case AU_FMT_ULAW:
687
		f->fmt = AFILE_FMT_ULAW;
688
		f->par.bits = 8;
689
		f->par.bps = 1;
690
		break;
691
	case AU_FMT_ALAW:
692
		f->fmt = AFILE_FMT_ALAW;
693
		f->par.bits = 8;
694
		f->par.bps = 1;
695
		break;
696
	case AU_FMT_FLOAT:
697
		f->fmt = AFILE_FMT_FLOAT;
698
		f->par.bits = 32;
699
		f->par.bps = 4;
700
		break;
701
	default:
702
		log_puts(f->path);
703
		log_puts(": ");
704
		log_putu(fmt);
705
		log_puts(": unsupported encoding\n");
706
		return 0;
707
	}
708
	f->par.le = 0;
709
	f->par.sig = 1;
710
	f->par.bps = f->par.bits / 8;
711
	f->par.msb = 0;
712
	f->rate = be32_get(&hdr.rate);
713
	f->nch = be32_get(&hdr.nch);
714
	if (lseek(f->fd, f->startpos, SEEK_SET) < 0) {
715
		log_puts(f->path);
716
		log_puts(": ");
717
		log_puts("failed to seek to data chunk\n");
718
		return 0;
719
	}
720
	return afile_checkpar(f);
721
}
722
723
/*
724
 * Write header and seek to start position
725
 */
726
static int
727
afile_au_writehdr(struct afile *f)
728
{
729
	struct au_hdr hdr;
730
	unsigned int fmt;
731
732
	memset(&hdr, 0, sizeof(struct au_hdr));
733
	memcpy(hdr.id, au_id, 4);
734
	be32_set(&hdr.offs, f->startpos);
735
	be32_set(&hdr.size, f->endpos - f->startpos);
736
	switch (f->par.bits) {
737
	case 8:
738
		fmt = AU_FMT_PCM8;
739
		break;
740
	case 16:
741
		fmt = AU_FMT_PCM16;
742
		break;
743
	case 24:
744
		fmt = AU_FMT_PCM24;
745
		break;
746
	case 32:
747
		fmt = AU_FMT_PCM32;
748
		break;
749
#ifdef DEBUG
750
	default:
751
		log_puts(f->path);
752
		log_puts(": wrong precision\n");
753
		panic();
754
		return 0;
755
#endif
756
	}
757
	be32_set(&hdr.fmt, fmt);
758
	be32_set(&hdr.rate, f->rate);
759
	be32_set(&hdr.nch, f->nch);
760
	return afile_writehdr(f, &hdr, sizeof(struct au_hdr));
761
}
762
763
size_t
764
afile_read(struct afile *f, void *data, size_t count)
765
{
766
	off_t maxread;
767
	ssize_t n;
768
769
	if (f->endpos >= 0) {
770
		maxread = f->endpos - f->curpos;
771
		if (maxread == 0) {
772
#ifdef DEBUG
773
			if (log_level >= 3) {
774
				log_puts(f->path);
775
				log_puts(": end reached\n");
776
			}
777
#endif
778
			return 0;
779
		}
780
		if (count > maxread)
781
			count = maxread;
782
	}
783
	n = read(f->fd, data, count);
784
	if (n < 0) {
785
		log_puts(f->path);
786
		log_puts(": couldn't read\n");
787
		return 0;
788
	}
789
	f->curpos += n;
790
	return n;
791
}
792
793
size_t
794
afile_write(struct afile *f, void *data, size_t count)
795
{
796
	off_t maxwrite;
797
	int n;
798
799
	if (f->maxpos >= 0) {
800
		maxwrite = f->maxpos - f->curpos;
801
		if (maxwrite == 0) {
802
#ifdef DEBUG
803
			if (log_level >= 3) {
804
				log_puts(f->path);
805
				log_puts(": max file size reached\n");
806
			}
807
#endif
808
			return 0;
809
		}
810
		if (count > maxwrite)
811
			count = maxwrite;
812
	}
813
	n = write(f->fd, data, count);
814
	if (n < 0) {
815
		log_puts(f->path);
816
		log_puts(": couldn't write\n");
817
		return 0;
818
	}
819
	f->curpos += n;
820
	if (f->endpos < f->curpos)
821
		f->endpos = f->curpos;
822
	return n;
823
}
824
825
int
826
afile_seek(struct afile *f, off_t pos)
827
{
828
	pos += f->startpos;
829
	if (f->endpos >= 0 && pos > f->endpos && !f->par.sig) {
830
		log_puts(f->path);
831
		log_puts(": attempt to seek outside file boundaries\n");
832
		return 0;
833
	}
834
835
	/*
836
	 * seek only if needed to avoid errors with pipes & sockets
837
	 */
838
	if (pos != f->curpos) {
839
		if (lseek(f->fd, pos, SEEK_SET) < 0) {
840
			log_puts(f->path);
841
			log_puts(": couldn't seek\n");
842
			return 0;
843
		}
844
		f->curpos = pos;
845
	}
846
	return 1;
847
}
848
849
void
850
afile_close(struct afile *f)
851
{
852
	if (f->flags & AFILE_FWRITE) {
853
		if (f->hdr == AFILE_HDR_WAV)
854
			afile_wav_writehdr(f);
855
		else if (f->hdr == AFILE_HDR_AIFF)
856
			afile_aiff_writehdr(f);
857
		else if (f->hdr == AFILE_HDR_AU)
858
			afile_au_writehdr(f);
859
	}
860
	close(f->fd);
861
}
862
863
int
864
afile_open(struct afile *f, char *path, int hdr, int flags,
865
    struct aparams *par, int rate, int nch)
866
{
867
	char *ext;
868
	static union {
869
		struct wav_hdr wav;
870
		struct aiff_hdr aiff;
871
		struct au_hdr au;
872
	} dummy;
873
874
	f->par = *par;
875
	f->rate = rate;
876
	f->nch = nch;
877
	f->flags = flags;
878
	f->hdr = hdr;
879
	if (hdr == AFILE_HDR_AUTO) {
880
		f->hdr = AFILE_HDR_RAW;
881
		ext = strrchr(path, '.');
882
		if (ext != NULL) {
883
			ext++;
884
			if (strcasecmp(ext, "aif") == 0 ||
885
			    strcasecmp(ext, "aiff") == 0 ||
886
			    strcasecmp(ext, "aifc") == 0)
887
				f->hdr = AFILE_HDR_AIFF;
888
			else if (strcasecmp(ext, "au") == 0 ||
889
			    strcasecmp(ext, "snd") == 0)
890
				f->hdr = AFILE_HDR_AU;
891
			else if (strcasecmp(ext, "wav") == 0)
892
				f->hdr = AFILE_HDR_WAV;
893
		}
894
	}
895
	if (f->flags == AFILE_FREAD) {
896
		if (strcmp(path, "-") == 0) {
897
			f->path = "stdin";
898
			f->fd = STDIN_FILENO;
899
		} else {
900
			f->path = path;
901
			f->fd = open(f->path, O_RDONLY, 0);
902
			if (f->fd < 0) {
903
				log_puts(f->path);
904
				log_puts(": failed to open for reading\n");
905
				return 0;
906
			}
907
		}
908
		if (f->hdr == AFILE_HDR_WAV) {
909
			if (!afile_wav_readhdr(f))
910
				goto bad_close;
911
		} else if (f->hdr == AFILE_HDR_AIFF) {
912
			if (!afile_aiff_readhdr(f))
913
				goto bad_close;
914
		} else if (f->hdr == AFILE_HDR_AU) {
915
			if (!afile_au_readhdr(f))
916
				goto bad_close;
917
		} else {
918
			f->startpos = 0;
919
			f->endpos = -1; /* read until EOF */
920
			f->fmt = AFILE_FMT_PCM;
921
		}
922
		f->curpos = f->startpos;
923
	} else if (flags == AFILE_FWRITE) {
924
		if (strcmp(path, "-") == 0) {
925
			f->path = "stdout";
926
			f->fd = STDOUT_FILENO;
927
		} else {
928
			f->path = path;
929
			f->fd = open(f->path,
930
			    O_WRONLY | O_TRUNC | O_CREAT, 0666);
931
			if (f->fd < 0) {
932
				log_puts(f->path);
933
				log_puts(": failed to create file\n");
934
				return 0;
935
			}
936
		}
937
		if (f->hdr == AFILE_HDR_WAV) {
938
			f->par.bps = (f->par.bits + 7) >> 3;
939
			if (f->par.bits > 8) {
940
				f->par.le = 1;
941
				f->par.sig = 1;
942
			} else
943
				f->par.sig = 0;
944
			if (f->par.bits & 7)
945
				f->par.msb = 1;
946
			f->endpos = f->startpos = sizeof(struct wav_hdr);
947
			f->maxpos = 0x7fffffff;
948
			if (!afile_writehdr(f, &dummy, sizeof(struct wav_hdr)))
949
				goto bad_close;
950
		} else if (f->hdr == AFILE_HDR_AIFF) {
951
			f->par.bps = (f->par.bits + 7) >> 3;
952
			if (f->par.bps > 1)
953
				f->par.le = 0;
954
			f->par.sig = 1;
955
			if (f->par.bits & 7)
956
				f->par.msb = 1;
957
			f->endpos = f->startpos = sizeof(struct aiff_hdr);
958
			f->maxpos = 0x7fffffff;
959
			if (!afile_writehdr(f, &dummy,
960
				sizeof(struct aiff_hdr)))
961
				goto bad_close;
962
		} else if (f->hdr == AFILE_HDR_AU) {
963
			f->par.bits = (f->par.bits + 7) & ~7;
964
			f->par.bps = f->par.bits / 8;
965
			f->par.le = 0;
966
			f->par.sig = 1;
967
			f->par.msb = 1;
968
			f->endpos = f->startpos = sizeof(struct au_hdr);
969
			f->maxpos = 0x7fffffff;
970
			if (!afile_writehdr(f, &dummy, sizeof(struct au_hdr)))
971
				goto bad_close;
972
		} else {
973
			f->endpos = f->startpos = 0;
974
			f->maxpos = -1;
975
		}
976
		f->curpos = f->startpos;
977
	} else {
978
#ifdef DEBUG
979
		log_puts("afile_open: wrong flags\n");
980
		panic();
981
#endif
982
	}
983
	return 1;
984
bad_close:
985
	close(f->fd);
986
	return 0;
987
}