Annotation of src/usr.bin/aucat/afile.c, Revision 1.7
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:
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: {
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));
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:
1.5 nicm 537: if (!afile_readhdr(f, &form, sizeof(struct aiff_form)))
1.1 ratchov 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;
1.3 ratchov 564: }
1.1 ratchov 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;
1.3 ratchov 573: f->startpos = sizeof(form) + pos +
574: sizeof(chunk) + offs;
1.1 ratchov 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:
1.7 ! deraadt 596: if (lseek(f->fd, sizeof(form) + pos, SEEK_SET) == -1) {
1.1 ratchov 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:
1.5 nicm 659: if (!afile_readhdr(f, &hdr, sizeof(struct au_hdr)))
1.1 ratchov 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: break;
690: case AU_FMT_ALAW:
691: f->fmt = AFILE_FMT_ALAW;
692: f->par.bits = 8;
693: break;
694: case AU_FMT_FLOAT:
695: f->fmt = AFILE_FMT_FLOAT;
696: f->par.bits = 32;
697: break;
698: default:
699: log_puts(f->path);
700: log_puts(": ");
701: log_putu(fmt);
702: log_puts(": unsupported encoding\n");
703: return 0;
704: }
705: f->par.le = 0;
706: f->par.sig = 1;
707: f->par.bps = f->par.bits / 8;
708: f->par.msb = 0;
709: f->rate = be32_get(&hdr.rate);
710: f->nch = be32_get(&hdr.nch);
1.7 ! deraadt 711: if (lseek(f->fd, f->startpos, SEEK_SET) == -1) {
1.1 ratchov 712: log_puts(f->path);
713: log_puts(": ");
714: log_puts("failed to seek to data chunk\n");
715: return 0;
716: }
717: return afile_checkpar(f);
718: }
719:
720: /*
721: * Write header and seek to start position
722: */
723: static int
724: afile_au_writehdr(struct afile *f)
725: {
726: struct au_hdr hdr;
727: unsigned int fmt;
728:
729: memset(&hdr, 0, sizeof(struct au_hdr));
730: memcpy(hdr.id, au_id, 4);
731: be32_set(&hdr.offs, f->startpos);
732: be32_set(&hdr.size, f->endpos - f->startpos);
733: switch (f->par.bits) {
734: case 8:
735: fmt = AU_FMT_PCM8;
736: break;
737: case 16:
738: fmt = AU_FMT_PCM16;
739: break;
740: case 24:
741: fmt = AU_FMT_PCM24;
742: break;
743: case 32:
744: fmt = AU_FMT_PCM32;
745: break;
746: #ifdef DEBUG
747: default:
748: log_puts(f->path);
749: log_puts(": wrong precision\n");
750: panic();
751: return 0;
752: #endif
753: }
754: be32_set(&hdr.fmt, fmt);
755: be32_set(&hdr.rate, f->rate);
756: be32_set(&hdr.nch, f->nch);
757: return afile_writehdr(f, &hdr, sizeof(struct au_hdr));
758: }
759:
760: size_t
761: afile_read(struct afile *f, void *data, size_t count)
762: {
763: off_t maxread;
764: ssize_t n;
765:
766: if (f->endpos >= 0) {
767: maxread = f->endpos - f->curpos;
768: if (maxread == 0) {
769: #ifdef DEBUG
770: if (log_level >= 3) {
771: log_puts(f->path);
772: log_puts(": end reached\n");
773: }
774: #endif
775: return 0;
776: }
777: if (count > maxread)
778: count = maxread;
779: }
780: n = read(f->fd, data, count);
1.7 ! deraadt 781: if (n == -1) {
1.1 ratchov 782: log_puts(f->path);
783: log_puts(": couldn't read\n");
784: return 0;
785: }
786: f->curpos += n;
787: return n;
788: }
789:
790: size_t
791: afile_write(struct afile *f, void *data, size_t count)
792: {
793: off_t maxwrite;
794: int n;
795:
796: if (f->maxpos >= 0) {
797: maxwrite = f->maxpos - f->curpos;
798: if (maxwrite == 0) {
799: #ifdef DEBUG
800: if (log_level >= 3) {
801: log_puts(f->path);
802: log_puts(": max file size reached\n");
803: }
804: #endif
805: return 0;
806: }
807: if (count > maxwrite)
808: count = maxwrite;
809: }
810: n = write(f->fd, data, count);
1.7 ! deraadt 811: if (n == -1) {
1.1 ratchov 812: log_puts(f->path);
813: log_puts(": couldn't write\n");
814: return 0;
815: }
816: f->curpos += n;
817: if (f->endpos < f->curpos)
818: f->endpos = f->curpos;
819: return n;
820: }
821:
822: int
823: afile_seek(struct afile *f, off_t pos)
824: {
825: pos += f->startpos;
1.2 ratchov 826: if (f->endpos >= 0 && pos > f->endpos && !f->par.sig) {
1.1 ratchov 827: log_puts(f->path);
828: log_puts(": attempt to seek outside file boundaries\n");
829: return 0;
830: }
831:
832: /*
833: * seek only if needed to avoid errors with pipes & sockets
834: */
835: if (pos != f->curpos) {
1.7 ! deraadt 836: if (lseek(f->fd, pos, SEEK_SET) == -1) {
1.1 ratchov 837: log_puts(f->path);
838: log_puts(": couldn't seek\n");
839: return 0;
840: }
841: f->curpos = pos;
842: }
843: return 1;
844: }
845:
846: void
847: afile_close(struct afile *f)
848: {
849: if (f->flags & AFILE_FWRITE) {
850: if (f->hdr == AFILE_HDR_WAV)
851: afile_wav_writehdr(f);
852: else if (f->hdr == AFILE_HDR_AIFF)
853: afile_aiff_writehdr(f);
854: else if (f->hdr == AFILE_HDR_AU)
855: afile_au_writehdr(f);
856: }
857: close(f->fd);
858: }
859:
860: int
861: afile_open(struct afile *f, char *path, int hdr, int flags,
862: struct aparams *par, int rate, int nch)
863: {
864: char *ext;
865: static union {
866: struct wav_hdr wav;
867: struct aiff_hdr aiff;
868: struct au_hdr au;
869: } dummy;
870:
871: f->par = *par;
872: f->rate = rate;
873: f->nch = nch;
874: f->flags = flags;
875: f->hdr = hdr;
876: if (hdr == AFILE_HDR_AUTO) {
877: f->hdr = AFILE_HDR_RAW;
878: ext = strrchr(path, '.');
879: if (ext != NULL) {
880: ext++;
881: if (strcasecmp(ext, "aif") == 0 ||
882: strcasecmp(ext, "aiff") == 0 ||
883: strcasecmp(ext, "aifc") == 0)
884: f->hdr = AFILE_HDR_AIFF;
885: else if (strcasecmp(ext, "au") == 0 ||
886: strcasecmp(ext, "snd") == 0)
887: f->hdr = AFILE_HDR_AU;
888: else if (strcasecmp(ext, "wav") == 0)
889: f->hdr = AFILE_HDR_WAV;
890: }
891: }
892: if (f->flags == AFILE_FREAD) {
893: if (strcmp(path, "-") == 0) {
894: f->path = "stdin";
895: f->fd = STDIN_FILENO;
896: } else {
897: f->path = path;
898: f->fd = open(f->path, O_RDONLY, 0);
1.7 ! deraadt 899: if (f->fd == -1) {
1.1 ratchov 900: log_puts(f->path);
901: log_puts(": failed to open for reading\n");
902: return 0;
903: }
904: }
905: if (f->hdr == AFILE_HDR_WAV) {
906: if (!afile_wav_readhdr(f))
907: goto bad_close;
908: } else if (f->hdr == AFILE_HDR_AIFF) {
909: if (!afile_aiff_readhdr(f))
910: goto bad_close;
911: } else if (f->hdr == AFILE_HDR_AU) {
912: if (!afile_au_readhdr(f))
913: goto bad_close;
914: } else {
915: f->startpos = 0;
916: f->endpos = -1; /* read until EOF */
917: f->fmt = AFILE_FMT_PCM;
918: }
919: f->curpos = f->startpos;
920: } else if (flags == AFILE_FWRITE) {
921: if (strcmp(path, "-") == 0) {
922: f->path = "stdout";
923: f->fd = STDOUT_FILENO;
924: } else {
925: f->path = path;
1.3 ratchov 926: f->fd = open(f->path,
927: O_WRONLY | O_TRUNC | O_CREAT, 0666);
1.7 ! deraadt 928: if (f->fd == -1) {
1.1 ratchov 929: log_puts(f->path);
930: log_puts(": failed to create file\n");
931: return 0;
932: }
933: }
934: if (f->hdr == AFILE_HDR_WAV) {
935: f->par.bps = (f->par.bits + 7) >> 3;
936: if (f->par.bits > 8) {
937: f->par.le = 1;
938: f->par.sig = 1;
939: } else
940: f->par.sig = 0;
941: if (f->par.bits & 7)
942: f->par.msb = 1;
943: f->endpos = f->startpos = sizeof(struct wav_hdr);
944: f->maxpos = 0x7fffffff;
945: if (!afile_writehdr(f, &dummy, sizeof(struct wav_hdr)))
946: goto bad_close;
947: } else if (f->hdr == AFILE_HDR_AIFF) {
948: f->par.bps = (f->par.bits + 7) >> 3;
949: if (f->par.bps > 1)
950: f->par.le = 0;
951: f->par.sig = 1;
952: if (f->par.bits & 7)
953: f->par.msb = 1;
954: f->endpos = f->startpos = sizeof(struct aiff_hdr);
955: f->maxpos = 0x7fffffff;
1.3 ratchov 956: if (!afile_writehdr(f, &dummy,
957: sizeof(struct aiff_hdr)))
1.1 ratchov 958: goto bad_close;
959: } else if (f->hdr == AFILE_HDR_AU) {
960: f->par.bits = (f->par.bits + 7) & ~7;
961: f->par.bps = f->par.bits / 8;
962: f->par.le = 0;
963: f->par.sig = 1;
964: f->par.msb = 1;
965: f->endpos = f->startpos = sizeof(struct au_hdr);
966: f->maxpos = 0x7fffffff;
967: if (!afile_writehdr(f, &dummy, sizeof(struct au_hdr)))
968: goto bad_close;
969: } else {
970: f->endpos = f->startpos = 0;
971: f->maxpos = -1;
972: }
973: f->curpos = f->startpos;
974: } else {
975: #ifdef DEBUG
976: log_puts("afile_open: wrong flags\n");
977: panic();
978: #endif
979: }
980: return 1;
981: bad_close:
982: close(f->fd);
983: return 0;
984: }