[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.8

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