[BACK]Return to afile.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

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: }