+
+typedef struct _reader
+{
+ int (*read)(struct _reader*, void*data, int len);
+ void (*dealloc)(struct _reader*);
+ void *internal;
+ int pos;
+} reader_t;
+
+/* ---------------------------- mem reader ------------------------------- */
+
+struct memread_t
+{
+ unsigned char*data;
+ int length;
+};
+static int reader_memread(reader_t*reader, void* data, int _len)
+{
+ struct memread_t*mr = (struct memread_t*)reader->internal;
+
+ int len = _len;
+ if(mr->length - reader->pos < len) {
+ len = mr->length - reader->pos;
+ }
+ memcpy(data, &mr->data[reader->pos], len);
+ msg("at pos %d, asked to read %d bytes, did read %d bytes\n", reader->pos, _len, len);
+ reader->pos += len;
+ return len;
+}
+static void reader_memread_dealloc(reader_t*reader)
+{
+ if(reader->internal)
+ free(reader->internal);
+ memset(reader, 0, sizeof(reader_t));
+}
+reader_t*reader_init_memreader(void*newdata, int newlength)
+{
+ reader_t*r = malloc(sizeof(reader_t));
+ struct memread_t*mr = (struct memread_t*)malloc(sizeof(struct memread_t));
+ mr->data = (unsigned char*)newdata;
+ mr->length = newlength;
+ r->read = reader_memread;
+ r->dealloc = reader_memread_dealloc;
+ r->internal = (void*)mr;
+ r->pos = 0;
+ return r;
+}
+
+
+/* ---------------------------- zlibinflate reader -------------------------- */
+struct zlibinflate_t
+{
+ z_stream zs;
+ reader_t*input;
+ unsigned char readbuffer[ZLIB_BUFFER_SIZE];
+};
+
+static void zlib_error(int ret, char* msg, z_stream*zs)
+{
+ fprintf(stderr, "%s: zlib error (%d): last zlib error: %s\n", msg, ret, zs->msg?zs->msg:"unknown");
+ perror("errno:");
+ exit(1);
+}
+
+static int reader_zlibinflate(reader_t*reader, void* data, int len)
+{
+ struct zlibinflate_t*z = (struct zlibinflate_t*)reader->internal;
+ int ret;
+ if(!z) {
+ return 0;
+ }
+ if(!len)
+ return 0;
+
+ z->zs.next_out = (Bytef *)data;
+ z->zs.avail_out = len;
+
+ while(1) {
+ if(!z->zs.avail_in) {
+ z->zs.avail_in = z->input->read(z->input, z->readbuffer, ZLIB_BUFFER_SIZE);
+ z->zs.next_in = z->readbuffer;
+ }
+ if(z->zs.avail_in)
+ ret = inflate(&z->zs, Z_NO_FLUSH);
+ else
+ ret = inflate(&z->zs, Z_FINISH);
+
+ if (ret != Z_OK &&
+ ret != Z_STREAM_END) zlib_error(ret, "bitio:inflate_inflate", &z->zs);
+
+ if (ret == Z_STREAM_END) {
+ int pos = z->zs.next_out - (Bytef*)data;
+ ret = inflateEnd(&z->zs);
+ if (ret != Z_OK) zlib_error(ret, "bitio:inflate_end", &z->zs);
+ free(reader->internal);
+ reader->internal = 0;
+ reader->pos += pos;
+ return pos;
+ }
+ if(!z->zs.avail_out) {
+ break;
+ }
+ }
+ reader->pos += len;
+ return len;
+}
+static void reader_zlibinflate_dealloc(reader_t*reader)
+{
+ struct zlibinflate_t*z = (struct zlibinflate_t*)reader->internal;
+ if(z) {
+ if(z->input) {
+ z->input->dealloc(z->input);z->input = 0;
+ }
+ inflateEnd(&z->zs);
+ free(reader->internal);
+ }
+ memset(reader, 0, sizeof(reader_t));
+}
+reader_t* reader_init_zlibinflate(reader_t*input)
+{
+ reader_t*r = malloc(sizeof(reader_t));
+ struct zlibinflate_t*z;
+ int ret;
+ memset(r, 0, sizeof(reader_t));
+ z = (struct zlibinflate_t*)malloc(sizeof(struct zlibinflate_t));
+ memset(z, 0, sizeof(struct zlibinflate_t));
+ r->internal = z;
+ r->read = reader_zlibinflate;
+ r->dealloc = reader_zlibinflate_dealloc;
+ r->pos = 0;
+ z->input = input;
+ memset(&z->zs,0,sizeof(z_stream));
+ z->zs.zalloc = Z_NULL;
+ z->zs.zfree = Z_NULL;
+ z->zs.opaque = Z_NULL;
+ ret = inflateInit(&z->zs);
+ if (ret != Z_OK) zlib_error(ret, "bitio:inflate_init", &z->zs);
+ return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+