aboutsummaryrefslogtreecommitdiff
path: root/lpg/libqr/bitstream.c
diff options
context:
space:
mode:
authorLeo Howell <leo@lwh.jp>2009-09-05 09:33:22 +0900
committerLeo Howell <leo@lwh.jp>2009-09-05 09:33:22 +0900
commitef01767c732629b7eff7d1601e76a1bac58f5bfd (patch)
treeac29871fd3c6f1bab8dc8e3c51e33292d5544a96 /lpg/libqr/bitstream.c
downloadpdf-simple-sign-ef01767c732629b7eff7d1601e76a1bac58f5bfd.tar.gz
pdf-simple-sign-ef01767c732629b7eff7d1601e76a1bac58f5bfd.tar.xz
pdf-simple-sign-ef01767c732629b7eff7d1601e76a1bac58f5bfd.zip
The story so far
Diffstat (limited to 'lpg/libqr/bitstream.c')
-rw-r--r--lpg/libqr/bitstream.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/lpg/libqr/bitstream.c b/lpg/libqr/bitstream.c
new file mode 100644
index 0000000..a2b2b58
--- /dev/null
+++ b/lpg/libqr/bitstream.c
@@ -0,0 +1,203 @@
+/**
+ * It would perhaps be more sensible just to store the bits
+ * as an array of char or similar, but this way is more fun.
+ * This is a pretty inefficient implementation, althought I
+ * suspect that won't be a problem.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "bitstream.h"
+
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+struct bitstream {
+ size_t pos; /* bits */
+ size_t count; /* bits */
+ size_t bufsiz; /* bytes */
+ unsigned char * buffer;
+};
+
+static size_t bits_to_bytes(size_t bits)
+{
+ return (bits / CHAR_BIT) + (bits % CHAR_BIT != 0);
+}
+
+static int ensure_available(struct bitstream * stream, size_t bits)
+{
+ size_t need_bits = stream->pos + bits;
+ size_t need_bytes = need_bits / CHAR_BIT + ((need_bits % CHAR_BIT) ? 0 : 1);
+ size_t newsize;
+
+ if (stream->bufsiz >= need_bytes)
+ return 0;
+
+ newsize = MAX(stream->bufsiz, 100);
+ while (newsize < need_bytes)
+ newsize *= 2;
+
+ return bitstream_resize(stream, newsize);
+}
+
+struct bitstream * bitstream_create(void)
+{
+ struct bitstream * obj;
+
+ obj = malloc(sizeof(*obj));
+
+ if (obj) {
+ obj->pos = 0;
+ obj->count = 0;
+ obj->bufsiz = 0;
+ obj->buffer = 0;
+ }
+
+ return obj;
+}
+
+int bitstream_resize(struct bitstream * stream, size_t bits)
+{
+ size_t newsize;
+ void * newbuf;
+
+ newsize = bits_to_bytes(bits);
+ newbuf = realloc(stream->buffer, newsize);
+
+ if (newbuf) {
+ stream->bufsiz = newsize;
+ stream->buffer = newbuf;
+ }
+
+ return newbuf ? 0 : -1;
+}
+
+void bitstream_destroy(struct bitstream * stream)
+{
+ free(stream->buffer);
+ free(stream);
+}
+
+struct bitstream * bitstream_copy(const struct bitstream * src)
+{
+ struct bitstream * ret;
+
+ ret = bitstream_create();
+ if (!ret)
+ return 0;
+
+ if (bitstream_resize(ret, src->count) != 0) {
+ free(ret);
+ return 0;
+ }
+
+ ret->pos = src->pos;
+ ret->count = src->count;
+ memcpy(ret->buffer, src->buffer, src->bufsiz);
+
+ return ret;
+}
+
+void bitstream_seek(struct bitstream * stream, size_t pos)
+{
+ assert(pos <= stream->count);
+ stream->pos = pos;
+}
+
+size_t bitstream_tell(const struct bitstream * stream)
+{
+ return stream->pos;
+}
+
+size_t bitstream_remaining(const struct bitstream * stream)
+{
+ return stream->count - stream->pos;
+}
+
+size_t bitstream_size(const struct bitstream * stream)
+{
+ return stream->count;
+}
+
+unsigned int bitstream_read(struct bitstream * stream, size_t bits)
+{
+ unsigned int result = 0;
+ unsigned char * byte;
+ size_t bitnum;
+
+ assert(bitstream_remaining(stream) >= bits);
+
+ byte = stream->buffer + (stream->pos / CHAR_BIT);
+ bitnum = stream->pos % CHAR_BIT;
+
+ stream->pos += bits;
+
+ while (bits-- > 0) {
+ int bit = (*byte >> bitnum++) & 0x1;
+ result = (result << 1) | bit;
+ if (bitnum == CHAR_BIT) {
+ bitnum = 0;
+ ++byte;
+ }
+ }
+
+ return result;
+}
+
+void bitstream_unpack(struct bitstream * stream,
+ unsigned int * result,
+ size_t count,
+ size_t bitsize)
+{
+ assert(bitstream_remaining(stream) >= (count * bitsize));
+
+ while (count--)
+ *(result++) = bitstream_read(stream, bitsize);
+}
+
+int bitstream_write(struct bitstream * stream,
+ unsigned int value,
+ size_t bits)
+{
+ unsigned char * byte;
+ size_t bitnum;
+
+ if (ensure_available(stream, bits) != 0)
+ return -1;
+
+ byte = stream->buffer + (stream->pos / CHAR_BIT);
+ bitnum = stream->pos % CHAR_BIT;
+
+ stream->pos += bits;
+ stream->count = stream->pos; /* truncate */
+
+ while (bits-- > 0) {
+ int bit = (value >> bits) & 0x1;
+ unsigned char mask = 1 << bitnum++;
+ *byte = (*byte & ~mask) | (bit ? mask : 0);
+ if (bitnum == CHAR_BIT) {
+ bitnum = 0;
+ ++byte;
+ }
+ }
+
+ return 0;
+}
+
+int bitstream_pack(struct bitstream * stream,
+ const unsigned int * values,
+ size_t count,
+ size_t bitsize)
+{
+ if (ensure_available(stream, count * bitsize) != 0)
+ return -1;
+
+ while (count--)
+ bitstream_write(stream, *(values++), bitsize);
+
+ return 0;
+}
+