Annotation of src/usr.bin/aucat/afile.c, Revision 1.10
1.1 ratchov 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:
1.8 naddy 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] = {
1.1 ratchov 139: 0x00, 0x00, 0x00, 0x00,
140: 0x10, 0x00, 0x80, 0x00,
141: 0x00, 0xAA, 0x00, 0x38,
142: 0x9B, 0x71
143: };
144:
1.8 naddy 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'};
1.1 ratchov 154:
1.8 naddy 155: const char au_id[4] = {'.', 's', 'n', 'd'};
1.1 ratchov 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: {
1.7 deraadt 222: if (lseek(f->fd, 0, SEEK_SET) == -1) {
1.1 ratchov 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: {
1.7 deraadt 238: if (lseek(f->fd, 0, SEEK_SET) == -1) {
1.1 ratchov 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;
1.7 deraadt 407: if (lseek(f->fd, sizeof(riff) + pos, SEEK_SET) == -1) {
1.1 ratchov 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));
1.10 ! ratchov 435: le16_set(&hdr.fmt.fmt, WAV_FMT_EXT);
1.1 ratchov 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);
1.10 ! ratchov 441: le16_set(&hdr.fmt.extsize,
! 442: WAV_FMT_EXT_SIZE - WAV_FMT_SIZE - sizeof(hdr.fmt.extsize));
! 443: le16_set(&hdr.fmt.valbits, f->par.bits);
! 444: le16_set(&hdr.fmt.extfmt, 1);
! 445: memcpy(&hdr.fmt.guid, wav_guid, sizeof(hdr.fmt.guid));
1.1 ratchov 446: memcpy(hdr.data_hdr.id, wav_id_data, 4);
447: le32_set(&hdr.data_hdr.size, f->endpos - f->startpos);
448: return afile_writehdr(f, &hdr, sizeof(struct wav_hdr));
449: }
450:
451: static int
452: afile_aiff_readcomm(struct afile *f, unsigned int csize,
453: int comp, unsigned int *nfr)
454: {
455: struct aiff_comm comm;
456: unsigned int csize_min;
457: unsigned int e, m;
458:
459: csize_min = comp ?
460: sizeof(struct aiff_comm) : sizeof(struct aiff_commbase);
461: if (csize < csize_min) {
462: log_puts(f->path);
463: log_puts(": ");
464: log_putu(csize);
465: log_puts(": bogus comm chunk size\n");
466: return 0;
467: }
468: if (read(f->fd, &comm, csize_min) != csize_min) {
469: log_puts(f->path);
470: log_puts(": failed to read comm chunk\n");
471: return 0;
472: }
473: f->nch = be16_get(&comm.base.nch);
474: e = be16_get(&comm.base.rate_ex);
475: m = be32_get(&comm.base.rate_hi);
476: if (e < 0x3fff || e > 0x3fff + 31) {
477: log_puts(f->path);
478: log_puts(": malformed sample rate\n");
479: return 0;
480: }
481: f->rate = m >> (0x3fff + 31 - e);
482: if (comp) {
483: if (memcmp(comm.comp_id, aiff_id_none, 4) == 0) {
484: f->fmt = AFILE_FMT_PCM;
485: f->par.bits = be16_get(&comm.base.bits);
486: } else if (memcmp(comm.comp_id, aiff_id_fl32, 4) == 0) {
487: f->fmt = AFILE_FMT_FLOAT;
488: f->par.bits = 32;
489: } else if (memcmp(comm.comp_id, aiff_id_ulaw, 4) == 0) {
490: f->fmt = AFILE_FMT_ULAW;
491: f->par.bits = 8;
492: } else if (memcmp(comm.comp_id, aiff_id_alaw, 4) == 0) {
493: f->fmt = AFILE_FMT_ALAW;
494: f->par.bits = 8;
495: } else {
496: log_puts(f->path);
497: log_puts(": unsupported encoding\n");
498: return 0;
499: }
500: } else {
501: f->fmt = AFILE_FMT_PCM;
502: f->par.bits = be16_get(&comm.base.bits);
503: }
504: f->par.le = 0;
505: f->par.sig = 1;
506: f->par.msb = 1;
507: f->par.bps = (f->par.bits + 7) / 8;
508: *nfr = be32_get(&comm.base.nfr);
509: return afile_checkpar(f);
510: }
511:
512: static int
513: afile_aiff_readdata(struct afile *f, unsigned int csize, unsigned int *roffs)
514: {
515: struct aiff_data data;
516:
517: if (csize < sizeof(struct aiff_data)) {
518: log_puts(f->path);
519: log_puts(": ");
520: log_putu(csize);
521: log_puts(": bogus data chunk size\n");
522: return 0;
523: }
524: csize = sizeof(struct aiff_data);
525: if (read(f->fd, &data, csize) != csize) {
526: log_puts(f->path);
527: log_puts(": failed to read data chunk\n");
528: return 0;
529: }
530: *roffs = csize + be32_get(&data.offs);
531: return 1;
532: }
533:
534: static int
535: afile_aiff_readhdr(struct afile *f)
536: {
537: struct aiff_form form;
538: struct aiff_chunk chunk;
539: unsigned int csize, rsize, nfr = 0, pos = 0, offs;
540: int comm_done = 0, comp;
541:
1.5 nicm 542: if (!afile_readhdr(f, &form, sizeof(struct aiff_form)))
1.1 ratchov 543: return 0;
544: if (memcmp(&form.id, &aiff_id_form, 4) != 0) {
545: log_puts(f->path);
546: log_puts(": not an aiff file\n");
547: return 0;
548: }
549: if (memcmp(&form.type, &aiff_id_aiff, 4) == 0) {
550: comp = 0;
551: } else if (memcmp(&form.type, &aiff_id_aifc, 4) == 0)
552: comp = 1;
553: else {
554: log_puts(f->path);
555: log_puts(": unsupported aiff file sub-type\n");
556: return 0;
557: }
558: rsize = be32_get(&form.size);
559: for (;;) {
560: if (pos + sizeof(struct aiff_chunk) > rsize) {
561: log_puts(f->path);
562: log_puts(": missing data chunk\n");
563: return 0;
564: }
565: if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
566: log_puts(f->path);
567: log_puts(": failed to read chunk header\n");
568: return 0;
1.3 ratchov 569: }
1.1 ratchov 570: csize = be32_get(&chunk.size);
571: if (memcmp(chunk.id, aiff_id_comm, 4) == 0) {
572: if (!afile_aiff_readcomm(f, csize, comp, &nfr))
573: return 0;
574: comm_done = 1;
575: } else if (memcmp(chunk.id, aiff_id_data, 4) == 0) {
576: if (!afile_aiff_readdata(f, csize, &offs))
577: return 0;
1.3 ratchov 578: f->startpos = sizeof(form) + pos +
579: sizeof(chunk) + offs;
1.1 ratchov 580: break;
581: } else {
582: #ifdef DEBUG
583: if (log_level >= 2) {
584: log_puts(f->path);
585: log_puts(": skipped unknown chunk\n");
586: }
587: #endif
588: }
589:
590: /*
591: * The aiff spec says "Each Chunk must contain an even
592: * number of bytes. For those Chunks whose total
593: * contents would yield an odd number of bytes, a zero
594: * pad byte must be added at the end of the Chunk. This
595: * pad byte is not included in ckDataSize, which
596: * indicates the size of the data in the Chunk."
597: */
598: csize = (csize + 1) & ~1;
599: pos += sizeof(struct aiff_chunk) + csize;
600:
1.7 deraadt 601: if (lseek(f->fd, sizeof(form) + pos, SEEK_SET) == -1) {
1.1 ratchov 602: log_puts(f->path);
603: log_puts(": filed to seek to chunk\n");
604: return 0;
605: }
606: }
607: if (!comm_done) {
608: log_puts(f->path);
609: log_puts(": missing comm chunk\n");
610: return 0;
611: }
612: f->endpos = f->startpos + f->par.bps * f->nch * nfr;
613: return 1;
614: }
615:
616: /*
617: * Write header and seek to start position
618: */
619: static int
620: afile_aiff_writehdr(struct afile *f)
621: {
622: struct aiff_hdr hdr;
623: unsigned int bpf;
624: unsigned int e, m;
625:
626: /* convert rate to 80-bit float (exponent and fraction part) */
627: m = f->rate;
628: e = 0x3fff + 31;
629: while ((m & 0x80000000) == 0) {
630: e--;
631: m <<= 1;
632: }
633:
634: /* bytes per frame */
635: bpf = f->nch * f->par.bps;
636:
637: memset(&hdr, 0, sizeof(struct aiff_hdr));
638: memcpy(hdr.form.id, aiff_id_form, 4);
639: memcpy(hdr.form.type, aiff_id_aiff, 4);
640: be32_set(&hdr.form.size, f->endpos - sizeof(hdr.form));
641:
642: memcpy(hdr.comm_hdr.id, aiff_id_comm, 4);
643: be32_set(&hdr.comm_hdr.size, sizeof(hdr.comm));
644: be16_set(&hdr.comm.nch, f->nch);
645: be16_set(&hdr.comm.bits, f->par.bits);
646: be16_set(&hdr.comm.rate_ex, e);
647: be32_set(&hdr.comm.rate_hi, m);
648: be32_set(&hdr.comm.rate_lo, 0);
649: be32_set(&hdr.comm.nfr, (f->endpos - f->startpos) / bpf);
650:
651: memcpy(hdr.data_hdr.id, aiff_id_data, 4);
652: be32_set(&hdr.data_hdr.size, f->endpos - f->startpos);
653: be32_set(&hdr.data.offs, 0);
654: be32_set(&hdr.data.blksz, 0);
655: return afile_writehdr(f, &hdr, sizeof(struct aiff_hdr));
656: }
657:
658: static int
659: afile_au_readhdr(struct afile *f)
660: {
661: struct au_hdr hdr;
662: unsigned int fmt;
663:
1.5 nicm 664: if (!afile_readhdr(f, &hdr, sizeof(struct au_hdr)))
1.1 ratchov 665: return 0;
666: if (memcmp(&hdr.id, &au_id, 4) != 0) {
667: log_puts(f->path);
668: log_puts(": not a .au file\n");
669: return 0;
670: }
671: f->startpos = be32_get(&hdr.offs);
672: f->endpos = f->startpos + be32_get(&hdr.size);
673: fmt = be32_get(&hdr.fmt);
674: switch (fmt) {
675: case AU_FMT_PCM8:
676: f->fmt = AFILE_FMT_PCM;
677: f->par.bits = 8;
678: break;
679: case AU_FMT_PCM16:
680: f->fmt = AFILE_FMT_PCM;
681: f->par.bits = 16;
682: break;
683: case AU_FMT_PCM24:
684: f->fmt = AFILE_FMT_PCM;
685: f->par.bits = 24;
686: break;
687: case AU_FMT_PCM32:
688: f->fmt = AFILE_FMT_PCM;
689: f->par.bits = 32;
690: break;
691: case AU_FMT_ULAW:
692: f->fmt = AFILE_FMT_ULAW;
693: f->par.bits = 8;
694: break;
695: case AU_FMT_ALAW:
696: f->fmt = AFILE_FMT_ALAW;
697: f->par.bits = 8;
698: break;
699: case AU_FMT_FLOAT:
700: f->fmt = AFILE_FMT_FLOAT;
701: f->par.bits = 32;
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);
1.7 deraadt 716: if (lseek(f->fd, f->startpos, SEEK_SET) == -1) {
1.1 ratchov 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);
1.7 deraadt 786: if (n == -1) {
1.1 ratchov 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);
1.7 deraadt 816: if (n == -1) {
1.1 ratchov 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;
1.2 ratchov 831: if (f->endpos >= 0 && pos > f->endpos && !f->par.sig) {
1.1 ratchov 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) {
1.7 deraadt 841: if (lseek(f->fd, pos, SEEK_SET) == -1) {
1.1 ratchov 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;
1.9 deraadt 903: f->fd = open(f->path, O_RDONLY);
1.7 deraadt 904: if (f->fd == -1) {
1.1 ratchov 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;
1.3 ratchov 931: f->fd = open(f->path,
932: O_WRONLY | O_TRUNC | O_CREAT, 0666);
1.7 deraadt 933: if (f->fd == -1) {
1.1 ratchov 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;
1.3 ratchov 961: if (!afile_writehdr(f, &dummy,
962: sizeof(struct aiff_hdr)))
1.1 ratchov 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: }