1
0
mirror of https://github.com/koenkooi/foo2zjs.git synced 2026-01-22 03:34:49 +08:00
foo2zjs/oakdecode.c
Koen Kooi 66819e6d05 import 'Tarball last modified: Fri Jan 22 05:14:24 2016 CST'
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
2016-01-25 16:22:04 +01:00

719 lines
18 KiB
C

/*
* $Id: oakdecode.c,v 1.42 2014/01/24 19:25:47 rick Exp $
*
* Work in progress decoder for Oak Tech. JBIG streams (HP1500)
*
* The image data appears to be a bastard little-endian version of JBIG,
* split into bands of 256 pixels (except for the last). The data needs
* to be directly driven into a hacked version of jbig.c. The -r and -d
* options are non-functional.
*
* In addition, the image data is left/right mirrored.
*/
/*b
* Copyright (C) 2003-2006 Rick Richardson
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Author: Rick Richardson <rick.richardson@comcast.net>
b*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "jbig.h"
#include "oak.h"
/*
* Global option flags
*/
int Debug = 0;
char *RawFile;
char *DecFile;
int PrintOffset = 0;
int SupressImage = 0;
int ImageRec[4];
FILE *FpDec[4][2];
FILE *FpRaw[4][2];
void
debug(int level, char *fmt, ...)
{
va_list ap;
if (Debug < level)
return;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
int
error(int fatal, char *fmt, ...)
{
va_list ap;
fprintf(stderr, fatal ? "Error: " : "Warning: ");
if (errno)
fprintf(stderr, "%s: ", strerror(errno));
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fatal > 0)
exit(fatal);
else
{
errno = 0;
return (fatal);
}
}
void
usage(void)
{
fprintf(stderr,
"Usage:\n"
" oakdecode [options] < OAKT-file\n"
"\n"
" Decode an Oak Tech. OAKT printer stream into human readable form.\n"
"\n"
" OAKT is the printer language used by the HP 1500 printers.\n"
"\n"
"Options:\n"
" -d basename Basename of .pbm file for saving decompressed planes\n"
" -r basename Basename of .jbg file for saving raw planes\n"
" -i Supress display of image records\n"
" -o Print file offsets\n"
" -D lvl Set Debug level [%d]\n"
, Debug
);
exit(1);
}
#if 0
BIH-style from foo2zjs/pbmtojbg...
00000000: 00 00 01 00 00 00 26 40 00 00 18 f8 00 00 00 80
00000010: 10 00 03 5c
#include <inttypes.h>
typedef uint32_t DWORD;
typedef uint16_t WORD;
typedef uint8_t BYTE;
typedef struct
{
DWORD opt1;
DWORD xd; // Oak has this little endian
DWORD yd; // Oak has this little endian
DWORD l0; // Oak has this little endian
DWORD opt2;
} OAKBIH;
#endif
void
iswap32(void *p)
{
char *cp = (char *) p;
char tmp;
tmp = cp[0];
cp[0] = cp[3];
cp[3] = tmp;
tmp = cp[1];
cp[1] = cp[2];
cp[2] = tmp;
}
/*
* This is the standard JBIG-KIT big-endian BIH prettyprinter.
*/
void
print_bih(unsigned char bih[20])
{
unsigned int xd, yd, l0;
xd = (bih[4] << 24) | (bih[5] << 16) | (bih[6] << 8) | (bih[7] << 0);
yd = (bih[8] << 24) | (bih[9] << 16) | (bih[10] << 8) | (bih[11] << 0);
l0 = (bih[12] << 24) | (bih[13] << 16) | (bih[14] << 8) | (bih[15] << 0);
printf(" DL = %d, D = %d, P = %d, - = %d, XY = %d x %d\n",
bih[0], bih[1], bih[2], bih[3], xd, yd);
printf(" L0 = %d, MX = %d, MY = %d\n",
l0, bih[16], bih[17]);
printf(" Order = %d %s%s%s%s%s\n", bih[18],
bih[18] & JBG_HITOLO ? " HITOLO" : "",
bih[18] & JBG_SEQ ? " SEQ" : "",
bih[18] & JBG_ILEAVE ? " ILEAVE" : "",
bih[18] & JBG_SMID ? " SMID" : "",
bih[18] & 0xf0 ? " other" : "");
printf(" Options = %d %s%s%s%s%s%s%s%s\n", bih[19],
bih[19] & JBG_LRLTWO ? " LRLTWO" : "",
bih[19] & JBG_VLENGTH ? " VLENGTH" : "",
bih[19] & JBG_TPDON ? " TPDON" : "",
bih[19] & JBG_TPBON ? " TPBON" : "",
bih[19] & JBG_DPON ? " DPON" : "",
bih[19] & JBG_DPPRIV ? " DPPRIV" : "",
bih[19] & JBG_DPLAST ? " DPLAST" : "",
bih[19] & 0x80 ? " other" : "");
printf(" %u stripes, %d layers, %d planes\n",
((yd >> bih[1]) + ((((1UL << bih[1]) - 1) & xd) != 0) + l0 - 1) / l0,
bih[1] - bih[0], bih[2]);
}
#if 0
00000260: 4f 41 4b 54 40 00 00 00 3c 00 00 00 00 00 01 00 | OAKT@...<....... |
00000270: 60 13 00 00 80 00 00 00 80 00 00 00 20 00 03 58 | `........... ..X |
00000280: 02 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 | ................ |
00000290: 00 00 00 00 00 00 00 00 50 41 44 5f 50 41 44 5f | ........PAD_PAD_ |
000002a0: ff 02 50 41 44 5f 50 41 44 5f 50 41 44 5f 50 41 | ..PAD_PAD_PAD_PA |
000002b0: 4f 41 4b 54 40 00 00 00 3c 00 00 00 00 00 01 00 | OAKT@...<....... |
000002c0: 60 13 00 00 80 00 00 00 80 00 00 00 20 00 03 58 | `........... ..X |
000002d0: 02 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 | ................ |
000002e0: 00 00 00 00 01 00 00 00 50 41 44 5f 50 41 44 5f | ........PAD_PAD_ |
000002f0: ff 02 50 41 44 5f 50 41 44 5f 50 41 44 5f 50 41 | ..PAD_PAD_PAD_PA |
0000ba20: 4f 41 4b 54 40 00 00 00 3c 00 00 00 00 00 01 00 | OAKT@...<....... |
0000ba30: 60 13 00 00 00 01 00 00 00 01 00 00 20 00 03 58 | `........... ..X |
0000ba40: 90 0d 00 00 a0 0d 00 00 00 00 00 00 40 02 00 00 | ............@... |
0000ba50: 00 00 00 00 00 00 00 00 50 41 44 5f 50 41 44 5f | ........PAD_PAD_ |
0000ba60: a6 ab 23 26 a0 78 7e 82 25 30 39 8b 95 16 32 4e | ..#&.x~.%09...2N |
...
0000c7f0: 50 41 44 5f 50 41 44 5f 50 41 44 5f 50 41 44 5f | PAD_PAD_PAD_PAD_ |
0000c800: 4f 41 4b 54 40 00 00 00 3c 00 00 00 00 00 01 00 | OAKT@...<....... |
0000c810: 60 13 00 00 00 01 00 00 00 01 00 00 20 00 03 58 | `........... ..X |
0000c820: 02 00 00 00 10 00 00 00 00 00 00 00 40 02 00 00 | ............@... |
0000c830: 00 00 00 00 01 00 00 00 50 41 44 5f 50 41 44 5f | ........PAD_PAD_ |
0000c840: ff 02 50 41 44 5f 50 41 44 5f 50 41 44 5f 50 41 | ..PAD_PAD_PAD_PA |
000124d0: 4f 41 4b 54 40 00 00 00 3c 00 00 00 00 00 01 00 | OAKT@...<....... |
000124e0: 60 13 00 00 00 01 00 00 00 01 00 00 20 00 03 58 | `........... ..X |
000124f0: fe 16 00 00 10 17 00 00 00 00 00 00 40 02 00 00 | ............@... |
00012500: 03 00 00 00 00 00 00 00 50 41 44 5f 50 41 44 5f | ........PAD_PAD_ |
00012510: 4c 8b 1a 0b 4d 74 19 a8 64 fa 91 c0 02 10 36 8c | L...Mt..d.....6. |
...
00013bf0: 11 f6 d3 e1 ca 98 ed b3 1a c3 2d a1 db 34 a9 db | ..........-..4.. |
00013c00: 04 f4 b8 2e 53 cb d3 be b3 e4 8a 3c ff 02 50 41 | ....S......<..PA |
00013c10: 44 5f 50 41 44 5f 50 41 44 5f 50 41 44 5f 50 41 | D_PAD_PAD_PAD_PA |
00013c20: 4f 41 4b 54 40 00 00 00 3c 00 00 00 00 00 01 00 | OAKT@...<....... |
00013c30: 60 13 00 00 00 01 00 00 00 01 00 00 20 00 03 58 | `........... ..X |
00013c40: 7e 02 00 00 90 02 00 00 00 00 00 00 40 02 00 00 | ~...........@... |
00013c50: 03 00 00 00 01 00 00 00 50 41 44 5f 50 41 44 5f | ........PAD_PAD_ |
typedef struct
{
char magic[4];
DWORD len;
DWORD type;
} OAK_HDR;
#endif
typedef struct
{
WORD unk;
char string[64];
WORD pad;
} HDR_0D;
typedef struct
{
char datetime[32]; // Date/time in string format (with NL)
DWORD time_t; // Time in seconds since the Unix epoch
WORD year; // e.g. 2003
WORD tm_mon; // Month-1
WORD tm_mday; // Day of month (1-31)
WORD tm_hour; // Hour (0-23)
WORD tm_min; // Minute (0-59)
WORD tm_sec; // Second (0-59)
DWORD pad;
} HDR_0C;
typedef struct
{
OAKBIH bih;
DWORD datalen;
DWORD padlen;
DWORD unk1C;
DWORD y; // Y offset of this chunk
DWORD plane; // 0=, 1=, 2=, 3=K
DWORD subplane; // 0 or 1
DWORD pad[2];
} HDR_3C;
typedef struct
{
DWORD unk0;
DWORD unk1;
DWORD w;
DWORD h;
DWORD resx;
DWORD resy;
DWORD nbits;
DWORD unk7[4];
} HDR_3X;
void
decode(FILE *fp)
{
OAK_HDR hdr;
int rc;
int size;
int plane = 0;
int subplane;
int pageNum = 0;
int len;
int i, j;
int c;
char *p;
int curOff = 0;
int dwords[128];
short words[128];
unsigned char bytes[128];
char buf[512];
HDR_0D hdr0d;
HDR_0C hdr0c;
HDR_3C hdr3c;
HDR_3X hdr3x[4];
int firstPlane;
size_t cnt;
char *ibuf;
struct jbg_dec_state s[4][2];
int height[4][2];
int width[4][2];
char *strpaper[300+1];
#define STRARY(X, A) \
((X) >= 0 && (X) < sizeof(A)/sizeof(A[0])) \
? A[X] : "UNK"
for (i = 0; i < sizeof(strpaper)/sizeof(strpaper[0]); ++i)
strpaper[i] = "unk";
strpaper[1] = "letter";
strpaper[3] = "ledger";
strpaper[5] = "legal";
strpaper[6] = "statement";
strpaper[7] = "executive";
strpaper[8] = "A3";
strpaper[9] = "A4";
strpaper[11] = "A5";
strpaper[12] = "B4";
strpaper[13] = "B5jis";
strpaper[14] = "folio";
strpaper[19] = "env#9";
strpaper[20] = "env#10";
strpaper[27] = "envDL";
strpaper[28] = "envC5";
strpaper[30] = "envC4";
strpaper[37] = "envMonarch";
strpaper[257] = "A6";
strpaper[258] = "B6";
strpaper[259] = "B5iso";
strpaper[260] = "env6";
strpaper[296] = "CUSTOM";
for (;;)
{
static int first3c = 1;
rc = fread(&hdr, 1, len = sizeof(hdr), fp);
if (rc <=0)
break;
if (rc != len)
{
debug(0, "Expected OAK header, got short read: %d bytes\n", rc);
break;
}
if (hdr.type == 0x3c && first3c)
{
printf("\t"
"\t%8s %4s %4s %4s %8s %5s %5s %3s %4s %s %s\n",
"bih0", "w", "h", "l0", "bih5", "dlen", "plen",
"unk", "yOff", "P", "subP"
);
first3c = 0;
}
if (hdr.type != 0x3c || !SupressImage || !ImageRec[plane])
{
if (PrintOffset)
printf("%x: ", curOff);
printf("%02x (%d)", hdr.type, hdr.len);
}
curOff += len;
size = hdr.len;
size -= sizeof(hdr);
switch (hdr.type)
{
case 0x0d: // first record
rc = fread(&hdr0d, len = sizeof(hdr0d), 1, fp);
if (rc != 1) goto out;
curOff += len;
printf(" %x %s", hdr0d.unk, hdr0d.string);
break;
case 0x0c: // time
rc = fread(&hdr0c, len = sizeof(hdr0c), 1, fp);
if (rc != 1) goto out;
curOff += len;
p = strchr(hdr0c.datetime, '\n');
if (p) *p = 0;
printf(" %s", hdr0c.datetime);
printf(", %d", hdr0c.time_t);
printf(", %d/%02d/%02d %02d:%02d:%02d",
hdr0c.year, hdr0c.tm_mon+1, hdr0c.tm_mday,
hdr0c.tm_hour, hdr0c.tm_min, hdr0c.tm_sec);
break;
case 0x0a: // filename
case 0x1f: // Driver
if (hdr.type == OAK_TYPE_FILENAME)
printf(" filename=");
else
printf(" driver=");
curOff += size;
while (size--)
{
c = fgetc(fp);
if (c == EOF)
break;
else if (c) putchar(c);
else break;
}
if (size > 0)
while (size--)
fgetc(fp);
break;
case 0x0f:
rc = fread(dwords, len = 5*4, 1, fp);
if (rc != 1) goto out;
curOff += len;
printf(" Duplex=0x%x Short=0x%x", dwords[0], dwords[1]);
break;
case 0x14:
printf(" (no args)");
++pageNum;
curOff += size;
while (size--)
fgetc(fp);
break;
case 0x28:
rc = fread(dwords, len = 1*4, 1, fp);
if (rc != 1) goto out;
curOff += len;
switch (dwords[0])
{
case 1: printf(" Source=Tray1"); break;
case 2: printf(" Source=Tray2"); break;
case 4: printf(" Source=ManualFeed"); break;
case 7: printf(" Source=Auto"); break;
default: printf(" Source=%d", dwords[0]); break;
}
break;
case 0x29:
rc = fread(bytes, len = 17*4, 1, fp);
if (rc != 1) goto out;
curOff += len;
printf(" PaperType=%d UNK8=%d,%d,%d, str='%s'",
bytes[0],
bytes[1], bytes[2], bytes[3], &bytes[4]);
// PaperType: 0=AutoSelect, 1=Plain, 2=Preprinted, 3=Letterhead
// 4=GrayscaleTransparency, 5=Prepunched, 6=Labels, 7=Bond
// 8=Recycled, 9=Color, 10=Cardstock, 11=Heavy, 12=Envelope
// 13=Light, 14=Tough
break;
case 0x2a:
rc = fread(dwords, len = 5*4, 1, fp);
if (rc != 1) goto out;
curOff += len;
printf(" Copies=0x%x Duplex=0x%x", dwords[0], dwords[1]);
break;
case 0x2b:
rc = fread(dwords, len = 5*4, 1, fp);
if (rc != 1) goto out;
curOff += len;
printf(" papercode=%s(%d)",
STRARY(dwords[0], strpaper), dwords[0]);
printf(" xwid=%d", dwords[1]);
printf(" ywid=%d", dwords[2]);
printf(" UNK=0x%x", dwords[3]);
break;
case 0x32:
firstPlane = 0;
goto prplanes;
case 0x33:
firstPlane = 3;
prplanes:
printf("\n\tunk0 unk1 w h resx resy nBits");
for (i = firstPlane; i < 4; ++i)
{
rc = fread(&hdr3x[i], len = sizeof(HDR_3X), 1, fp);
if (rc != 1) goto out;
curOff += len;
size -= len;
printf("\n\t0x%x\t0x%x\t%d\t%d\t%d\t%d\t0x%x",
hdr3x[i].unk0,
hdr3x[i].unk1,
hdr3x[i].w,
hdr3x[i].h,
hdr3x[i].resx,
hdr3x[i].resy,
hdr3x[i].nbits);
}
curOff += size;
while (size-- > 0)
fgetc(fp);
break;
case 0x15:
printf(" (no args)");
curOff += size;
while (size--)
fgetc(fp);
break;
case 0x3c:
// rc = fread(dwords, len = 48, 1, fp);
rc = fread(&hdr3c, len = sizeof(hdr3c), 1, fp);
if (rc != 1)
{
debug(0, "Short read of hdr3c\n");
goto out;
}
curOff += len;
plane = hdr3c.plane;
subplane = hdr3c.subplane;
if (!SupressImage || !ImageRec[plane])
{
printf(
"\t0x%08x %4d %4d %4d 0x%08x %5d %5d 0x%03x %4d %d %d\n",
hdr3c.bih.opt1,
hdr3c.bih.xd,
hdr3c.bih.yd,
hdr3c.bih.l0,
hdr3c.bih.opt2,
hdr3c.datalen,
hdr3c.padlen,
hdr3c.unk1C,
hdr3c.y,
hdr3c.plane,
hdr3c.subplane);
}
if (RawFile && !FpRaw[plane][subplane])
{
sprintf(buf, "%s-%02d-%d-%d.jbg",
RawFile, pageNum, plane, subplane);
FpRaw[plane][subplane] = fopen(buf, "w");
}
if (DecFile && !FpDec[plane][subplane])
{
height[plane][subplane] = 0;
sprintf(buf, "%s-%02d-%d-%d.pbm",
DecFile, pageNum, plane, subplane);
FpDec[plane][subplane] = fopen(buf, "w");
fprintf(FpDec[plane][subplane], "P4\n%8d %8d\n", 0, 0);
}
if (FpDec[plane][subplane])
jbg_dec_init(&s[plane][subplane]);
if (1||hdr3c.subplane == 0)
{
static int testend = 1;
static char *cp = (char *) &testend;
static int first_bih = 1;
// JBIGKIT is bigendian, Oak is little-endian
// swap the BIH header words before passing it to
// jbig-kit. N.B. - is there any issues with endianess
// inside the compressed stream itself????
if (*cp == 1)
{
iswap32(&hdr3c.bih.xd);
iswap32(&hdr3c.bih.yd);
iswap32(&hdr3c.bih.l0);
}
if (!SupressImage || !ImageRec[plane])
if (first_bih)
{
first_bih = 0;
print_bih((unsigned char *) &hdr3c);
}
if (0 && *cp == 1)
{
iswap32(&hdr3c.bih.xd);
iswap32(&hdr3c.bih.yd);
iswap32(&hdr3c.bih.l0);
}
if (FpRaw[plane][subplane])
rc = fwrite(&hdr3c.bih, 1, 20, FpRaw[plane][subplane]);
if (FpDec[plane][subplane])
{
rc = jbg_dec_in(&s[plane][subplane],
(unsigned char *)&hdr3c.bih, 20, &cnt);
}
}
ImageRec[plane]++;
// image data
if (!hdr3c.padlen)
break;
size = hdr3c.datalen;
ibuf = malloc(size);
rc = fread(ibuf, 1, size, fp);
if (rc <= 0)
break;
curOff += size;
if (FpRaw[plane][subplane])
rc = fwrite(ibuf, 1, size, FpRaw[plane][subplane]);
if (FpDec[plane][subplane])
{
unsigned char *image;
rc = JBG_EAGAIN;
p = ibuf;
while (size > 0 &&
(rc == JBG_EAGAIN || rc == JBG_EOK))
{
rc = jbg_dec_in(&s[plane][subplane],
(unsigned char *) p, size, &cnt);
p += cnt;
size -= cnt;
}
if (rc)
debug(0, "rc= %d size=%d\n", rc, size);
height[plane][subplane]
+= jbg_dec_getheight(&s[plane][subplane]);
width[plane][subplane]
= jbg_dec_getwidth(&s[plane][subplane]);
image = jbg_dec_getimage(&s[plane][subplane], 0);
if (image)
rc = fwrite(image, 1, jbg_dec_getsize(&s[plane][subplane]),
FpDec[plane][subplane]);
else
debug(0, "Missing image p=%d/%d %dx%d!\n",
plane, subplane,
jbg_dec_getwidth(&s[plane][subplane]),
jbg_dec_getheight(&s[plane][subplane]));
jbg_dec_free(&s[plane][subplane]);
}
free(ibuf);
size = hdr3c.padlen - hdr3c.datalen;
curOff += size;
while (size--)
c = fgetc(fp);
continue;
case 0x17:
printf(" (no args)");
curOff += size;
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 2; ++j)
{
if (FpRaw[i][j])
{
fclose(FpRaw[i][j]);
FpRaw[i][j] = NULL;
}
if (FpDec[i][j])
{
fseek(FpDec[i][j], 0, 0);
fprintf(FpDec[i][j], "P4\n%8d %8d\n",
width[i][j], height[i][j]);
fclose(FpDec[i][j]);
FpDec[i][j] = NULL;
}
}
}
while (size--)
fgetc(fp);
break;
case 0x18:
rc = fread(words, len = (1+1)*2, 1, fp);
if (rc != 1) goto out;
curOff += len;
printf(" UNK=%x", words[0]);
break;
case 0x0b:
printf(" (no args)");
curOff += size;
while (size--)
fgetc(fp);
break;
default:
curOff += size;
while (size--)
fgetc(fp);
}
printf("\n");
}
out:
return;
}
int
main(int argc, char *argv[])
{
extern int optind;
extern char *optarg;
int c;
while ( (c = getopt(argc, argv, "d:ior:D:?h")) != EOF)
switch (c)
{
case 'd': DecFile = optarg; break;
case 'r': RawFile = optarg; break;
case 'i': SupressImage = 1; break;
case 'o': PrintOffset = 1; break;
case 'D': Debug = atoi(optarg); break;
default: usage(); exit(1);
}
argc -= optind;
argv += optind;
if (argc > 0)
{
FILE *fp;
fp = fopen(argv[0], "r");
if (!fp)
error(1, "file '%s' doesn't exist\n", argv[0]);
decode(fp);
fclose(fp);
}
else
decode(stdin);
exit(0);
}