* Added unriffle RIFF inspector.
authorUrban Wallasch <urban.wallasch@freenet.de>
Sun, 17 Nov 2019 04:45:03 +0000 (05:45 +0100)
committerUrban Wallasch <urban.wallasch@freenet.de>
Sun, 17 Nov 2019 04:45:03 +0000 (05:45 +0100)
* Amended and improved Makefile.
* Updated .gitignore.

.gitignore
Makefile
unriffle.c [new file with mode: 0644]

index 1cdc1584318f22c476d9062b64678185b8714776..34da50ed480063750ab38b30ca4f0295aa42349d 100644 (file)
@@ -1 +1,2 @@
 riffx
+unriffle
index 68efab797fe5a6615e104fe2c722c2fe1506076d..5a4d5915f50c11cde15b493cb9855d6d2782a50b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,21 +1,26 @@
+CC ?= gcc
+CCX ?= g++
 CFLAGS = -O2 -Wall -Wextra -Werror
 
 .PHONY: all clean
 
-all: ww2ogg-b revorb-b riffx-b
+all: ww2ogg/ww2ogg revorb-nix/revorb riffx unriffle
 
-riffx-b: riffx
+riffx: riffx.c
+       $(CC) $(CFLAGS) -o riffx riffx.c
        strip riffx
 
-riffx: riffx.c
+unriffle: unriffle.c
+       $(CC) $(CFLAGS) -o unriffle unriffle.c
+       strip unriffle
 
-ww2ogg-b:
+ww2ogg/ww2ogg:
        cd ww2ogg && $(MAKE) all
 
-revorb-b:
-       cd revorb-nix && ./build.sh
+revorb-nix/revorb: revorb-nix/revorb.cpp
+       $(CCX) revorb-nix/revorb.cpp -o revorb-nix/revorb -logg -lvorbis
 
 clean:
-       rm -f *.o riffx
+       rm -f *.o riffx unriffle
        cd ww2ogg && $(MAKE) clean
        cd revorb-nix && rm revorb 2>/dev/null ||:
