shithub: jbig2

Download patch

ref: 0a9304dad738268b27556717bf83936c15618506
parent: 3a77ab1dd49743f0ed9cc0ad862671f462781bd1
author: raph <raph@ded80894-8fb9-0310-811b-c03f3676ab4d>
date: Wed Feb 13 03:47:18 EST 2002

Implementation of new API as discussed on jbig2-dev. Not all logic
of existing jbig2dec.c has been ported to new codebase - in
particular, jbig2_read_symbol_dictionary and jbig2_read_page_info.


git-svn-id: http://svn.ghostscript.com/jbig2dec/trunk@41 ded80894-8fb9-0310-811b-c03f3676ab4d

--- /dev/null
+++ b/jbig2.c
@@ -1,0 +1,368 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include "jbig2.h"
+#include "jbig2_priv.h"
+
+static void *
+jbig2_default_alloc (Jbig2Allocator *allocator, size_t size)
+{
+  return malloc (size);
+}
+
+static void
+jbig2_default_free (Jbig2Allocator *allocator, void *p)
+{
+  free (p);
+}
+
+static void *
+jbig2_default_realloc (Jbig2Allocator *allocator, void *p, size_t size)
+{
+  return realloc (p, size);
+}
+
+static Jbig2Allocator jbig2_default_allocator =
+{
+  jbig2_default_alloc,
+  jbig2_default_free,
+  jbig2_default_realloc
+};
+
+void *
+jbig2_alloc (Jbig2Allocator *allocator, size_t size)
+{
+  return allocator->alloc (allocator, size);
+}
+
+void
+jbig2_free (Jbig2Allocator *allocator, void *p)
+{
+  allocator->free (allocator, p);
+}
+
+void *
+jbig2_realloc (Jbig2Allocator *allocator, void *p, size_t size)
+{
+  return allocator->realloc (allocator, p, size);
+}
+
+int
+jbig2_error (Jbig2Ctx *ctx, Jbig2Severity severity, int seg_idx,
+	     const char *fmt, ...)
+{
+  char buf[1024];
+  va_list ap;
+  int n;
+
+  va_start (ap, fmt);
+  n = vsnprintf (buf, sizeof(buf), fmt, ap);
+  va_end (ap);
+  if (n < 0 || n == sizeof(buf))
+    strcpy (buf, "jbig2_error: error in generating error string");
+  return ctx->error_callback (ctx->error_callback_data, buf, severity, seg_idx);
+}
+
+Jbig2Ctx *
+jbig2_ctx_new (Jbig2Allocator *allocator,
+	       Jbig2Options options,
+	       Jbig2GlobalCtx *global_ctx,
+	       Jbig2ErrorCallback error_callback,
+	       void *error_callback_data)
+{
+  Jbig2Ctx *result;
+
+  if (allocator == NULL)
+      allocator = &jbig2_default_allocator;
+
+  result = (Jbig2Ctx *)jbig2_alloc (allocator, sizeof(Jbig2Ctx));
+  result->allocator = allocator;
+  result->options = options;
+  result->global_ctx = (const Jbig2Ctx *)global_ctx;
+  result->error_callback = error_callback;
+  result->error_callback_data = error_callback_data;
+
+  result->state = (options & JBIG2_OPTIONS_EMBEDDED) ?
+    JBIG2_FILE_SEQUENTIAL_HEADER :
+    JBIG2_FILE_HEADER;
+
+  result->buf = NULL;
+  result->sh_list = NULL;
+  result->n_sh = 0;
+  result->n_sh_max = 1;
+  result->sh_ix = 0;
+  return result;
+}
+
+static int32_t
+jbig2_get_int32 (uint8_t *buf)
+{
+  return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+static Jbig2SegmentHeader *
+jbig2_parse_segment_header (Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size,
+			    size_t *p_header_size)
+{
+  Jbig2SegmentHeader *result;
+  byte	rtscarf;
+  int32_t rtscarf_long;
+  int referred_to_segment_count;
+  int referred_to_segment_size;
+  int pa_size;
+  int offset;
+
+  /* minimum possible size of a jbig2 segment header */
+  if (buf_size < 11)
+    return NULL;
+
+  result = (Jbig2SegmentHeader *)jbig2_alloc(ctx->allocator,
+					     sizeof(Jbig2SegmentHeader));
+
+  /* 7.2.2 */
+  result->segment_number = jbig2_get_int32 (buf);
+
+  /* 7.2.3 */
+  result->flags = buf[4];
+
+  /* 7.2.4 */
+  rtscarf = buf[5];
+  if ((rtscarf & 0xe0) == 0xe0)
+    {
+      rtscarf_long = jbig2_get_int32(buf + 5);
+      referred_to_segment_count = rtscarf_long & 0x1fffffff;
+      offset = 5 + 4 + (referred_to_segment_count + 1) / 8;
+    }
+  else
+    {
+      referred_to_segment_count = (rtscarf >> 5);
+      offset = 5 + 1;
+    }
+  result->referred_to_segment_count = referred_to_segment_count;
+
+  /* 7.2.5 */
+  /* todo: read referred to segment numbers */
+  /* For now, we skip them. */
+  referred_to_segment_size = result->segment_number <= 256 ? 1:
+    result->segment_number <= 65536 ? 2:
+    4;
+  offset += referred_to_segment_count * referred_to_segment_size;
+
+  /* 7.2.6 */
+  pa_size = result->flags & 0x40 ? 4 : 1;
+
+  if (offset + pa_size + 4 > buf_size)
+    {
+      jbig2_free (ctx->allocator, result);
+      return NULL;
+    }
+
+  if (result->flags & 0x40) {
+	result->page_association = jbig2_get_int32(buf + offset);
+	offset += 4;
+  } else {
+	result->page_association = buf[offset++];
+  }
+  
+  /* 7.2.7 */
+  result->data_length = jbig2_get_int32 (buf + offset);
+  *p_header_size = offset + 4;
+
+  return result;
+}
+
+void
+jbig2_free_segment_header (Jbig2Ctx *ctx, Jbig2SegmentHeader *sh)
+{
+  jbig2_free (ctx->allocator, sh);
+}
+
+int
+jbig2_write (Jbig2Ctx *ctx, const unsigned char *data, size_t size)
+{
+  const int initial_buf_size = 1024;
+
+  if (ctx->buf == NULL)
+    {
+      int buf_size = initial_buf_size;
+
+      do
+	buf_size <<= 1;
+      while (buf_size < size);
+      ctx->buf = (byte *)jbig2_alloc (ctx->allocator, size);
+      ctx->buf_size = buf_size;
+      ctx->buf_rd_ix = 0;
+      ctx->buf_wr_ix = 0;
+    }
+  else if (ctx->buf_wr_ix + size > ctx->buf_size)
+    {
+      if (ctx->buf_rd_ix <= (ctx->buf_size >> 1) &&
+	  ctx->buf_wr_ix - ctx->buf_rd_ix + size <= ctx->buf_size)
+	{
+	  memcpy (ctx->buf, ctx->buf + ctx->buf_rd_ix,
+		  ctx->buf_wr_ix - ctx->buf_rd_ix);
+	}
+      else
+	{
+	  byte *buf;
+	  int buf_size = initial_buf_size;
+	  
+	  do
+	    buf_size <<= 1;
+	  while (buf_size < ctx->buf_wr_ix - ctx->buf_rd_ix + size);
+	  buf = (byte *)jbig2_alloc (ctx->allocator, buf_size);
+	  memcpy (buf, ctx->buf + ctx->buf_rd_ix,
+		  ctx->buf_wr_ix - ctx->buf_rd_ix);
+	  jbig2_free (ctx->allocator, ctx->buf);
+	  ctx->buf = buf;
+	  ctx->buf_size = buf_size;
+	}
+      ctx->buf_wr_ix -= ctx->buf_rd_ix;
+      ctx->buf_rd_ix = 0;
+    }
+  memcpy (ctx->buf + ctx->buf_wr_ix, data, size);
+  ctx->buf_wr_ix += size;
+
+  /* data has now been added to buffer */
+
+  for (;;)
+    {
+      const byte jbig2_id_string[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a };
+      Jbig2SegmentHeader *sh;
+      size_t header_size;
+      int code;
+
+      switch (ctx->state)
+	{
+	case JBIG2_FILE_HEADER:
+	  if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9)
+	    return 0;
+	  if (memcmp(ctx->buf + ctx->buf_rd_ix, jbig2_id_string, 8))
+	    {
+	      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+			  "Not a JBIG2 file header");
+	      return -1;
+	    }
+	  ctx->file_header_flags = ctx->buf[ctx->buf_rd_ix + 8];
+	  if (!(ctx->file_header_flags & 2))
+	    {
+	      if (ctx->buf_wr_ix - ctx->buf_rd_ix < 13)
+		return 0;
+	      ctx->n_pages = jbig2_get_int32(ctx->buf + ctx->buf_rd_ix + 9);
+	      ctx->buf_rd_ix += 13;
+	    }
+	  else
+	    ctx->buf_rd_ix += 9;
+	  if (ctx->file_header_flags & 1)
+	    {
+	      ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
+	    }
+	  else
+	    {
+	      ctx->state = JBIG2_FILE_RANDOM_HEADERS;
+	      ctx->n_sh_max = 16;
+	    }
+	  break;
+	case JBIG2_FILE_SEQUENTIAL_HEADER:
+	case JBIG2_FILE_RANDOM_HEADERS:
+	  sh = jbig2_parse_segment_header(ctx, ctx->buf + ctx->buf_rd_ix,
+					  ctx->buf_wr_ix - ctx->buf_rd_ix,
+					  &header_size);
+	  if (sh == NULL)
+	    return 0;
+	  ctx->buf_rd_ix += header_size;
+
+	  if (ctx->sh_list == NULL)
+	      ctx->sh_list = jbig2_alloc(ctx->allocator, ctx->n_sh_max *
+				     sizeof(Jbig2SegmentHeader *));
+	  else if (ctx->n_sh == ctx->n_sh_max)
+	    /* Note to rillian: I usually define a macro to make this
+	       less ungainly. */
+	    ctx->sh_list = (Jbig2SegmentHeader **)jbig2_realloc(ctx->allocator,
+								ctx->sh_list,
+								(ctx->n_sh_max <<= 2) * sizeof(Jbig2SegmentHeader *));
+
+	  ctx->sh_list[ctx->n_sh++] = sh;
+	  if (ctx->state == JBIG2_FILE_RANDOM_HEADERS)
+	    {
+	      if ((sh->flags & 63) == 51) /* end of file */
+		ctx->state = JBIG2_FILE_RANDOM_BODIES;
+	    }
+	  else
+	    ctx->state = JBIG2_FILE_SEQUENTIAL_BODY;
+	  break;
+	case JBIG2_FILE_SEQUENTIAL_BODY:
+	case JBIG2_FILE_RANDOM_BODIES:
+	  sh = ctx->sh_list[ctx->sh_ix];
+	  if (sh->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix)
+	    return 0;
+	  code = jbig2_write_segment(ctx, sh, ctx->buf + ctx->buf_rd_ix);
+	  ctx->buf_rd_ix += sh->data_length;
+	  jbig2_free_segment_header(ctx, sh);
+	  ctx->sh_list[ctx->sh_ix] = NULL;
+	  if (ctx->state == JBIG2_FILE_RANDOM_BODIES)
+	    {
+	      ctx->sh_ix++;
+	      if (ctx->sh_ix == ctx->n_sh)
+		ctx->state = JBIG2_FILE_EOF;
+	    }
+	  else
+	    {
+	      ctx->n_sh = 0;
+	      ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
+	    }
+	  if (code < 0)
+	    {
+	      ctx->state = JBIG2_FILE_EOF;
+	      return code;
+	    }
+	  break;
+	case JBIG2_FILE_EOF:
+	  if (ctx->buf_rd_ix == ctx->buf_wr_ix)
+	    return 0;
+	  jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1,
+		      "Garbage beyond end of file");
+	  return -1;
+	}
+    }
+  return 0;
+}
+
+/* get_bits */
+
+void
+jbig2_ctx_free (Jbig2Ctx *ctx)
+{
+  Jbig2Allocator *ca = ctx->allocator;
+  int i;
+
+  jbig2_free(ca, ctx->buf);
+  if (ctx->sh_list != NULL)
+    {
+      for (i = ctx->sh_ix; i < ctx->n_sh; i++)
+	jbig2_free_segment_header(ctx, ctx->sh_list[i]);
+      jbig2_free(ca, ctx->sh_list);
+    }
+  jbig2_free(ca, ctx);
+}
+
+Jbig2GlobalCtx *jbig2_make_global_ctx (Jbig2Ctx *ctx)
+{
+  return (Jbig2GlobalCtx *)ctx;
+}
+
+void jbig2_global_ctx_free(Jbig2GlobalCtx *global_ctx)
+{
+  jbig2_ctx_free((Jbig2Ctx *)global_ctx);
+}
+
+int jbig2_write_segment (Jbig2Ctx *ctx, Jbig2SegmentHeader *sh,
+			 const uint8_t *segment_data)
+{
+  jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number,
+	      "Segment %d, flags=%x, type=%d, data_length=%d",
+	      sh->segment_number, sh->flags, sh->flags & 63,
+	      sh->data_length);
+  return 0;
+}
--- /dev/null
+++ b/jbig2.h
@@ -1,0 +1,59 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  JBIG2_SEVERITY_INFO,
+  JBIG2_SEVERITY_WARNING,
+  JBIG2_SEVERITY_FATAL
+} Jbig2Severity;
+
+typedef enum {
+  JBIG2_OPTIONS_EMBEDDED = 1
+} Jbig2Options;
+
+typedef struct _Jbig2Allocator Jbig2Allocator;
+typedef struct _Jbig2Ctx Jbig2Ctx;
+typedef struct _Jbig2GlobalCtx Jbig2GlobalCtx;
+typedef struct _Jbig2SegmentHeader Jbig2SegmentHeader;
+
+struct _Jbig2SegmentHeader {
+  int32_t segment_number;
+  uint8_t flags;
+  int referred_to_segment_count;
+  int32_t page_association;
+  int data_length;
+};
+
+typedef int (*Jbig2ErrorCallback) (void *data,
+				  const char *msg, Jbig2Severity severity,
+				  int32_t seg_idx);
+
+struct _Jbig2Allocator {
+  void *(*alloc) (Jbig2Allocator *allocator, size_t size);
+  void (*free) (Jbig2Allocator *allocator, void *p);
+  void *(*realloc) (Jbig2Allocator *allocator, void *p, size_t size);
+};
+
+Jbig2Ctx *jbig2_ctx_new (Jbig2Allocator *allocator,
+			 Jbig2Options options,
+			 Jbig2GlobalCtx *global_ctx,
+			 Jbig2ErrorCallback error_callback,
+			 void *error_callback_data);
+
+int jbig2_write (Jbig2Ctx *ctx, const unsigned char *data, size_t size);
+
+/* get_bits */
+
+void jbig2_ctx_free (Jbig2Ctx *ctx);
+
+Jbig2GlobalCtx *jbig2_make_global_ctx (Jbig2Ctx *ctx);
+
+void jbig2_global_ctx_free (Jbig2GlobalCtx *global_ctx);
+
+int jbig2_write_segment (Jbig2Ctx *ctx, Jbig2SegmentHeader *sh,
+			 const uint8_t *segment_data);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+++ b/jbig2_priv.h
@@ -1,0 +1,47 @@
+void *
+jbig2_alloc (Jbig2Allocator *allocator, size_t size);
+
+void
+jbig2_free (Jbig2Allocator *allocator, void *p);
+
+void *
+jbig2_realloc (Jbig2Allocator *allocator, void *p, size_t size);
+
+int
+jbig2_error (Jbig2Ctx *ctx, Jbig2Severity severity, int32_t seg_idx,
+	     const char *fmt, ...);
+
+typedef uint8_t byte;
+
+typedef enum {
+  JBIG2_FILE_HEADER,
+  JBIG2_FILE_SEQUENTIAL_HEADER,
+  JBIG2_FILE_SEQUENTIAL_BODY,
+  JBIG2_FILE_RANDOM_HEADERS,
+  JBIG2_FILE_RANDOM_BODIES,
+  JBIG2_FILE_EOF
+} Jbig2FileState;
+
+struct _Jbig2Ctx {
+  Jbig2Allocator *allocator;
+  Jbig2Options options;
+  const Jbig2Ctx *global_ctx;
+  Jbig2ErrorCallback error_callback;
+  void *error_callback_data;
+
+  byte *buf;
+  int buf_size;
+  int buf_rd_ix;
+  int buf_wr_ix;
+
+  Jbig2FileState state;
+
+  byte file_header_flags;
+  int32_t n_pages;
+
+  int n_sh;
+  int n_sh_max;
+  Jbig2SegmentHeader **sh_list;
+  int sh_ix;
+};
+
--- a/jbig2dec.c
+++ b/jbig2dec.c
@@ -8,21 +8,23 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 
-    $Id: jbig2dec.c,v 1.12 2002/02/12 02:19:36 giles Exp $
+    $Id: jbig2dec.c,v 1.13 2002/02/13 08:47:18 raph Exp $
 */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 
