123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- #include <assert.h>
- #include <ctype.h>
- #include <errno.h>
- #include <inttypes.h>
- #include <limits.h>
- #include <signal.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #ifdef USE_CAPSICUM
- #include <sys/capsicum.h>
- #endif
- #include <err.h>
- #include <sysexits.h>
- #include "au.h"
- #include "common.h"
- #ifndef BSIZE
- #define BSIZE 1024
- #endif
- enum {
- MODE_AU,
- MODE_RAW,
- MODE_NOHDR
- };
- #ifdef SIGINFO
- static size_t info_in = 0;
- static size_t info_out = 0;
- #endif
- #ifdef SIGINFO
- static void siginfo(int);
- #endif
- static size_t conv(uint32_t, const void *, size_t, uint32_t, void *,
- size_t, size_t);
- static size_t pcmconv(void *, size_t, void *, uint32_t);
- static size_t ulawconv(uint8_t, void *, uint32_t);
- static size_t alawconv(uint8_t, void *, uint32_t);
- static size_t floatconv(void *, size_t, void *, uint32_t);
- static ssize_t ncpy(int, int, void *, size_t);
- static unsigned clz_16(uint16_t);
- int
- main(int argc, char *argv[])
- {
- char hb[AU_SIZE];
- #ifdef USE_CAPSICUM
- cap_rights_t rights;
- #endif
- struct au iau = AU_INITIALIZER;
- struct au oau = AU_INITIALIZER;
- int (*iswap)(uint32_t, void *, size_t) = NULL;
- int (*oswap)(uint32_t, void *, size_t) = NULL;
- size_t bsize = BSIZE;
- size_t ibsize = 0;
- size_t obsize = 0;
- void *ib = NULL;
- void *ob = NULL;
- const char *cp;
- char *p;
- ssize_t r;
- ssize_t t;
- ssize_t i;
- int imode = MODE_AU;
- int omode = MODE_AU;
- int c;
- #ifdef USE_PLEDGE
- pledge("stdio", NULL);
- #endif
- #ifdef USE_CAPSICUM
- if (cap_enter() == -1 && errno != ENOSYS)
- err(EX_OSERR, "Could not enter capibility mode");
- cap_rights_init(&rights, CAP_READ);
- if (cap_rights_limit(STDIN_FILENO, &rights) == -1 &&
- errno != ENOSYS)
- err(EX_OSERR, "Could not limit the input");
- cap_rights_init(&rights, CAP_WRITE);
- if (cap_rights_limit(STDOUT_FILENO, &rights) == -1 &&
- errno != ENOSYS)
- err(EX_OSERR, "Could not limit the output");
- if (cap_rights_limit(STDERR_FILENO, &rights) == -1 &&
- errno != ENOSYS)
- err(EX_OSERR, "Could not limit the standard error");
- #endif
- while ((c = getopt(argc, argv, "b:c:i:j:o:r:s:")) != -1)
- switch (c) {
- case 'b':
- bsize = strtoul(optarg, &p, 0);
- if (p == optarg || *p != '\0')
- err(EX_USAGE, "Bad number %s", optarg);
- break;
- case 'c':
- iau.au_chan = strtou32(optarg);
- if (imode != MODE_RAW)
- imode = MODE_NOHDR;
- break;
- case 'i':
- imode = MODE_AU;
- if (strncasecmp(optarg, "r", 1) == 0) {
- optarg++;
- if (strncasecmp(optarg, "aw", 2) == 0)
- optarg += 2;
- imode = MODE_RAW;
- if (*optarg == '\0')
- break;
- }
- if ((iau.au_enc = au_strencp(optarg, &cp)) == 0)
- errx(EX_USAGE, "Bad encoding %s",
- optarg);
- if (imode != MODE_RAW)
- imode = MODE_NOHDR;
- if (*cp == '\0')
- break;
- if (toupper(cp[0]) == 'E' && cp[1] != '\0')
- p++;
- switch (toupper(*cp)) {
- case 'B':
- cp++;
- iswap = NULL;
- imode = MODE_RAW;
- break;
- case 'L':
- cp++;
- iswap = &au_encbswap;
- imode = MODE_RAW;
- break;
- case 'N':
- cp++;
- iswap = &au_encnswap;
- imode = MODE_RAW;
- break;
- default:
- err(EX_USAGE, "Bad encoding %s",
- optarg);
- break;
- }
- if (toupper(cp[0]) == 'E')
- cp++;
- if (*cp != '\0')
- errx(EX_USAGE, "Bad encoding %s",
- optarg);
- break;
- case 'j':
- iau.au_off = strtou32(optarg);
- if (imode != MODE_RAW)
- imode = MODE_NOHDR;
- break;
- case 'o':
- omode = MODE_AU;
- if (strncasecmp(optarg, "r", 1) == 0) {
- optarg++;
- if (strncasecmp(optarg, "aw", 2) == 0)
- optarg += 2;
- omode = MODE_RAW;
- if (*optarg == '\0')
- break;
- }
- if ((oau.au_enc = au_strencp(optarg, &cp)) == 0)
- err(EX_USAGE, "Bad encoding %s",
- optarg);
- if (*cp == '\0')
- break;
- if (toupper(cp[0]) == 'E' && cp[1] != '\0')
- p++;
- switch (toupper(*cp++)) {
- case 'B':
- oswap = NULL;
- imode = MODE_RAW;
- break;
- case 'L':
- oswap = &au_encbswap;
- omode = MODE_RAW;
- break;
- case 'N':
- oswap = &au_encnswap;
- omode = MODE_RAW;
- break;
- default:
- err(EX_USAGE, "Bad encoding %s",
- optarg);
- break;
- }
- if (toupper(cp[0]) == 'E')
- cp++;
- if (*cp != '\0')
- errx(EX_USAGE, "Bad encoding %s",
- optarg);
- break;
- case 'r':
- iau.au_rate = strtoul(optarg, &p, 0);
- if (p == optarg || *p != '\0')
- err(EX_USAGE, "Bad number %s", optarg);
- if (imode != MODE_RAW)
- imode = MODE_NOHDR;
- break;
- case 's':
- iau.au_size = strtou32(optarg);
- if (imode != MODE_RAW)
- imode = MODE_NOHDR;
- break;
- default:
- goto usage;
- }
- #ifdef SIGINFO
- (void)signal(SIGINFO, &siginfo);
- #endif
- while (imode != MODE_AU ||
- nread(STDIN_FILENO, hb, sizeof(hb)) == sizeof(hb)) {
- if (imode == MODE_AU) {
- #ifdef SIGINFO
- info_in += AU_SIZE;
- #endif
- if (au_gethdr(&iau, hb) != 0)
- errx(EX_DATAERR, "Bad header");
- }
- if (au_vsize(&iau) == 0)
- err(EX_DATAERR, "Invalid encoding %"PRIu32,
- iau.au_enc);
- if (ibsize < bsize * au_ssize(&iau)) {
- ibsize = bsize * au_ssize(&iau);
- if ((ib = ib == NULL ? malloc(ibsize) :
- realloc(ib, ibsize)) == NULL)
- err(EX_OSERR, "Could not allocate "
- "the input array");
- }
- oau.au_off = iau.au_off;
- oau.au_size = iau.au_size == UINT32_MAX ? UINT32_MAX :
- iau.au_size / au_vsize(&iau) * au_vsize(&oau);
- oau.au_rate = iau.au_rate;
- oau.au_chan = iau.au_chan;
- if (obsize < bsize * au_ssize(&oau)) {
- obsize = bsize * au_ssize(&oau);
- if ((ob = ob == NULL ? malloc(obsize) :
- realloc(ob, obsize)) == NULL)
- err(EX_OSERR, "Could not allocate "
- "the output array");
- }
- if (omode == MODE_AU) {
- (void)au_puthdr(&oau, hb);
- if (nwrite(STDOUT_FILENO, hb, sizeof(hb)) !=
- sizeof(hb))
- err(EX_IOERR,
- "Could not write audio header");
- #ifdef SIGINFO
- info_out += AU_SIZE;
- #endif
- }
- if (omode == MODE_RAW) {
- for (i = AU_SIZE; i < (size_t)iau.au_off;
- i += r) {
- if ((r = nread(STDIN_FILENO, ib,
- MIN(iau.au_off - i, bsize))) < 0)
- err(EX_IOERR,
- "error while reading");
- #ifdef SIGINFO
- info_in += r;
- #endif
- }
- } else {
- /* ncpy handles info_in/info_out */
- for (i = AU_SIZE; i < (size_t)iau.au_off;
- i += r)
- if ((r = ncpy(STDIN_FILENO,
- STDOUT_FILENO, ib, MIN(
- iau.au_off - i, bsize))) < 0)
- err(EX_IOERR,
- "error while copying "
- "stdin -> stdout");
- }
- while (iau.au_size > 0 && (r = nread(STDIN_FILENO, ib,
- MIN(iau.au_size, ibsize))) > 0) {
- #ifdef SIGINFO
- info_in += r;
- #endif
- if (iswap != NULL)
- iswap(iau.au_enc, ib, r);
- if ((t = conv(iau.au_enc, ib, r, oau.au_enc, ob,
- obsize, 0)) < 0)
- abort();
- if (oswap != NULL)
- oswap(oau.au_enc, ob, t);
- if (nwrite(STDOUT_FILENO, ob, t) != t) {
- if (iau.au_size != UINT32_MAX)
- err(EX_IOERR,
- "Write error");
- goto ret;
- }
- #ifdef SIGINFO
- info_out += t;
- #endif
- if (iau.au_size != UINT32_MAX)
- iau.au_size -= r;
- }
- if (r < 0)
- err(EX_IOERR, "Error reading from the "
- "standard input");
- if (imode == MODE_RAW)
- break;
- if (imode == MODE_NOHDR)
- imode = MODE_AU;
- }
- ret:
- if (ib != NULL)
- free(ib);
- if (ob != NULL)
- free(ob);
- return (EX_OK);
- usage:
- (void)fprintf(stderr,
- "usage: auconv "
- "[-b buffer-size] [-c channels] [-i input-encoding]\n"
- " "
- "[-j skip] [-o output-encoding] [-r rate] [-s size]\n");
- return (EX_USAGE);
- }
- #ifdef SIGINFO
- void
- siginfo(int sig)
- {
- /* auconv: XXXXXXiB in XXXXXXiB out */
- char b[8 + 8 + 4 + 8 + 5];
- size_t i = 0;
- (void)memcpy(b + i, "auconv: ", 8);
- i += 8;
- (void)memcpy(b + i, ": ", 2);
- i += 2;
- i += szwrite(b + i, info_in, "B", "iB");
- (void)memcpy(b + i, " in ", 4);
- i += 4;
- i += szwrite(b + i, info_out, "B", "iB");
- (void)memcpy(b + i, " out\n ", 5);
- i += 5;
- (void)write(STDERR_FILENO, b, i);
- }
- #endif
- size_t
- conv(uint32_t ienc, const void *ib, size_t isize, uint32_t oenc,
- void *ob, size_t osize, size_t skip)
- {
- size_t i;
- size_t j = 0;
- size_t o;
- size_t off;
- assert(ib != NULL && ob != NULL);
- if (osize == 0)
- return (0);
- o = au_encsize(ienc);
- off = o + o * skip;
- if (ienc == oenc) {
- if (off == o) {
- i = isize > osize ? osize : isize;
- (void)memmove(ob, ib, i);
- return (i);
- }
- for (i = 0, j = 0; i < isize && j < osize;
- i += off, j += o)
- (void)memmove((void *)((uintptr_t)ob + j),
- (void *)((uintptr_t)ib + i), o);
- }
- switch (ienc) {
- case AU_ULAW:
- for (i = 0, j = 0; i < isize && j < osize; i += off)
- j += ulawconv(*(uint8_t *)((uintptr_t)ib + i),
- (void *)((uintptr_t)ob + j), oenc);
- break;
- case AU_PCM8:
- /* FALLTHROUGH */
- case AU_PCM16:
- /* FALLTHROUGH */
- case AU_PCM24:
- /* FALLTHROUGH */
- case AU_PCM32:
- for (i = 0, j = 0; i < isize && j < osize; i += off)
- j += pcmconv((void *)((uintptr_t)ib + i), o,
- (void *)((uintptr_t)ob + j), oenc);
- break;
- case AU_FLOAT32:
- /* FALLTHROUGH */
- case AU_FLOAT64:
- for (i = 0, j = 0; i < isize && j < osize; i += off)
- j += floatconv((void *)((uintptr_t)ib + i), o,
- (void *)((uintptr_t)ob + j), oenc);
- break;
- case AU_ALAW:
- for (i = 0, j = 0; i < isize && j < osize; i += off)
- j += alawconv(*(uint8_t *)((uintptr_t)ib + i),
- (void *)((uintptr_t)ob + j), oenc);
- break;
- }
- return (j);
- }
- size_t
- pcmconv(void *ib, size_t io, void *ob, uint32_t oenc)
- {
- const uint32_t end = 1;
- char b[sizeof(double)];
- size_t i;
- size_t t;
- uint32_t pcm;
- switch (oenc) {
- case AU_ULAW:
- if (io == 1) { /* expand to 14-bits */
- pcm = *(uint8_t *)ib;
- pcm = (pcm << 6) | (pcm >> 2);
- } else /* shrink to 14-bits */
- pcm = (((uint8_t *)ib)[0] << 6) |
- (((uint8_t *)ib)[1] >> 2);
- if (pcm & 0x2000) {
- pcm = ~pcm & 0x1FFF;
- i = 0;
- } else
- i = 0x80;
- if (pcm < 0x2000 - 33)
- pcm += 33;
- t = clz_16(pcm) - 3;
- *(uint8_t *)ob = i | (t << 4) |
- (~(pcm >> (8 - t)) & 0x0F);
- return (1);
- case AU_PCM8:
- /* FALLTHROUGH */
- case AU_PCM16:
- /* FALLTHROUGH */
- case AU_PCM24:
- /* FALLTHROUGH */
- case AU_PCM32:
- for (i = 0, t = au_encsize(oenc); i < t; i++)
- ((uint8_t *)ob)[i] = ((uint8_t *)ib)[i % io];
- return (t);
- case AU_FLOAT32:
- /* FALLTHROUGH */
- case AU_FLOAT64:
- for (i = 0, pcm = 0; i < io; i++)
- pcm = pcm << 8 | ((uint8_t *)ib)[i];
- t = UINT32_C(1) << ((io * 8) - 1);
- if (pcm & t) {
- pcm = (~pcm & (t - 1)) + 1;
- i = 0;
- } else
- i = 1;
- if (oenc == AU_FLOAT32) {
- *(float *)b = (float)pcm / (float)(t - i);
- if (!i)
- *(float *)b = -*(float *)b;
- t = sizeof(float);
- } else {
- *(double *)b = (double)pcm / (double)(t - i);
- if (!i)
- *(double *)b = -*(double *)b;
- t = sizeof(double);
- }
- if (*(char *)&end)
- for (i = 0; i < t; i++)
- ((char *)ob)[i] = b[t - i - 1];
- else
- for (i = 0; i < t; i++)
- ((char *)ob)[i] = b[i];
- return (t);
- case AU_ALAW:
- if (io == 1) { /* expand to 13-bits */
- pcm = *(uint8_t *)ib;
- pcm = (pcm << 5) | (pcm >> 3);
- } else /* shrink to 13-bits */
- pcm = (((uint8_t *)ib)[0] << 5) |
- (((uint8_t *)ib)[1] >> 3);
- if (pcm & 0x1000) {
- pcm = ~pcm & 0x0FFF;
- i = 0;
- } else
- i = 0x80;
- if ((t = clz_16(pcm) - 4) >= 7)
- *(uint8_t *)ob = i | ((pcm >> 1) & 0x0F);
- else
- *(uint8_t *)ob = i | ((7 - t) << 4) |
- ((pcm >> (7 - t)) & 0x0F);
- *(uint8_t *)ob ^= 0x55;
- return (1);
- }
- abort();
- }
- size_t
- ulawconv(uint8_t u, void *ob, uint32_t oenc)
- {
- unsigned char b[sizeof(uint16_t)];
- uint16_t pcm;
- uint16_t p;
- if (oenc == AU_ULAW) {
- *(uint8_t *)ob = u;
- return (1);
- }
- u = ~u;
- p = (u >> 4) & 7;
- pcm = ((u & 0x0F) << (p + 1)) | (0x21 << p);
- pcm = ((pcm << 2) | (pcm >> 12)) - 33;
- if (u & 0x80)
- pcm = ~pcm;
- for (p = 0; p < sizeof(b); p++)
- b[p] = pcm >> (sizeof(b) - p - 1) * CHAR_BIT;
- return (pcmconv(b, sizeof(uint16_t), ob, oenc));
- }
- size_t
- alawconv(uint8_t a, void *ob, uint32_t oenc)
- {
- unsigned char b[sizeof(uint16_t)];
- uint16_t pcm;
- uint16_t p;
- if (oenc == AU_ALAW) {
- *(uint8_t *)ob = a;
- return (1);
- }
- a ^= 0xD5;
- if ((p = (a >> 4) & 7) == 0)
- pcm = ((a & 0x0F) << 1) | 1;
- else
- pcm = ((a & 0x0F) << p) | (0x21 << (p - 1));
- pcm = (pcm << 3) | (pcm >> 10);
- if (a & 0x80)
- pcm = ~pcm;
- for (p = 0; p < sizeof(b); p++)
- b[p] = pcm >> (sizeof(b) - p - 1) * CHAR_BIT;
- return (pcmconv(b, sizeof(uint16_t), ob, oenc));
- }
- size_t
- floatconv(void *ib, size_t io, void *ob, uint32_t oenc)
- {
- const uint32_t end = 1;
- unsigned char b[sizeof(double)];
- uint32_t pcm;
- uint32_t t = 0;
- double d;
- size_t i;
- /* and begin incantations */
- switch (oenc) {
- case AU_ULAW:
- (void)floatconv(ib, io, b, AU_PCM16);
- return (pcmconv(b, sizeof(uint16_t), ob, oenc));
- break;
- case AU_PCM8:
- /* FALLTHROUGH */
- case AU_PCM16:
- /* FALLTHROUGH */
- case AU_PCM24:
- /* FALLTHROUGH */
- case AU_PCM32:
- t = oenc - AU_PCM8 + 1;
- if (*(char *)&end)
- for (i = 0; i < io; i++)
- b[i] = ((char *)ib)[io - i - 1];
- else
- for (i = 0; i < io; i++)
- b[i] = ((char *)ib)[i];
- if (io == sizeof(float))
- d = *(float *)b;
- else
- d = *(double *)b;
- if (d < 0) {
- d = -d;
- i = 0;
- } else
- i = 1;
- d *= (UINT32_C(1) << (t * 8 - 1)) - i;
- pcm = (uint32_t)d;
- if (!i)
- pcm = ~pcm + 1;
- for (i = 0; i < t; i++)
- ((uint8_t *)ob)[i] = pcm >> (t - i - 1) * 8;
- return (t);
- case AU_FLOAT32:
- if (io == sizeof(float)) {
- (void)memcpy(ob, ib, io);
- return (io);
- }
- /*
- * Expanded Float Double
- * sabcdefg sabcdefg
- * mantissa loop -> habc*123 hijk0123
- * 45670123 45670123
- * 45670123 45670123
- * mantissa loop -> 456*1234 45670123
- * 56701234 45670123
- * 56701234 45670123
- * mantissa loop -> 56*12345 45670123
- */
- ((uint8_t *)ob)[0] = ((uint8_t *)ib)[0];
- ((uint8_t *)ob)[1] = (((uint8_t *)ib)[1] & 0x80) |
- (((uint8_t *)ob)[0] & 0x70) |
- ((((uint8_t *)ib)[1] >> 3) & 0x0F);
- ((uint8_t *)ob)[2] = (((uint8_t *)ib)[1] << 5) |
- ((((uint8_t *)ib)[2] >> 3) & 0x1F);
- ((uint8_t *)ob)[3] = (((uint8_t *)ib)[2] << 5) |
- ((((uint8_t *)ib)[3] >> 3) & 0x1F);
- ((uint8_t *)ob)[4] = (((uint8_t *)ib)[3] << 5) |
- ((((uint8_t *)ib)[1] >> 2) & 0x1F);
- ((uint8_t *)ob)[5] = (((uint8_t *)ib)[1] << 6) |
- ((((uint8_t *)ib)[2] >> 2) & 0x1F);
- ((uint8_t *)ob)[6] = (((uint8_t *)ib)[2] << 6) |
- ((((uint8_t *)ib)[3] >> 2) & 0x1F);
- ((uint8_t *)ob)[7] = (((uint8_t *)ib)[3] << 6) |
- ((((uint8_t *)ib)[1] >> 1) & 0x1F);
- return (sizeof(double));
- case AU_FLOAT64:
- if (io == sizeof(double)) {
- (void)memcpy(ob, ib, io);
- return (io);
- }
- ((uint8_t *)ob)[0] = ((uint8_t *)ib)[0];
- ((uint8_t *)ob)[1] = (((uint8_t *)ib)[1] & 0x80) |
- ((((uint8_t *)ib)[1] << 3) & 0x70) |
- (((uint8_t *)ib)[2] >> 5);
- ((uint8_t *)ob)[2] = (((uint8_t *)ib)[2] << 3) |
- (((uint8_t *)ib)[3] >> 5);
- ((uint8_t *)ob)[3] = (((uint8_t *)ib)[3] << 3) |
- (((uint8_t *)ib)[4] >> 5);
- return (sizeof(float));
- case AU_ALAW:
- (void)floatconv(ib, io, b, AU_PCM16);
- return (pcmconv(b, sizeof(uint16_t), ob, oenc));
- break;
- }
- abort();
- }
- ssize_t
- ncpy(int in, int out, void *b, size_t s)
- {
- ssize_t t;
- if ((t = nread(in, b, s)) > 0) {
- #ifdef SIGINFO
- info_in += t;
- #endif
- t = nwrite(out, b, s);
- #ifdef SIGINFO
- info_out += t;
- #endif
- }
- return (t);
- }
- unsigned
- clz_16(uint16_t v)
- {
- unsigned r = 0;
- if ((v & 0xFF00) == 0) {
- v <<= 8;
- r += 8;
- }
- if ((v & 0xF000) == 0) {
- v <<= 4;
- r += 4;
- }
- if ((v & 0xC000) == 0) {
- v <<= 2;
- r += 2;
- }
- r += (uint16_t)~v >> 15;
- return (r);
- }
|