diff --git a/unriffle.c b/unriffle.c
new file mode 100644 (file)
index 0000000..9134ab1
--- /dev/null
@@ -0,0 +1,216 @@
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static struct {
+    FILE *dump_fp;
+    FILE *log_fp;
+    int endianess;
+} cfg = {
+    NULL,
+    NULL,
+    0,
+};
+
+
+/*
+ * dump helper:
+ */
+
+static const char *hdig = "0123456789abcdef";
+
+static inline void xdump(const void *s, size_t n) {
+    const unsigned char *p = s;
+    char buf[68];
+    char *b = buf;
+    char *a = buf + 51;
+    size_t i = 0;
+
+    memset(buf, ' ', sizeof buf);
+    while (i < n) {
+        *b++ = hdig[p[i] / 16];
+        *b++ = hdig[p[i] % 16];
+        *a++ = isgraph(p[i]) ? p[i] : '.';
+        ++i;
+        if (i % 16 == 0) {
+            *a++ = '\0';
+            fprintf(cfg.dump_fp, "%14zu: %s\n", i - 16, buf);
+            memset(buf, ' ', sizeof buf);
+            b = buf;
+            a = buf + 51;
+        }
+        else {
+            if (i % 8 == 0)
+                *b++ = ' ';
+            *b++ = ' ';
+        }
+    }
+    if (b != buf) {
+        *a++ = '\0';
+        fprintf(cfg.dump_fp, "%14zu: %s\n", (i - 1) / 16 * 16, buf);
+    }
+}
+
+/* Little/Big Endian to native uint32 conversion: */
+static inline uint32_t get_ui32(const void *p) {
+    const uint8_t *b = p;
+    if (!cfg.endianess)     /* Little Endian byte order (RIFF) */
+        return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;
+    /* Big Endian byte order (RIFX) */
+    return b[3] | b[2] << 8 | b[1] << 16 | b[0] << 24;
+}
+
+/* Little/Big Endian to native uint16 conversion: */
+static inline uint16_t get_ui16(const void *p) {
+    const uint8_t *b = p;
+    if (!cfg.endianess)     /* Little Endian byte order (RIFF) */
+        return b[0] | b[1] << 8;
+    /* Big Endian byte order (RIFX) */
+    return b[1] | b[0] << 8;
+}
+
+#define LOG(...)  (fprintf(cfg.log_fp,__VA_ARGS__))
+#define DIE(...)  do{LOG(__VA_ARGS__);exit(EXIT_FAILURE);}while(0)
+#define DMP(...)  (fprintf(cfg.dump_fp,__VA_ARGS__))
+
+#define FOURCC_IS(p_,q_) (!memcmp((const void *)(p_),(const void *)(q_),4))
+
+typedef uint8_t fcc_t[4];
+
+typedef
+    struct RIFF_chunk_t {
+        fcc_t fcc;
+        uint32_t csize;
+        uint8_t data[];
+    }
+    RIFF_chunk_t;
+
+static inline void dump4cc(const char *s, fcc_t fcc) {
+    fcc_t f;
+    for (size_t i = 0; i < sizeof f; i++)
+        f[i] = isprint((unsigned char)fcc[i]) ? fcc[i] : '?';
+    DMP("[4] %14s: ", s);  DMP("%4.4s\n", f);
+}
+
+static inline void dump4ccEnd(const char *s, fcc_t fcc) {
+    fcc_t f;
+    for (size_t i = 0; i < sizeof f; i++)
+        f[i] = isprint((unsigned char)fcc[i]) ? fcc[i] : '?';
+    DMP("    %14s: [%4.4s end]\n", s, f);
+}
+
+static inline void dumpU16(const char *s, const void *u) {
+    DMP("[2] %14s: ", s);  DMP("%"PRIu16"\n", get_ui16(u));
+}
+
+static inline void dumpU32(const char *s, const void *u) {
+    DMP("[4] %14s: ", s);  DMP("%"PRIu32"\n", get_ui32(u));
+}
+
+static inline void dumpStr(const char *s, const void *u) {
+    DMP("%14s: ", s);  DMP("%s\n", (const char *)u);
+}
+
+static int rdump(void *p, size_t fsize) {
+    RIFF_chunk_t *r = p;
+    uint32_t sz = get_ui32(&r->csize);
+
+    if (!fsize || !sz) {
+        return 0;
+    }
+    DMP("\n");
+    dump4cc("Chunk ID", r->fcc);
+    dumpU32("Size", &r->csize);
+    if (FOURCC_IS(&r->fcc, "RIFF") || FOURCC_IS(&r->fcc, "RIFX")) {
+        dump4cc("RIFF Type", r->data);
+        rdump(r->data + sizeof(fcc_t), fsize - sizeof(fcc_t));
+    }
+    else if (FOURCC_IS(&r->fcc, "LIST")) {
+        dump4cc("Form Type", r->data);
+        rdump(r->data + sizeof(fcc_t), sz - sizeof(fcc_t));
+    }
+    else if (FOURCC_IS(&r->fcc, "labl")) {
+        dumpU32("Label ID", r->data);
+        dumpStr("Label Text", r->data + 4);
+        sz += 8;
+    }
+    else if (FOURCC_IS(&r->fcc, "cue ")) {
+        uint32_t cn = get_ui32(r->data);
+        dumpU32("# Cue points", &r->data);
+        for (uint32_t i = 0; i < cn; ++i) {
+            uint8_t *c;
+            c = r->data + i * 24 + 4;
+            dumpU32("Cue ID", c);
+            dumpU32("Cue Position", c+4);
+            dump4cc("Data Chunk ID", c + 8);
+            dumpU32("Chunk Start", c+12);
+            dumpU32("Block Start", c+16);
+            dumpU32("Sample Offset", c+20);
+        }
+    }
+    else if (FOURCC_IS(&r->fcc, "fmt ")) {
+        dumpU16("Compression", r->data);
+        dumpU16("# Channels", r->data+2);
+        dumpU32("Sample Rate", r->data+4);
+        dumpU32("Avg. Bytes/s", r->data+8);
+        dumpU16("Block align", r->data+12);
+        dumpU16("Signif. bit/s", r->data+14 );
+        dumpU16("Xtra FMT bytes", r->data+16);
+        xdump(r->data+18, sz-18);
+    }
+    else if (sz <= fsize) {
+        xdump(r->data, sz);
+    }
+    else {
+        /* Garbage beyond expected EOF: */
+        xdump(r->data, fsize);
+        return -1;
+    }
+    dump4ccEnd("==============", r->fcc);
+    return rdump(r->data + sz, fsize - sz);
+}
+
+int main(int argc, char *argv[]) {
+    FILE *ifp = stdin;
+    size_t fsize = 0;
+    void *buf;
+    RIFF_chunk_t *r;
+    size_t nrd;
+
+    cfg.dump_fp = stdout;
+    cfg.log_fp = stderr;
+    if (argc > 1) {
+        ifp = fopen(argv[1], "r");
+        if (!ifp)
+            DIE("fopen %s: %s\n", argv[1], strerror(errno));
+        fseek(ifp, 0, SEEK_END);
+        fsize = ftell(ifp);
+        rewind(ifp);
+    }
+    buf = malloc(fsize);
+    if (!buf)
+        DIE("malloc: %s\n", strerror(errno));
+    nrd = fread(buf, 1, fsize, ifp);
+    if (ferror(ifp) || nrd != fsize)
+        DIE("read: %s\n", strerror(errno));
+    r = buf;
+
+    if (!FOURCC_IS(r->fcc, "RIFF")) {
+        if (!FOURCC_IS(r->fcc, "RIFX"))
+            DIE("%s is not a RIFF file!\n", argv[1]);
+        cfg.endianess = 1;
+    }
+
+    DMP("File name: %s\n", argv[1]);
+    DMP("File size: %zu\n", fsize);
+    rdump(r, fsize);
+    free(buf);
+    exit(EXIT_SUCCESS);
+}
+
+