mISDNuser/capi20/g3_mh.c

589 lines
14 KiB
C

/*
* G3 decoding
*
* Written by Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright (C) 2011 Karsten Keil <kkeil@linux-pingi.de>
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2 as published by the
* Free Software Foundation. See the LICENSE file included with
* this package for more details.
*/
#ifdef USE_SOFTFAX
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include "m_capi.h"
#include "g3_mh.h"
/* This debug will generate huge amount of data and slow down the process a lot */
//#define G3_VERBOSE_DEBUG 1
struct g3_mh_code tr_white[64] = {
{ 0, 0x0ac, 0x0ff, 8, 0},
{ 1, 0x038, 0x03f, 6, 0},
{ 2, 0x00e, 0x00f, 4, 0},
{ 3, 0x001, 0x00f, 4, 0},
{ 4, 0x00d, 0x00f, 4, 0},
{ 5, 0x003, 0x00f, 4, 0},
{ 6, 0x007, 0x00f, 4, 0},
{ 7, 0x00f, 0x00f, 4, 0},
{ 8, 0x019, 0x01f, 5, 0},
{ 9, 0x005, 0x01f, 5, 0},
{ 10, 0x01c, 0x01f, 5, 0},
{ 11, 0x002, 0x01f, 5, 0},
{ 12, 0x004, 0x03f, 6, 0},
{ 13, 0x030, 0x03f, 6, 0},
{ 14, 0x00b, 0x03f, 6, 0},
{ 15, 0x02b, 0x03f, 6, 0},
{ 16, 0x015, 0x03f, 6, 0},
{ 17, 0x035, 0x03f, 6, 0},
{ 18, 0x072, 0x07f, 7, 0},
{ 19, 0x018, 0x07f, 7, 0},
{ 20, 0x008, 0x07f, 7, 0},
{ 21, 0x074, 0x07f, 7, 0},
{ 22, 0x060, 0x07f, 7, 0},
{ 23, 0x010, 0x07f, 7, 0},
{ 24, 0x00a, 0x07f, 7, 0},
{ 25, 0x06a, 0x07f, 7, 0},
{ 26, 0x064, 0x07f, 7, 0},
{ 27, 0x012, 0x07f, 7, 0},
{ 28, 0x00c, 0x07f, 7, 0},
{ 29, 0x040, 0x0ff, 8, 0},
{ 30, 0x0c0, 0x0ff, 8, 0},
{ 31, 0x058, 0x0ff, 8, 0},
{ 32, 0x0d8, 0x0ff, 8, 0},
{ 33, 0x048, 0x0ff, 8, 0},
{ 34, 0x0c8, 0x0ff, 8, 0},
{ 35, 0x028, 0x0ff, 8, 0},
{ 36, 0x0a8, 0x0ff, 8, 0},
{ 37, 0x068, 0x0ff, 8, 0},
{ 38, 0x0e8, 0x0ff, 8, 0},
{ 39, 0x014, 0x0ff, 8, 0},
{ 40, 0x094, 0x0ff, 8, 0},
{ 41, 0x054, 0x0ff, 8, 0},
{ 42, 0x0d4, 0x0ff, 8, 0},
{ 43, 0x034, 0x0ff, 8, 0},
{ 44, 0x0b4, 0x0ff, 8, 0},
{ 45, 0x020, 0x0ff, 8, 0},
{ 46, 0x0a0, 0x0ff, 8, 0},
{ 47, 0x050, 0x0ff, 8, 0},
{ 48, 0x0d0, 0x0ff, 8, 0},
{ 49, 0x04a, 0x0ff, 8, 0},
{ 50, 0x0ca, 0x0ff, 8, 0},
{ 51, 0x02a, 0x0ff, 8, 0},
{ 52, 0x0aa, 0x0ff, 8, 0},
{ 53, 0x024, 0x0ff, 8, 0},
{ 54, 0x0a4, 0x0ff, 8, 0},
{ 55, 0x01a, 0x0ff, 8, 0},
{ 56, 0x09a, 0x0ff, 8, 0},
{ 57, 0x05a, 0x0ff, 8, 0},
{ 58, 0x0da, 0x0ff, 8, 0},
{ 59, 0x052, 0x0ff, 8, 0},
{ 60, 0x0d2, 0x0ff, 8, 0},
{ 61, 0x04c, 0x0ff, 8, 0},
{ 62, 0x0cc, 0x0ff, 8, 0},
{ 63, 0x02c, 0x0ff, 8, 0}
};
/* make-up codes white */
struct g3_mh_code mk_white[27] = {
{ 64, 0x01b, 0x01f, 5, 1},
{ 128, 0x009, 0x01f, 5, 1},
{ 192, 0x03a, 0x03f, 6, 1},
{ 256, 0x076, 0x07f, 7, 1},
{ 320, 0x06c, 0x0ff, 8, 1},
{ 384, 0x0ec, 0x0ff, 8, 1},
{ 448, 0x026, 0x0ff, 8, 1},
{ 512, 0x0a6, 0x0ff, 8, 1},
{ 576, 0x016, 0x0ff, 8, 1},
{ 640, 0x0e6, 0x0ff, 8, 1},
{ 704, 0x066, 0x1ff, 9, 1},
{ 768, 0x166, 0x1ff, 9, 1},
{ 832, 0x096, 0x1ff, 9, 1},
{ 896, 0x196, 0x1ff, 9, 1},
{ 960, 0x056, 0x1ff, 9, 1},
{ 1024, 0x156, 0x1ff, 9, 1},
{ 1088, 0x0d6, 0x1ff, 9, 1},
{ 1152, 0x1d6, 0x1ff, 9, 1},
{ 1216, 0x036, 0x1ff, 9, 1},
{ 1280, 0x136, 0x1ff, 9, 1},
{ 1344, 0x0b6, 0x1ff, 9, 1},
{ 1408, 0x1b6, 0x1ff, 9, 1},
{ 1472, 0x032, 0x1ff, 9, 1},
{ 1536, 0x132, 0x1ff, 9, 1},
{ 1600, 0x0b2, 0x1ff, 9, 1},
{ 1664, 0x006, 0x03f, 6, 1},
{ 1728, 0x1b2, 0x1ff, 9, 1}
};
struct g3_mh_code tr_black[64] = {
{ 0, 0x3b0, 0x3ff, 10, 0},
{ 1, 0x002, 0x007, 3, 0},
{ 2, 0x003, 0x003, 2, 0},
{ 3, 0x001, 0x003, 2, 0},
{ 4, 0x006, 0x007, 3, 0},
{ 5, 0x00c, 0x00f, 4, 0},
{ 6, 0x004, 0x00f, 4, 0},
{ 7, 0x018, 0x01f, 5, 0},
{ 8, 0x028, 0x03f, 6, 0},
{ 9, 0x008, 0x03f, 6, 0},
{ 10, 0x010, 0x07f, 7, 0},
{ 11, 0x050, 0x07f, 7, 0},
{ 12, 0x070, 0x07f, 7, 0},
{ 13, 0x020, 0x0ff, 8, 0},
{ 14, 0x0e0, 0x0ff, 8, 0},
{ 15, 0x030, 0x1ff, 9, 0},
{ 16, 0x3a0, 0x3ff, 10, 0},
{ 17, 0x060, 0x3ff, 10, 0},
{ 18, 0x040, 0x3ff, 10, 0},
{ 19, 0x730, 0x7ff, 11, 0},
{ 20, 0x0b0, 0x7ff, 11, 0},
{ 21, 0x1b0, 0x7ff, 11, 0},
{ 22, 0x760, 0x7ff, 11, 0},
{ 23, 0x0a0, 0x7ff, 11, 0},
{ 24, 0x740, 0x7ff, 11, 0},
{ 25, 0x0c0, 0x7ff, 11, 0},
{ 26, 0x530, 0xfff, 12, 0},
{ 27, 0xd30, 0xfff, 12, 0},
{ 28, 0x330, 0xfff, 12, 0},
{ 29, 0xb30, 0xfff, 12, 0},
{ 30, 0x160, 0xfff, 12, 0},
{ 31, 0x960, 0xfff, 12, 0},
{ 32, 0x560, 0xfff, 12, 0},
{ 33, 0xd60, 0xfff, 12, 0},
{ 34, 0x4b0, 0xfff, 12, 0},
{ 35, 0xcb0, 0xfff, 12, 0},
{ 36, 0x2b0, 0xfff, 12, 0},
{ 37, 0xab0, 0xfff, 12, 0},
{ 38, 0x6b0, 0xfff, 12, 0},
{ 39, 0xeb0, 0xfff, 12, 0},
{ 40, 0x360, 0xfff, 12, 0},
{ 41, 0xb60, 0xfff, 12, 0},
{ 42, 0x5b0, 0xfff, 12, 0},
{ 43, 0xdb0, 0xfff, 12, 0},
{ 44, 0x2a0, 0xfff, 12, 0},
{ 45, 0xaa0, 0xfff, 12, 0},
{ 46, 0x6a0, 0xfff, 12, 0},
{ 47, 0xea0, 0xfff, 12, 0},
{ 48, 0x260, 0xfff, 12, 0},
{ 49, 0xa60, 0xfff, 12, 0},
{ 50, 0x4a0, 0xfff, 12, 0},
{ 51, 0xca0, 0xfff, 12, 0},
{ 52, 0x240, 0xfff, 12, 0},
{ 53, 0xec0, 0xfff, 12, 0},
{ 54, 0x1c0, 0xfff, 12, 0},
{ 55, 0xe40, 0xfff, 12, 0},
{ 56, 0x140, 0xfff, 12, 0},
{ 57, 0x1a0, 0xfff, 12, 0},
{ 58, 0x9a0, 0xfff, 12, 0},
{ 59, 0xd40, 0xfff, 12, 0},
{ 60, 0x340, 0xfff, 12, 0},
{ 61, 0x5a0, 0xfff, 12, 0},
{ 62, 0x660, 0xfff, 12, 0},
{ 63, 0xe60, 0xfff, 12, 0}
};
struct g3_mh_code mk_black[27] = {
{ 64, 0x3c0, 0x03ff, 10, 1},
{ 128, 0x130, 0x0fff, 12, 1},
{ 192, 0x930, 0x0fff, 12, 1},
{ 256, 0xda0, 0x0fff, 12, 1},
{ 320, 0xcc0, 0x0fff, 12, 1},
{ 384, 0x2c0, 0x0fff, 12, 1},
{ 448, 0xac0, 0x0fff, 12, 1},
{ 512, 0x6c0, 0x1fff, 13, 1},
{ 576, 0x16c0, 0x1fff, 13, 1},
{ 640, 0xa40, 0x1fff, 13, 1},
{ 704, 0x1a40, 0x1fff, 13, 1},
{ 768, 0x640, 0x1fff, 13, 1},
{ 832, 0x1640, 0x1fff, 13, 1},
{ 896, 0x9c0, 0x1fff, 13, 1},
{ 960, 0x19c0, 0x1fff, 13, 1},
{ 1024, 0x5c0, 0x1fff, 13, 1},
{ 1088, 0x15c0, 0x1fff, 13, 1},
{ 1152, 0xdc0, 0x1fff, 13, 1},
{ 1216, 0x1dc0, 0x1fff, 13, 1},
{ 1280, 0x940, 0x1fff, 13, 1},
{ 1344, 0x1940, 0x1fff, 13, 1},
{ 1408, 0x540, 0x1fff, 13, 1},
{ 1472, 0x1540, 0x1fff, 13, 1},
{ 1536, 0xb40, 0x1fff, 13, 1},
{ 1600, 0x1b40, 0x1fff, 13, 1},
{ 1664, 0x4c0, 0x1fff, 13, 1},
{ 1728, 0x14c0, 0x1fff, 13, 1}
};
struct g3_mh_code special_cw[2] = {
{ 0, 0x0000, 0x0fff, 12, 3},
{ 0, 0x0800, 0x0fff, 12, 2}
};
struct g3_mh_code **white_rev;
struct g3_mh_code **black_rev;
/* white run length table wrunlen_tbl[bitpos to start][val of byte] */
static uint8_t wrunlen_tbl[8][256];
static uint8_t bit_swap[256];
/* we use 13 bit tables */
#define G3_REVERSE_TBL_SIZE 8192
#define G3_REVERSE_MASK 0x1fff
#define G3_REVERSE_BITS 13
static int fill_rev_tbl(struct g3_mh_code **tbl, struct g3_mh_code *code)
{
uint16_t i_cnt, shift, idx;
i_cnt = 0;
shift = code->bits;
idx = code->val | (i_cnt << shift);
while (idx < G3_REVERSE_TBL_SIZE) {
if (!tbl[idx]) {
tbl[idx] = code;
} else {
wprint("Error during fill %x/%d idx %x already filled with %x/%d\n",
code->val, shift, idx, tbl[idx]->val, tbl[idx]->bits);
return -1;
}
i_cnt++;
idx = code->val | (i_cnt << shift);
};
return 0;
}
static inline uint8_t calc_byte_runlen(uint8_t val, uint8_t sb)
{
uint8_t i = sb, bm = 1 << sb;
while (i < 8) {
if ( val & bm)
break;
i++;
bm <<= 1;
}
return i - sb;
}
void g3_gen_tables(void)
{
uint8_t i, v;
white_rev = calloc(G3_REVERSE_TBL_SIZE, sizeof(*white_rev));
black_rev = calloc(G3_REVERSE_TBL_SIZE, sizeof(*black_rev));
for (i = 0; i < 64; i++) {
if (fill_rev_tbl(white_rev, &tr_white[i]))
wprint("Error during white term fill\n");
}
for (i = 0; i < 27; i++) {
if (fill_rev_tbl(white_rev, &mk_white[i]))
wprint("Error during white makeup fill\n");
}
if (fill_rev_tbl(white_rev, &special_cw[0]))
wprint("Error during white skip fill\n");
if (fill_rev_tbl(white_rev, &special_cw[1]))
wprint("Error during white EOL fill\n");
for (i = 0; i < 64; i++) {
if (fill_rev_tbl(black_rev, &tr_black[i]))
wprint("Error during black term fill\n");
}
for (i = 0; i < 27; i++) {
if (fill_rev_tbl(black_rev, &mk_black[i]))
wprint("Error during black makeup fill\n");
}
if (fill_rev_tbl(black_rev, &special_cw[0]))
wprint("Error during black skip fill\n");
if (fill_rev_tbl(black_rev, &special_cw[1]))
wprint("Error during black EOL fill\n");
special_cw[0].bits = 1; /* skip only one bit a time */
/* run length table */
for (i = 0; i < 8; i++) {
v = 0;
do {
wrunlen_tbl[i][v] = calc_byte_runlen(v, i);
v++;
} while (v != 0);
}
/* bit order tab */
v = 0;
do {
bit_swap[v] = (((v & 0x01) << 7) | ((v & 0x02) << 5) | ((v & 0x04) << 3) | ((v & 0x08) << 1) |
((v & 0x10) >> 1) | ((v & 0x20) >> 3) | ((v & 0x40) >> 5) | ((v & 0x80) >> 7));
v++;
} while (v != 0);
}
void g3_destroy_tables(void)
{
free(white_rev);
white_rev = NULL;
free(black_rev);
black_rev =NULL;
}
static struct g3_mh_code *g3_lookup_code(uint16_t val, int black)
{
struct g3_mh_code *code;
if (black)
code = black_rev[val & G3_REVERSE_MASK];
else
code = white_rev[val & G3_REVERSE_MASK];
return code;
}
static inline void _update_nb(struct g3_mh_line_s *ls)
{
if (ls->dp) {
ls->nb = *ls->dp++;
if (ls->dp >= (ls->line + ls->len))
ls->dp = NULL; /* EOL */
} else
ls->nb = 0; /* fill with 0 bits */
ls->nb_bits = 8;
ls->sreg |= ls->nb << 16;
}
static void advance_sreg(struct g3_mh_line_s *ls, uint8_t bits)
{
uint8_t b;
while (bits) {
if (!ls->nb_bits)
_update_nb(ls);
b = bits;
if (b > ls->nb_bits)
b = ls->nb_bits;
ls->sreg >>= b;
ls->nb_bits -= b;
bits -= b;
}
}
static void put_black_run(struct g3_mh_line_s *ls, int bits)
{
uint8_t bitp, bm, b, bb;
uint16_t bytep;
while (bits > 0) {
b = 0xff;
bb = 8;
bitp = ls->bitpos & 7;
bytep = ls->bitpos >> 3;
if (bitp) {
b <<= bitp;
bb -= bitp;
}
if (bits < bb) {
bb = bits;
bm = b;
bm <<= bb;
bm = ~bm;
b &= bm;
}
ls->rawline[bytep] |= bit_swap[b];
ls->bitpos += bb;
bits -= bb;
}
}
const char *code_type_str[] = {
"termination",
"markup",
"EOL",
"FillBit",
};
int g3_decode_line(struct g3_mh_line_s *ls)
{
struct g3_mh_code *cc;
int col = 0; /* start white */
int bits = 0;
// int wlen, ret;
ls->dp = ls->line;
ls->sreg = *ls->dp++;
ls->nb = *ls->dp++;
ls->sreg |= (ls->nb << 8);
ls->nb_bits = 0;
ls->bitcnt = 0;
ls->bitpos = 0;
memset(ls->rawline, 0, ((ls->linelen + 7) >> 3));
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Start decoding line %d, len=%d\n", ls->nr, ls->len);
#endif
while (ls->bitcnt <= ls->linelen) {
cc = g3_lookup_code(ls->sreg, col);
if (cc) {
ls->bitcnt += cc->rl;
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "sreg = %04x %s %s code %x %d bits runlen %d sum %4d\n",
ls->sreg, col ? "black" : "white", code_type_str[cc->type],
cc->val, cc->bits, cc->rl, ls->bitcnt);
#endif
advance_sreg(ls, cc->bits);
switch(cc->type) {
case G3_CWTYPE_TERMINATION:
bits += cc->rl;
if (col)
put_black_run(ls, bits);
else
ls->bitpos += bits;
bits = 0;
col = !col;
break;
case G3_CWTYPE_MAKEUP:
bits += cc->rl;
break;
default:
break;
}
} else {
wprint("sreg = %04x no code found\n", ls->sreg);
break;
}
if (ls->bitcnt == ls->linelen && ls->sreg == 0)
break;
}
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Stop decoding line %d, len=%d\n", ls->nr, ls->bitcnt);
#endif
// g3_print_hex(stdout, ls->rawline, (ls->bitcnt +7)>>3);
#if 0
if (ls->fd >= 0) {
/* Write raw linedata */
wlen = (ls->linelen + 7) >> 3;
ret = write(ls->fd, ls->rawline, wlen);
if (ret != wlen) {
wprint("Cannot write %d bytes (ret = %d) to plain file - %s\n", wlen, ret, strerror(errno));
}
}
#endif
return ls->bitcnt;
}
static int calc_current_runlen(struct g3_mh_line_s *ls, int col)
{
uint16_t sval = ls->bitcnt;
uint16_t bitsleft, crl, rl = 0;
uint8_t val, sbit, bitcnt;
bitsleft = ls->linelen - ls->bitcnt;
while (bitsleft) {
sbit = sval & 7;
val = bit_swap[ls->rawline[sval >> 3]];
if (col)
val ^= 0xff;
bitcnt = 8 - sbit;
if (bitsleft < bitcnt)
bitcnt = bitsleft;
crl = wrunlen_tbl[sbit][val];
if (crl > bitcnt)
crl = bitcnt;
rl += crl;
if (crl < bitcnt) {
/* found new color */
sval += crl;
break;
}
sval += bitcnt;
bitsleft -= bitcnt;
}
ls->bitcnt = sval;
return rl;
}
static void write_mh_code(struct g3_mh_line_s *ls, struct g3_mh_code *cc, int col)
{
uint32_t creg;
uint16_t bits, bitoff, idx;
creg = cc->val;
bitoff = ls->bitpos & 7;
idx = ls->bitpos >> 3;
creg <<= bitoff;
bits = cc->bits;
ls->sreg |= creg;
ls->line[idx] = ls->sreg & 0xff;
ls->bitpos += bits;
bits += bitoff;
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "sreg = %04x %s %s code %x %d bits runlen %d sum %4d\n",
ls->sreg, col ? "black" : "white", code_type_str[cc->type],
cc->val, cc->bits, cc->rl, ls->bitpos);
#endif
while (bits > 7) {
ls->line[idx] = ls->sreg & 0xff;
idx++;
bits -= 8;
ls->sreg >>= 8;
}
ls->line[idx] = ls->sreg & 0xff;
}
static int put_runlen(struct g3_mh_line_s *ls, uint16_t rl, int col)
{
uint16_t tidx, midx;
struct g3_mh_code *cc;
tidx = rl & 0x3f;
midx = rl >> 6;
if (midx) {
if (midx > 28) {
wprint("runlen too big - not supported yet\n");
return -1;
}
midx--;
cc = col ? &mk_black[midx] : &mk_white[midx];
write_mh_code(ls, cc, col);
}
cc = col ? &tr_black[tidx] : &tr_white[tidx];
write_mh_code(ls, cc, col);
return 0;
}
int g3_encode_line(struct g3_mh_line_s *ls)
{
int col = 0;
uint16_t rl;
ls->dp = ls->line;
ls->bitpos = 0;
ls->bitcnt = 0;
ls->sreg = 0;
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Start encoding line %d, len=%d\n", ls->nr, ls->linelen);
#endif
while (ls->bitcnt < ls->linelen) {
rl = calc_current_runlen(ls, col);
put_runlen(ls, rl, col);
col = !col;
}
ls->len = (ls->bitpos + 7) >> 3;
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Stop encoding line %d, compressed bits: %d len %d\n", ls->nr, ls->bitpos, ls->len);
#endif
return ls->len;
}
/* USE_SOFTFAX */
#endif