+#include "jbig2.h"
 #include "jbig2dec.h"
 
-typedef struct _Jbig2SegmentHeader Jbig2SegmentHeader;
+#ifdef DEAD_CODE
 typedef struct _Jbig2SymbolDictionary Jbig2SymbolDictionary;
 typedef struct _Jbig2PageInfo Jbig2PageInfo;
 
 /* our main 'context' structure for decoding a jbig2 bitstream */
-struct _Jbig2Ctx {
+struct _Jbig2Ctx_foo {
   FILE *f;
   int offset;
   int eof;
@@ -36,14 +38,6 @@
 #define JBIG2_FILE_FLAGS_PAGECOUNT_UNKNOWN	0x02
 
 
-struct _Jbig2SegmentHeader {
-  int32 segment_number;
-  byte flags;
-  int referred_to_segment_count;
-  int32 page_association;
-  int data_length;
-};
-
 struct _Jbig2SymbolDictionary {
   int16 flags;
   int8 SDAT_flags[8];
@@ -62,7 +56,7 @@
 };
 
 int32
-get_bytes (Jbig2Ctx *ctx, byte *buf, int size, int off)
+get_bytes (Jbig2Ctx_foo *ctx, byte *buf, int size, int off)
 {
   int n_bytes;
 
@@ -74,7 +68,7 @@
 }
 
 int16
-get_int16 (Jbig2Ctx *ctx, int off)
+get_int16 (Jbig2Ctx_foo *ctx, int off)
 {
   byte buf[2];
 
@@ -83,7 +77,7 @@
 }
 
 byte
-get_byte (Jbig2Ctx *ctx, int off)
+get_byte (Jbig2Ctx_foo *ctx, int off)
 {
   byte buf;
   
@@ -92,7 +86,7 @@
 }
 
 int32
-get_int32 (Jbig2Ctx *ctx, int off)
+get_int32 (Jbig2Ctx_foo *ctx, int off)
 {
   byte buf[4];
 
@@ -100,15 +94,15 @@
   return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
 }
 
-static Jbig2Ctx *
+static Jbig2Ctx_foo *
 jbig2_open (FILE *f)
 {
   byte buf[9];
   const byte header[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a };
-  Jbig2Ctx *ctx;
+  Jbig2Ctx_foo *ctx;
 
   /* Annex D.4 */
-  ctx = (Jbig2Ctx *)malloc(sizeof(Jbig2Ctx));
+  ctx = (Jbig2Ctx_foo *)malloc(sizeof(Jbig2Ctx_foo));
   ctx->f = f;
   ctx->eof = FALSE;
   get_bytes(ctx, buf, 9, 0);
@@ -139,12 +133,12 @@
   return ctx;
 }
 
-static Jbig2Ctx *
+static Jbig2Ctx_foo *
 jbig2_open_embedded (FILE *f_globals, FILE *f_page)
 {
-  Jbig2Ctx *ctx;
+  Jbig2Ctx_foo *ctx;
 
-  ctx = (Jbig2Ctx *)malloc(sizeof(Jbig2Ctx));
+  ctx = (Jbig2Ctx_foo *)malloc(sizeof(Jbig2Ctx_foo));
   ctx->f = f_globals;
   ctx->eof = 0;
   ctx->offset = 0;
@@ -152,7 +146,7 @@
 }
 
 static Jbig2SegmentHeader *
-jbig2_read_segment_header (Jbig2Ctx *ctx)
+jbig2_read_segment_header (Jbig2Ctx_foo *ctx)
 {
   Jbig2SegmentHeader *result = (Jbig2SegmentHeader *)malloc(sizeof(Jbig2SegmentHeader));
   int	offset = ctx->offset;
@@ -216,7 +210,7 @@
    segment header.
 */
 static Jbig2SymbolDictionary *
-jbig2_read_symbol_dictionary (Jbig2Ctx *ctx)
+jbig2_read_symbol_dictionary (Jbig2Ctx_foo *ctx)
 {
   Jbig2SymbolDictionary *result = (Jbig2SymbolDictionary *)malloc(sizeof(Jbig2SymbolDictionary));
   int offset = ctx->offset;
@@ -282,7 +276,7 @@
    segment header.
 */
 static Jbig2PageInfo *
-jbig2_read_page_info (Jbig2Ctx *ctx) {
+jbig2_read_page_info (Jbig2Ctx_foo *ctx) {
   Jbig2PageInfo *info = (Jbig2PageInfo *)malloc(sizeof(Jbig2PageInfo));
   int offset = ctx->offset;
 
@@ -342,7 +336,7 @@
 }
 
 static bool
-dump_segment (Jbig2Ctx *ctx)
+dump_segment (Jbig2Ctx_foo *ctx)
 {
   Jbig2SegmentHeader *sh;
   Jbig2SymbolDictionary *sd;
@@ -434,7 +428,7 @@
 }
 
 static void
-dump_jbig2 (Jbig2Ctx *ctx)
+dump_jbig2 (Jbig2Ctx_foo *ctx)
 {
   bool last;
 
@@ -448,6 +442,7 @@
 	break;
     }
 }
+#endif
 
 static int
 usage (void)
@@ -467,11 +462,20 @@
   return 1;
 }
 
+static int
+error_callback(void *error_callback_data, const char *buf, Jbig2Severity severity,
+	       int32_t seg_idx)
+{
+  fprintf(stderr, "%s\n", buf);
+  return 0;
+}
+
 int
 main (int argc, char **argv)
 {
   FILE *f = NULL, *f_page = NULL;
   Jbig2Ctx *ctx;
+  uint8_t buf[4096];
 
   if (argc == 2)
     {
@@ -483,10 +487,6 @@
 	  fprintf(stderr, "error opening %s\n", fn);
 	  return 1;
 	}
-      ctx = jbig2_open (f);
-      if (ctx != NULL)
-	dump_jbig2(ctx);
-      fclose(f);
     }
   else if (argc == 3)
     {
@@ -505,19 +505,39 @@
 	  fprintf(stderr, "error opening %s\n", fn_page);
 	  return 1;
 	}
-      ctx = jbig2_open_embedded(f, f_page);
-      if (ctx != NULL)
-	dump_jbig2(ctx);
-      ctx->f = f_page;
-      ctx->offset = 0;
-      ctx->eof = FALSE;
-      dump_jbig2(ctx);
-      fclose(f);
-      fclose(f_page);
     }
   else    
     return usage();
     
-  // control should never reach this point
+  ctx = jbig2_ctx_new(NULL, f_page != NULL ? JBIG2_OPTIONS_EMBEDDED : 0,
+		      NULL,
+		      error_callback, NULL);
+  for (;;)
+    {
+      int n_bytes = fread(buf, 1, sizeof(buf), f);
+      if (n_bytes <= 0)
+	break;
+      jbig2_write(ctx, buf, n_bytes);
+    }
+  fclose(f);
+
+  if (f_page != NULL)
+    {
+      Jbig2GlobalCtx *global_ctx = jbig2_make_global_ctx(ctx);
+      ctx = jbig2_ctx_new(NULL, JBIG2_OPTIONS_EMBEDDED, global_ctx,
+			 error_callback, NULL);
+      for (;;)
+	{
+	  int n_bytes = fread(buf, 1, sizeof(buf), f_page);
+	  if (n_bytes <= 0)
+	    break;
+	  jbig2_write(ctx, buf, n_bytes);
+	}
+      fclose(f_page);
+      jbig2_global_ctx_free(global_ctx);
+    }
+
+  jbig2_ctx_free(ctx);
+
   return 0;
 }
--- a/jbig2dec.h
+++ b/jbig2dec.h
@@ -8,7 +8,7 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 
-    $Id: jbig2dec.h,v 1.4 2002/02/12 02:19:08 giles Exp $
+    $Id: jbig2dec.h,v 1.5 2002/02/13 08:47:18 raph Exp $
 */
 
 #ifndef JBIG2DEC_H
@@ -29,16 +29,16 @@
 #define TRUE 1
 #define FALSE 0
 
-typedef struct _Jbig2Ctx Jbig2Ctx;
+typedef struct _Jbig2Ctx_foo Jbig2Ctx_foo;
 
 int32
-get_bytes (Jbig2Ctx *ctx, byte *buf, int size, int off);
+get_bytes (Jbig2Ctx_foo *ctx, byte *buf, int size, int off);
 
 int16
-get_int16 (Jbig2Ctx *ctx, int off);
+get_int16 (Jbig2Ctx_foo *ctx, int off);
 
 int32
-get_int32 (Jbig2Ctx *ctx, int off);
+get_int32 (Jbig2Ctx_foo *ctx, int off);
 
 /* The word stream design is a compromise between simplicity and
    trying to amortize the number of method calls. Each ::get_next_word
--- a/makefile
+++ b/makefile
@@ -4,7 +4,7 @@
 
 all:	$(APPS)
 
-jbig2dec:	jbig2dec.o jbig2_huffman.o jbig2_arith.o jbig2_image.o
+jbig2dec:	jbig2.o jbig2dec.o jbig2_huffman.o jbig2_arith.o jbig2_image.o
 
 test_huffman:	jbig2_huffman.c
 	gcc $(CFLAGS) -DTEST jbig2_huffman.c -o test_huffman