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