ref: d9367f7452f9117ce3a7f7649966cb42a2c33995
dir: /jbig2dec.c/
/*
jbig2dec
Copyright (c) 2001 artofcode LLC.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
$Id: jbig2dec.c,v 1.3 2001/06/10 07:09:18 giles Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jbig2dec.h"
typedef struct _Jbig2SegmentHeader Jbig2SegmentHeader;
typedef struct _Jbig2SymbolDictionary Jbig2SymbolDictionary;
struct _Jbig2Ctx {
FILE *f;
int offset;
byte flags;
int32 n_pages;
};
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];
byte SDRAT_flags[4];
int32 SDNUMEXSYMS;
int32 SDNUMNEWSYMS;
};
int32
get_bytes (Jbig2Ctx *ctx, byte *buf, int size, int off)
{
fseek (ctx->f, off, SEEK_SET);
return fread (buf, 1, size, ctx->f);
}
int16
get_int16 (Jbig2Ctx *ctx, int off)
{
byte buf[2];
get_bytes (ctx, buf, 2, off);
return (buf[0] << 8) | buf[1];
}
int32
get_int32 (Jbig2Ctx *ctx, int off)
{
byte buf[4];
get_bytes (ctx, buf, 4, off);
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}
static Jbig2Ctx *
jbig2_open (FILE *f)
{
byte buf[9];
const byte header[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a };
Jbig2Ctx *ctx;
/* Annex D.4 */
ctx = (Jbig2Ctx *)malloc (sizeof(Jbig2Ctx));
ctx->f = f;
get_bytes (ctx, buf, 9, 0);
if (memcmp (buf, header, 8))
{
printf ("not a JBIG2 file\n");
return NULL;
}
ctx->flags = buf[8];
if (ctx->flags & 2)
{
ctx->offset = 9;
}
else
{
ctx->offset = 13;
ctx->n_pages = get_int32 (ctx, 9);
}
return ctx;
}
static Jbig2SegmentHeader *
jbig2_read_segment_header (Jbig2Ctx *ctx)
{
Jbig2SegmentHeader *result = (Jbig2SegmentHeader *)malloc(sizeof(Jbig2SegmentHeader));
int32 offset = ctx->offset;
byte rtscarf;
int referred_to_segment_count;
byte spa;
/* 7.2.2 */
result->segment_number = get_int32 (ctx, offset);
/* 7.2.3 */
get_bytes (ctx, &result->flags, 1, offset + 4);
/* 7.2.4 */
get_bytes (ctx, &rtscarf, 1, offset + 5);
if ((rtscarf & 0xe0) == 0xe0)
{
printf ("long form of rtscarf, can't handle!\n");
}
else
{
referred_to_segment_count = (rtscarf >> 5);
offset += 6 + referred_to_segment_count;
}
result->referred_to_segment_count = referred_to_segment_count;
/* todo: read referred to segment numbers */
/* 7.2.6 */
get_bytes (ctx, &spa, 1, offset);
if (result->flags & 64)
{
printf ("long form of spa, can't handle!\n");
}
result->page_association = spa;
/* 7.2.7 */
result->data_length = get_int32 (ctx, offset + 1);
ctx->offset = offset + 5;
return result;
}
static Jbig2SymbolDictionary *
jbig2_read_symbol_dictionary (Jbig2Ctx *ctx)
{
Jbig2SymbolDictionary *result = (Jbig2SymbolDictionary *)malloc(sizeof(Jbig2SymbolDictionary));
int32 offset = ctx->offset;
bool SDHUFF, SDREFAGG, SDRTEMPLATE;
int sdat_bytes;
/* 7.4.2.1.1 */
result->flags = get_int16 (ctx, offset);
offset += 2;
SDHUFF = result->flags & 1;
SDREFAGG = (result->flags >> 1) & 1;
SDRTEMPLATE = (result->flags >> 12) & 1;
/* 7.4.2.1.2 */
if (!SDHUFF)
{
int SDTEMPLATE = (result->flags >> 10) & 3;
if (SDTEMPLATE == 0)
sdat_bytes = 8;
else
sdat_bytes = 2;
}
else
sdat_bytes = 0;
get_bytes (ctx, result->SDAT_flags, sdat_bytes, offset);
memset (&result->SDAT_flags + sdat_bytes, 0, 8 - sdat_bytes);
offset += sdat_bytes;
/* 7.4.2.1.3 */
if (SDREFAGG && !SDRTEMPLATE)
{
get_bytes (ctx, result->SDRAT_flags, 4, offset);
offset += 4;
}
/* 7.4.2.1.4 */
result->SDNUMEXSYMS = get_int32 (ctx, offset);
/* 7.4.2.1.5 */
result->SDNUMNEWSYMS = get_int32 (ctx, offset + 4);
offset += 8;
return result;
}
static void
dump_symbol_dictionary (Jbig2SymbolDictionary *sd)
{
printf ("segment type = symbol dictionary, flags = %04x, numexsyms = %d, numnewsyms = %d\n",
sd->flags, sd->SDNUMEXSYMS, sd->SDNUMNEWSYMS);
}
static bool
dump_segment (Jbig2Ctx *ctx)
{
Jbig2SegmentHeader *sh;
int32 offset;
Jbig2SymbolDictionary *sd;
sh = jbig2_read_segment_header (ctx);
offset = ctx->offset;
printf ("segment number = %d, flags = %02x, page %d, %d bytes\n",
sh->segment_number, sh->flags, sh->page_association, sh->data_length);
switch (sh->flags & 63)
{
case 0:
sd = jbig2_read_symbol_dictionary (ctx);
dump_symbol_dictionary (sd);
break;
case 51:
printf ("segment type = end of file\n");
return TRUE;
}
ctx->offset = offset + sh->data_length;
return FALSE;
}
static void
dump_jbig2 (FILE *f)
{
Jbig2Ctx *ctx;
bool last;
ctx = jbig2_open (f);
printf ("Number of pages = %d\n", ctx->n_pages);
for (;;)
{
last = dump_segment (ctx);
if (last)
break;
}
}
int
main (int argc, char **argv)
{
FILE *f;
if (argc < 2)
return -1;
f = fopen (argv[1], "rb");
if (f == NULL)
return -1;
dump_jbig2 (f);
fclose (f);
return 0;
}