initial commit
authorGeoffrey Allott <geoffrey@allott.email>
Sat, 30 Jul 2022 20:43:17 +0000 (21:43 +0100)
committerGeoffrey Allott <geoffrey@allott.email>
Sat, 30 Jul 2022 20:43:17 +0000 (21:43 +0100)
30 files changed:
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
src/floor_log2.h [new file with mode: 0644]
src/tans_bit_reader.h [new file with mode: 0644]
src/tans_bit_writer.h [new file with mode: 0644]
src/tans_buf_bit_reader.c [new file with mode: 0644]
src/tans_buf_bit_reader.h [new file with mode: 0644]
src/tans_buf_bit_writer.c [new file with mode: 0644]
src/tans_buf_bit_writer.h [new file with mode: 0644]
src/tans_constants.h [new file with mode: 0644]
src/tans_decode_st.c [new file with mode: 0644]
src/tans_decode_st.h [new file with mode: 0644]
src/tans_decode_tbl.c [new file with mode: 0644]
src/tans_decode_tbl.h [new file with mode: 0644]
src/tans_encode_st.c [new file with mode: 0644]
src/tans_encode_st.h [new file with mode: 0644]
src/tans_encode_tbl.c [new file with mode: 0644]
src/tans_encode_tbl.h [new file with mode: 0644]
src/tans_file_bit_reader.c [new file with mode: 0644]
src/tans_file_bit_reader.h [new file with mode: 0644]
src/tans_freq_tbl.h [new file with mode: 0644]
src/tans_symbol_tbl.c [new file with mode: 0644]
src/tans_symbol_tbl.h [new file with mode: 0644]
test/test.h [new file with mode: 0644]
test/test_tans_bit_reader [new file with mode: 0755]
test/test_tans_bit_reader.c [new file with mode: 0644]
test/test_tans_bit_writer [new file with mode: 0755]
test/test_tans_bit_writer.c [new file with mode: 0644]
test/test_tans_encode_st [new file with mode: 0755]
test/test_tans_encode_st.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..50a3785
--- /dev/null
@@ -0,0 +1,2 @@
+*.o
+.*.sw*
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..cedffbd
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+CFLAGS = -Isrc -g -Wall -Wextra -Wconversion
+
+OBJS = $(patsubst %.c, %.o, $(wildcard src/*.o))
+TEST_OBJS = $(patsubst %.c, %.o, $(wildcard test/*.o))
+TESTS = $(patsubst %.c, %, $(wildcard test/*.c))
+RUN_TESTS = $(addprefix run_, $(TESTS))
+
+default: $(RUN_TESTS)
+
+$(RUN_TESTS): run_%: %
+       $^
+
+all: $(OBJS)
+
+$(OBJS): %.o: %.h src/tans_constants.h
+$(TEST_OBJS): test/test.h $(OBJS)
+
+test/test_tans_bit_reader.o: src/tans_buf_bit_reader.h src/tans_file_bit_reader.h src/tans_bit_reader.h
+test/test_tans_bit_reader: src/tans_buf_bit_reader.o src/tans_file_bit_reader.o
+test/test_tans_bit_writer.o: src/tans_buf_bit_writer.h src/tans_bit_writer.h
+test/test_tans_bit_writer: src/tans_buf_bit_writer.o
+test/test_tans_encode_st.o: src/tans_buf_bit_writer.h src/tans_bit_writer.h src/tans_encode_st.h src/tans_symbol_tbl.h src/tans_freq_tbl.h
+test/test_tans_encode_st: src/tans_buf_bit_writer.o src/tans_encode_st.o src/tans_encode_tbl.o src/tans_symbol_tbl.o
+
+clean:
+       rm -f $(OBJS)
+       rm -f $(TEST_OBJS)
+       rm -f $(TESTS)
+
+.PHONY: default all clean $(RUN_TESTS)
diff --git a/src/floor_log2.h b/src/floor_log2.h
new file mode 100644 (file)
index 0000000..24c2e0e
--- /dev/null
@@ -0,0 +1,22 @@
+#pragma once
+
+static uint16_t floor_log2(uint16_t x)
+{
+    if (x <= 1) return 0;
+    if (x <= 2) return 1;
+    if (x <= 4) return 2;
+    if (x <= 8) return 3;
+    if (x <= 16) return 4;
+    if (x <= 32) return 5;
+    if (x <= 64) return 6;
+    if (x <= 128) return 7;
+    if (x <= 256) return 8;
+    if (x <= 512) return 9;
+    if (x <= 1024) return 10;
+    if (x <= 2048) return 11;
+    if (x <= 4096) return 12;
+    if (x <= 8192) return 13;
+    if (x <= 16384) return 14;
+    if (x <= 32768) return 15;
+    /*if (x <= 65536)*/ return 16;
+}
diff --git a/src/tans_bit_reader.h b/src/tans_bit_reader.h
new file mode 100644 (file)
index 0000000..dc139f8
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <stdint.h>
+
+struct tans_bit_reader;
+
+struct tans_bit_reader_ops {
+    uint16_t (*read)(struct tans_bit_reader *self, uint8_t bits);
+};
+
+struct tans_bit_reader {
+    const struct tans_bit_reader_ops *vtable;
+};
diff --git a/src/tans_bit_writer.h b/src/tans_bit_writer.h
new file mode 100644 (file)
index 0000000..119c138
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <stdint.h>
+
+struct tans_bit_writer;
+
+struct tans_bit_writer_ops {
+    uint16_t (*write)(struct tans_bit_writer *self, uint16_t value, uint8_t bits);
+};
+
+struct tans_bit_writer {
+    const struct tans_bit_writer_ops *vtable;
+};
diff --git a/src/tans_buf_bit_reader.c b/src/tans_buf_bit_reader.c
new file mode 100644 (file)
index 0000000..564549e
--- /dev/null
@@ -0,0 +1,36 @@
+#include "tans_buf_bit_reader.h"
+
+static uint16_t tans_buf_bit_reader_read(struct tans_bit_reader *reader, uint8_t bits)
+{
+    struct tans_buf_bit_reader *self = (struct tans_buf_bit_reader *) reader;
+    uint32_t bit = self->bit % 8;
+    uint32_t byte = self->bit / 8;
+
+    if (bits == 0 || self->bit + bits > self->len * 8) {
+        return (uint16_t) -1;
+    }
+
+    self->bit += bits;
+
+    if (bit + bits <= 8) {
+        return (uint16_t) (((1 << bits) - 1) & (self->buf[byte] >> bit));
+    } else if (bit + bits <= 16) {
+        return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte] | (self->buf[byte+1] << 8)) >> bit));
+    } else if (bit + bits <= 24) {
+        return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte] | (self->buf[byte+1] << 8) | (self->buf[byte+2] << 16)) >> bit));
+    } else {
+        return (uint16_t) -1;
+    }
+}
+
+static const struct tans_bit_reader_ops vtable = {
+    .read = tans_buf_bit_reader_read,
+};
+
+void tans_buf_bit_reader_init(struct tans_buf_bit_reader *self, const uint8_t *buf, uint32_t len)
+{
+    self->vtable = &vtable;
+    self->bit = 0;
+    self->len = len;
+    self->buf = buf;
+}
diff --git a/src/tans_buf_bit_reader.h b/src/tans_buf_bit_reader.h
new file mode 100644 (file)
index 0000000..71d7d07
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "tans_bit_reader.h"
+
+struct tans_buf_bit_reader {
+    const struct tans_bit_reader_ops *vtable;
+    uint32_t bit;
+    uint32_t len;
+    const uint8_t *buf;
+};
+
+void tans_buf_bit_reader_init(struct tans_buf_bit_reader *self, const uint8_t *buf, uint32_t len);
diff --git a/src/tans_buf_bit_writer.c b/src/tans_buf_bit_writer.c
new file mode 100644 (file)
index 0000000..20186a1
--- /dev/null
@@ -0,0 +1,46 @@
+#include "tans_buf_bit_writer.h"
+
+static uint16_t tans_buf_bit_writer_write(struct tans_bit_writer *writer, uint16_t value, uint8_t bits)
+{
+    struct tans_buf_bit_writer *self = (struct tans_buf_bit_writer *) writer;
+    uint32_t bit = self->bit % 8;
+    uint32_t byte = self->bit / 8;
+
+    if (bits == 0) {
+        return 0;
+    }
+
+    if (self->bit + bits > self->len * 8) {
+        return (uint16_t) -1;
+    }
+
+    self->bit += bits;
+
+    if (bit + bits <= 8) {
+        self->buf[byte] |= (uint8_t) ((value & ((1 << bits) - 1)) << bit);
+        return bits;
+    } else if (bit + bits <= 16) {
+        self->buf[byte] |= (uint8_t) ((value << bit) & 0xff);
+        self->buf[byte+1] |= (uint8_t) ((value & ((1 << bits) - 1)) >> (8 - bit));
+        return bits;
+    } else if (bit + bits <= 24) {
+        self->buf[byte] |= (uint8_t) ((value << bit) & 0xff);
+        self->buf[byte+1] |= (uint8_t) ((value >> (8 - bit)) & 0xff);
+        self->buf[byte+2] |= (uint8_t) ((value & ((1 << bits) - 1)) >> (16 - bit));
+        return bits;
+    } else {
+        return (uint16_t) -1;
+    }
+}
+
+static const struct tans_bit_writer_ops vtable = {
+    .write = tans_buf_bit_writer_write,
+};
+
+void tans_buf_bit_writer_init(struct tans_buf_bit_writer *self, uint8_t *buf, uint32_t len)
+{
+    self->vtable = &vtable;
+    self->bit = 0;
+    self->len = len;
+    self->buf = buf;
+}
diff --git a/src/tans_buf_bit_writer.h b/src/tans_buf_bit_writer.h
new file mode 100644 (file)
index 0000000..20d1488
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "tans_bit_writer.h"
+
+struct tans_buf_bit_writer {
+    const struct tans_bit_writer_ops *vtable;
+    uint32_t bit;
+    uint32_t len;
+    uint8_t *buf;
+};
+
+void tans_buf_bit_writer_init(struct tans_buf_bit_writer *self, uint8_t *buf, uint32_t len);
diff --git a/src/tans_constants.h b/src/tans_constants.h
new file mode 100644 (file)
index 0000000..ea031f2
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+#define TANS_R 10
+#define TANS_L (1 << TANS_R)
diff --git a/src/tans_decode_st.c b/src/tans_decode_st.c
new file mode 100644 (file)
index 0000000..c5077fc
--- /dev/null
@@ -0,0 +1,24 @@
+#include "tans_decode_st.h"
+
+void tans_decode_st_init(struct tans_decode_st *self, struct tans_symbol_tbl *symbol_tbl)
+{
+    tans_decode_tbl_init(&self->decode_tbl, symbol_tbl);
+    self->x = 0;
+}
+
+uint16_t tans_decode_st_next(struct tans_decode_st *self, struct tans_bit_reader *bit_reader)
+{
+    uint8_t ret;
+    uint16_t read;
+    struct tans_decode_tbl_entry t = self->decode_tbl.entries[self->x];
+
+    read = bit_reader->vtable->read(bit_reader, t.nb_bits);
+    if (read == -1) {
+        return -1;
+    }
+
+    ret = t.symbol;
+    self->x = t.new_x + read;
+
+    return (uint16_t) ret;
+}
diff --git a/src/tans_decode_st.h b/src/tans_decode_st.h
new file mode 100644 (file)
index 0000000..09165a8
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "tans_decode_tbl.h"
+#include "tans_bit_reader.h"
+
+struct tans_decode_st {
+    struct tans_decode_tbl decode_tbl;
+    uint16_t x;
+};
+
+void tans_decode_st_init(struct tans_decode_st *self, struct tans_symbol_tbl *symbol_tbl);
+uint16_t tans_decode_st_next(struct tans_decode_st *self, struct tans_bit_reader *bit_reader);
diff --git a/src/tans_decode_tbl.c b/src/tans_decode_tbl.c
new file mode 100644 (file)
index 0000000..e3feb24
--- /dev/null
@@ -0,0 +1,17 @@
+#include "tans_decode_tbl.h"
+
+#include "floor_log2.h"
+
+void tans_decode_tbl_init(struct tans_decode_tbl *self, struct tans_symbol_tbl *symbol_tbl)
+{
+    uint16_t i;
+    uint16_t x;
+    uint8_t s;
+
+    for (i = 0; i < TANS_L; ++i) {
+        s = self->entries[i].symbol = symbol_tbl->symbol[i];
+        x = symbol_tbl->entries[s].next++;
+        self->entries[s].nb_bits = TANS_R - floor_log2(x);
+        self->entries[s].new_x = (x << self->entries[s].nb_bits) - TANS_L;
+    }
+}
diff --git a/src/tans_decode_tbl.h b/src/tans_decode_tbl.h
new file mode 100644 (file)
index 0000000..e191176
--- /dev/null
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "tans_symbol_tbl.h"
+
+struct tans_decode_tbl_entry {
+    uint8_t symbol;
+    uint8_t nb_bits;
+    uint16_t new_x;
+};
+
+struct tans_decode_tbl {
+    struct tans_decode_tbl_entry entries[TANS_L];
+};
+
+void tans_decode_tbl_init(struct tans_decode_tbl *self, struct tans_symbol_tbl *symbol_tbl);
diff --git a/src/tans_encode_st.c b/src/tans_encode_st.c
new file mode 100644 (file)
index 0000000..d6c7232
--- /dev/null
@@ -0,0 +1,23 @@
+#include "tans_encode_st.h"
+
+void tans_encode_st_init(struct tans_encode_st *self, const struct tans_symbol_tbl *symbol_tbl)
+{
+    self->symbol_tbl = *symbol_tbl;
+    tans_encode_tbl_init(&self->encode_tbl, &self->symbol_tbl);
+    self->x = 0;
+}
+
+uint16_t tans_encode_st_next(struct tans_encode_st *self, struct tans_bit_writer *bit_writer, uint8_t symbol)
+{
+    uint8_t nb_bits;
+    uint16_t written;
+
+    nb_bits = (uint8_t) ((self->x + TANS_L + self->symbol_tbl.entries[symbol].nb) >> (TANS_R + 1));
+    written = bit_writer->vtable->write(bit_writer, self->x + TANS_L, nb_bits);
+    if (written != nb_bits) {
+        return (uint16_t) -1;
+    }
+    self->x = self->encode_tbl.entries[self->symbol_tbl.entries[symbol].start + ((self->x + TANS_L) >> nb_bits)].x;
+
+    return written;
+}
diff --git a/src/tans_encode_st.h b/src/tans_encode_st.h
new file mode 100644 (file)
index 0000000..e31ef79
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "tans_encode_tbl.h"
+#include "tans_bit_writer.h"
+
+struct tans_encode_st {
+    struct tans_symbol_tbl symbol_tbl;
+    struct tans_encode_tbl encode_tbl;
+    uint16_t x;
+};
+
+void tans_encode_st_init(struct tans_encode_st *self, const struct tans_symbol_tbl *symbol_tbl);
+uint16_t tans_encode_st_next(struct tans_encode_st *self, struct tans_bit_writer *bit_writer, uint8_t symbol);
diff --git a/src/tans_encode_tbl.c b/src/tans_encode_tbl.c
new file mode 100644 (file)
index 0000000..a60ebdc
--- /dev/null
@@ -0,0 +1,12 @@
+#include "tans_encode_tbl.h"
+
+void tans_encode_tbl_init(struct tans_encode_tbl *self, struct tans_symbol_tbl *symbol_tbl)
+{
+    uint8_t s;
+    uint16_t x;
+
+    for (x = TANS_L; x < TANS_L << 1; ++x) {
+        s = symbol_tbl->symbol[x-TANS_L];
+        self->entries[symbol_tbl->entries[s].start + symbol_tbl->entries[s].next++].x = x - TANS_L;
+    }
+}
diff --git a/src/tans_encode_tbl.h b/src/tans_encode_tbl.h
new file mode 100644 (file)
index 0000000..79ccf30
--- /dev/null
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "tans_constants.h"
+#include "tans_symbol_tbl.h"
+
+struct tans_encode_tbl_entry {
+    uint16_t x;
+};
+
+struct tans_encode_tbl {
+    // TODO verify size of entries table
+    struct tans_encode_tbl_entry entries[TANS_L];
+};
+
+void tans_encode_tbl_init(struct tans_encode_tbl *self, struct tans_symbol_tbl *symbol_tbl);
diff --git a/src/tans_file_bit_reader.c b/src/tans_file_bit_reader.c
new file mode 100644 (file)
index 0000000..fa79ddd
--- /dev/null
@@ -0,0 +1,56 @@
+#include "tans_file_bit_reader.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+static uint16_t tans_file_bit_reader_read(struct tans_bit_reader *reader, uint8_t bits)
+{
+    struct tans_file_bit_reader *self = (struct tans_file_bit_reader *) reader;
+    ssize_t bytes_read;
+    uint32_t bit = self->bit % 8;
+    uint32_t byte = self->bit / 8;
+
+    if (bits == 0) {
+        return (uint16_t) -1;
+    }
+
+    while (self->len * 8 - self->bit < bits) {
+        memmove(self->buf, self->buf + byte, self->len - byte);
+        bytes_read = read(self->fd, self->buf + self->len, sizeof self->buf - self->len);
+        if (bytes_read <= 0) {
+            return (uint16_t) -1;
+        }
+        self->len += (uint32_t) bytes_read;
+    }
+
+    self->bit += bits;
+
+    if (bit + bits <= 8) {
+        return (uint16_t) (((1 << bits) - 1) & (self->buf[byte] >> bit));
+    } else if (bit + bits <= 16) {
+        return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte] >> bit) | (self->buf[byte+1] << (8 - bit))));
+    } else if (bit + bits <= 24) {
+        return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte] >> bit) | ((self->buf[byte+1] | (self->buf[byte+2] << 8)) << (8 - bit))));
+    } else {
+        return (uint16_t) -1;
+    }
+}
+
+static const struct tans_bit_reader_ops vtable = {
+    .read = tans_file_bit_reader_read,
+};
+
+int tans_file_bit_reader_init(struct tans_file_bit_reader *self, const char *filename)
+{
+    self->vtable = &vtable;
+    self->fd = open(filename, O_RDONLY | O_CLOEXEC);
+    self->bit = 0;
+    self->len = 0;
+
+    if (self->fd == -1) {
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/src/tans_file_bit_reader.h b/src/tans_file_bit_reader.h
new file mode 100644 (file)
index 0000000..4e29dc3
--- /dev/null
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "tans_bit_reader.h"
+
+#define TANS_FILE_BIT_READER_BUFSZ 1024
+
+struct tans_file_bit_reader {
+    const struct tans_bit_reader_ops *vtable;
+    int fd;
+    uint32_t bit;
+    uint32_t len;
+    uint8_t buf[TANS_FILE_BIT_READER_BUFSZ];
+};
+
+int tans_file_bit_reader_init(struct tans_file_bit_reader *self, const char *filename);
diff --git a/src/tans_freq_tbl.h b/src/tans_freq_tbl.h
new file mode 100644 (file)
index 0000000..d2ff754
--- /dev/null
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <stdint.h>
+
+struct tans_freq_tbl {
+    uint16_t freq[256];
+};
diff --git a/src/tans_symbol_tbl.c b/src/tans_symbol_tbl.c
new file mode 100644 (file)
index 0000000..a1237b9
--- /dev/null
@@ -0,0 +1,32 @@
+#include "tans_symbol_tbl.h"
+
+#include "floor_log2.h"
+
+int tans_symbol_tbl_init(struct tans_symbol_tbl *self, const struct tans_freq_tbl *freq_tbl)
+{
+    uint16_t x, step, s, i, start, freq, k;
+
+    x = 0;
+    step = TANS_L*5/8 + 3;
+    start = 0;
+
+    for (s = 0; s < 256; ++s) {
+        freq = freq_tbl->freq[s];
+        self->entries[s].start = start;
+        self->entries[s].next = freq;
+        k = TANS_R - floor_log2(freq);
+        self->entries[s].nb = (uint16_t) ((k << (TANS_R + 1)) - (freq << k));
+        start += freq;
+        for (i = 0; i < freq; ++i) {
+            self->symbol[x] = (uint8_t) s;
+            x += step;
+            x %= TANS_L;
+        }
+    }
+
+    if (start != TANS_L) { // freq entries must add up to TANS_L
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/src/tans_symbol_tbl.h b/src/tans_symbol_tbl.h
new file mode 100644 (file)
index 0000000..985928c
--- /dev/null
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "tans_constants.h"
+#include "tans_freq_tbl.h"
+
+struct tans_symbol_tbl_entry {
+    uint16_t nb;
+    uint16_t start;
+    uint16_t next;
+};
+
+struct tans_symbol_tbl {
+    uint8_t symbol[TANS_L];
+    struct tans_symbol_tbl_entry entries[256];
+};
+
+int tans_symbol_tbl_init(struct tans_symbol_tbl *self, const struct tans_freq_tbl *freq_tbl);
diff --git a/test/test.h b/test/test.h
new file mode 100644 (file)
index 0000000..d9888ea
--- /dev/null
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <stdio.h>
+
+enum test_result {
+    TEST_SUCCESS = 0x100,
+    TEST_SKIP = 0x101,
+    TEST_FAILURE = 0x102,
+};
+
+#define ASSERT_EQ(lhs, rhs) do { \
+        long a = (long) (lhs), b = (long) (rhs); \
+        if ((a) != (b)) { \
+            printf("ERROR: " #lhs " (%ld) != " #rhs " (%ld)\n", (a), (b)); \
+            return TEST_FAILURE; \
+        } \
+    } while(0)
+
+#define ASSERT_NE(lhs, rhs) do { \
+        long a = (long) (lhs), b = (long) (rhs); \
+        if ((a) == (b)) { \
+            printf("ERROR: " #lhs " (%ld) == " #rhs " (%ld)\n", (a), (b)); \
+            return TEST_FAILURE; \
+        } \
+    } while(0)
+
+#define RUN_TEST(test_fn) switch (test_fn()) { \
+    case TEST_SUCCESS: printf("PASS: " #test_fn "\n"); break; \
+    case TEST_SKIP:    printf("SKIP: " #test_fn "\n"); break; \
+    case TEST_FAILURE: printf("FAIL: " #test_fn "\n"); return 1; \
+    default:           printf("FAIL: " #test_fn "\n"); return 1; \
+}
+
diff --git a/test/test_tans_bit_reader b/test/test_tans_bit_reader
new file mode 100755 (executable)
index 0000000..1f43ac2
Binary files /dev/null and b/test/test_tans_bit_reader differ
diff --git a/test/test_tans_bit_reader.c b/test/test_tans_bit_reader.c
new file mode 100644 (file)
index 0000000..f94a931
--- /dev/null
@@ -0,0 +1,49 @@
+#include "test.h"
+
+#include "tans_buf_bit_reader.h"
+#include "tans_file_bit_reader.h"
+
+enum test_result test_tans_buf_bit_reader(void)
+{
+    struct tans_buf_bit_reader bit_reader;
+    uint8_t buf[8] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0xfd, 0x08, 0xfc};
+
+    tans_buf_bit_reader_init(&bit_reader, buf, sizeof buf);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 0), (uint16_t) -1);
+
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 8), 1);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 4), 0xf);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 6), 0x2f);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 2), 0);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 16), 0x3fe0);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 8), 0xd0);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 7), 0x0f);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 1), 1);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 3), 0);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 5), 0x18);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 4), 0xf);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 1), (uint16_t) -1);
+
+    return TEST_SUCCESS;
+}
+
+enum test_result test_tans_file_bit_reader(void)
+{
+    struct tans_file_bit_reader bit_reader;
+    uint8_t bits;
+
+    ASSERT_EQ(tans_file_bit_reader_init(&bit_reader, "/dev/zero"), 0);
+    ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 0), (uint16_t) -1);
+
+    for (bits = 1; bits <= 16; ++bits) {
+        ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, bits), 0);
+    }
+
+    return TEST_SUCCESS;
+}
+
+int main(void)
+{
+    RUN_TEST(test_tans_buf_bit_reader);
+    RUN_TEST(test_tans_file_bit_reader);
+}
diff --git a/test/test_tans_bit_writer b/test/test_tans_bit_writer
new file mode 100755 (executable)
index 0000000..e8fe9ba
Binary files /dev/null and b/test/test_tans_bit_writer differ
diff --git a/test/test_tans_bit_writer.c b/test/test_tans_bit_writer.c
new file mode 100644 (file)
index 0000000..b31177b
--- /dev/null
@@ -0,0 +1,42 @@
+#include "test.h"
+
+#include "tans_buf_bit_writer.h"
+
+enum test_result test_tans_buf_bit_writer(void)
+{
+    struct tans_buf_bit_writer buf_bit_writer;
+    struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer;
+    uint8_t buf[8] = {0};
+
+    tans_buf_bit_writer_init(&buf_bit_writer, buf, sizeof buf);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 0), 0);
+
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 1, 8), 8);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xf, 4), 4);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x2f, 6), 6);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 2), 2);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x3fe0, 16), 16);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xd0, 8), 8);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x0f, 7), 7);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 1, 1), 1);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 3), 3);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x18, 5), 5);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xf, 4), 4);
+    ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 1), (uint16_t) -1);
+
+    ASSERT_EQ(buf[0], 0x01);
+    ASSERT_EQ(buf[1], 0xff);
+    ASSERT_EQ(buf[2], 0x02);
+    ASSERT_EQ(buf[3], 0xfe);
+    ASSERT_EQ(buf[4], 0x03);
+    ASSERT_EQ(buf[5], 0xfd);
+    ASSERT_EQ(buf[6], 0x08);
+    ASSERT_EQ(buf[7], 0xfc);
+
+    return TEST_SUCCESS;
+}
+
+int main(void)
+{
+    RUN_TEST(test_tans_buf_bit_writer);
+}
diff --git a/test/test_tans_encode_st b/test/test_tans_encode_st
new file mode 100755 (executable)
index 0000000..5721161
Binary files /dev/null and b/test/test_tans_encode_st differ
diff --git a/test/test_tans_encode_st.c b/test/test_tans_encode_st.c
new file mode 100644 (file)
index 0000000..a7bb884
--- /dev/null
@@ -0,0 +1,37 @@
+#include "test.h"
+
+#include "tans_buf_bit_writer.h"
+#include "tans_encode_st.h"
+
+enum test_result test_tans_encode_st_equal_freq(void)
+{
+    struct tans_freq_tbl freq_tbl;
+    struct tans_symbol_tbl symbol_tbl;
+    struct tans_encode_st encode_st;
+    struct tans_buf_bit_writer buf_bit_writer;
+    struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer;
+    uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+    uint8_t buf[8] = {0};
+    uint16_t i;
+
+    for (i = 0; i < 256; ++i) {
+        freq_tbl.freq[i] = TANS_L / 256;
+    }
+    ASSERT_EQ(tans_symbol_tbl_init(&symbol_tbl, &freq_tbl), 0);
+    tans_encode_st_init(&encode_st, &symbol_tbl);
+    tans_buf_bit_writer_init(&buf_bit_writer, buf, sizeof buf);
+
+    for (i = 0; i < sizeof data; ++i) {
+        ASSERT_NE(tans_encode_st_next(&encode_st, bit_writer, data[i]), (uint16_t) -1);
+    }
+
+    ASSERT_EQ(buf_bit_writer.bit, buf_bit_writer.len * 8);
+    ASSERT_EQ(tans_encode_st_next(&encode_st, bit_writer, 0), (uint16_t) -1);
+
+    return TEST_SUCCESS;
+}
+
+int main(void)
+{
+    RUN_TEST(test_tans_encode_st_equal_freq);
+}