#include "imgcodec.h" /* Local extension of public image buffer struct for encoding. */ typedef struct ibuf { IBUFPUB pub; char *line_adr; long length; long byte_width; /* Only used in Level-1 encoding. */ char *image_adr; char *image_ptr; /* Only used in Level-3 encoding. */ char *ptr_arr[256]; void (*raw_encode)(struct ibuf *ip); void (*user_exit)(void); FBUFPUB *output; short out_vrc; short lines_left; FBUFPUB temp; char *pbuf; char tbuf[4]; char data[0]; } IBUF; /* Forward declarations of local functions. */ static void level_3_putline(IBUF *ip); static void level_2_putline(IBUF *ip); static void level_1_putline(IBUF *ip); static void l_3_p_1_encode(IBUF *ip); static void l_3_p_2_encode(IBUF *ip); static void l_2_p_1_encode(IBUF *ip); static void l_2_p_2_encode(IBUF *ip); static void l_1_p_1_encode(IBUF *ip); static void l_1_p_2_encode(IBUF *ip); /* Generic initialization function for encoding. * Causes all defined encoding functions to be linked to the caller. * Returns a zero pointer if user_malloc failes. * Otherwise the returned pointer has to be freed after * processing by the 'complement' of user_malloc. */ IBUFPUB *encode_init(IMG_HEADER *input_header, FBUFPUB *output, void *(*user_malloc)(long size), void (*user_exit)(void), short out_lev, short out_pat) { long byte_width, line_len, buf_len; IBUF *image; byte_width = (input_header->sl_width + 7) >> 3; line_len = byte_width * input_header->planes; /* Alloc double line buffer for out_vrc handling (one line delay) */ buf_len = line_len << 1; /* For Level-2 we need an additional line buffer for extended vrc * handling. */ if (out_lev == 2) buf_len += line_len; else if (out_lev != 1) /* Level-3 encoder requires a full image buffer. */ buf_len += line_len * input_header->sl_height; image = (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run); if (image) { image->line_adr = image->pub.pbuf = image->data; image->image_adr = image->data + (line_len << 1); image->pub.pat_buf = image->data + buf_len; image->pub.bytes_left = line_len; image->length = line_len; image->byte_width = byte_width; image->pub.pat_run = input_header->pat_run; image->lines_left = input_header->sl_height; image->pub.vrc = 1; image->out_vrc = 0; image->output = output; image->user_exit = user_exit; image->pub.put_line = (void (*)(IBUFPUB *)) (out_lev == 1 ? level_1_putline : out_lev == 2 ? level_2_putline : level_3_putline); image->raw_encode = out_lev == 1 ? (out_pat == 1 ? l_1_p_1_encode : l_1_p_2_encode) : out_lev == 2 ? (out_pat == 1 ? l_2_p_1_encode : l_2_p_2_encode) : (out_pat == 1 ? l_3_p_1_encode : l_3_p_2_encode); } return &image->pub; } /* Here are the special encode initialization functions. * The reason for introducing them is, that an application usually * needs only one encoder. The programmer has the freedom * (or pain ;-) to decide. For instance, a snapshot utility is * recommended to use a Level-2 encoder, because extended vrc * may provide significant savings over Level-1, and Level-3 could * rather fail in memory allocation (if Level-3 is nevertheless * desired, there should be at least an alternative Level-2 mode * built in to be used in case of Level-3 failing). */ IBUFPUB *l3p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output, void *(*user_malloc)(long size), void (*user_exit)(void)) { long byte_width, line_len, buf_len; IBUF *image; byte_width = (input_header->sl_width + 7) >> 3; line_len = byte_width * input_header->planes; /* Alloc double line buffer for out_vrc handling (one line delay) */ buf_len = line_len << 1; /* Level-3 encoder requires a full image buffer. */ buf_len += line_len * input_header->sl_height; image = (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run); if (image) { image->line_adr = image->pub.pbuf = image->data; image->image_adr = image->data + (line_len << 1); image->pub.pat_buf = image->data + buf_len; image->pub.bytes_left = line_len; image->length = line_len; image->pub.pat_run = input_header->pat_run; image->lines_left = input_header->sl_height; image->pub.vrc = 1; image->out_vrc = 0; image->output = output; image->user_exit = user_exit; image->pub.put_line = (void (*)(IBUFPUB *))level_3_putline; image->raw_encode = l_3_p_2_encode; } return &image->pub; } IBUFPUB *l3p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output, void *(*user_malloc)(long size), void (*user_exit)(void)) { long byte_width, line_len, buf_len; IBUF *image; byte_width = (input_header->sl_width + 7) >> 3; line_len = byte_width * input_header->planes; /* Alloc double line buffer for out_vrc handling (one line delay) */ buf_len = line_len << 1; /* Level-3 encoder requires a full image buffer. */ buf_len += line_len * input_header->sl_height; image = (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run); if (image) { image->line_adr = image->pub.pbuf = image->data; image->image_adr = image->data + (line_len << 1); image->pub.pat_buf = image->data + buf_len; image->pub.bytes_left = line_len; image->length = line_len; image->pub.pat_run = input_header->pat_run; image->lines_left = input_header->sl_height; image->pub.vrc = 1; image->out_vrc = 0; image->output = output; image->user_exit = user_exit; image->pub.put_line = (void (*)(IBUFPUB *))level_3_putline; image->raw_encode = l_3_p_1_encode; } return &image->pub; } IBUFPUB *l2p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output, void *(*user_malloc)(long size), void (*user_exit)(void)) { long byte_width, line_len, buf_len; IBUF *image; byte_width = (input_header->sl_width + 7) >> 3; line_len = byte_width * input_header->planes; /* Alloc double line buffer for out_vrc handling (one line delay) */ buf_len = line_len << 1; /* For Level-2 we need an additional line buffer for extended vrc * handling. */ buf_len += line_len; image = (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run); if (image) { image->line_adr = image->pub.pbuf = image->data; image->image_adr = image->data + (line_len << 1); image->pub.pat_buf = image->data + buf_len; image->pub.bytes_left = line_len; image->length = line_len; image->pub.pat_run = input_header->pat_run; image->lines_left = input_header->sl_height; image->pub.vrc = 1; image->out_vrc = 0; image->output = output; image->user_exit = user_exit; image->pub.put_line = (void (*)(IBUFPUB *))level_2_putline; image->raw_encode = l_2_p_2_encode; } return &image->pub; } IBUFPUB *l2p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output, void *(*user_malloc)(long size), void (*user_exit)(void)) { long byte_width, line_len, buf_len; IBUF *image; byte_width = (input_header->sl_width + 7) >> 3; line_len = byte_width * input_header->planes; /* Alloc double line buffer for out_vrc handling (one line delay) */ buf_len = line_len << 1; /* For Level-2 we need an additional line buffer for extended vrc * handling. */ buf_len += line_len; image = (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run); if (image) { image->line_adr = image->pub.pbuf = image->data; image->image_adr = image->data + (line_len << 1); image->pub.pat_buf = image->data + buf_len; image->pub.bytes_left = line_len; image->length = line_len; image->pub.pat_run = input_header->pat_run; image->lines_left = input_header->sl_height; image->pub.vrc = 1; image->out_vrc = 0; image->output = output; image->user_exit = user_exit; image->pub.put_line = (void (*)(IBUFPUB *))level_2_putline; image->raw_encode = l_2_p_1_encode; } return &image->pub; } IBUFPUB *l1p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output, void *(*user_malloc)(long size), void (*user_exit)(void)) { long byte_width, line_len, buf_len; IBUF *image; byte_width = (input_header->sl_width + 7) >> 3; line_len = byte_width * input_header->planes; /* Alloc double line buffer for out_vrc handling (one line delay) */ buf_len = line_len << 1; image = (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run); if (image) { image->line_adr = image->pub.pbuf = image->data; image->image_adr = image->pub.pat_buf = image->data + buf_len; image->pub.bytes_left = line_len; image->length = line_len; image->byte_width = byte_width; image->pub.pat_run = input_header->pat_run; image->lines_left = input_header->sl_height; image->pub.vrc = 1; image->out_vrc = 0; image->output = output; image->user_exit = user_exit; image->pub.put_line = (void (*)(IBUFPUB *))level_1_putline; image->raw_encode = l_1_p_2_encode; } return &image->pub; } IBUFPUB *l1p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output, void *(*user_malloc)(long size), void (*user_exit)(void)) { long byte_width, line_len, buf_len; IBUF *image; byte_width = (input_header->sl_width + 7) >> 3; line_len = byte_width * input_header->planes; /* Alloc double line buffer for out_vrc handling (one line delay) */ buf_len = line_len << 1; image = (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run); if (image) { image->line_adr = image->pub.pbuf = image->data; image->image_adr = image->pub.pat_buf = image->data + buf_len; image->pub.bytes_left = line_len; image->length = line_len; image->byte_width = byte_width; image->pub.pat_run = input_header->pat_run; image->lines_left = input_header->sl_height; image->pub.vrc = 1; image->out_vrc = 0; image->output = output; image->user_exit = user_exit; image->pub.put_line = (void (*)(IBUFPUB *))level_1_putline; image->raw_encode = l_1_p_1_encode; } return &image->pub; } /* Here come the local functions for encode processing. */ static void l_3_p_2_encode(IBUF *ip) { char cdata, c_val, *line_buf, *line_ptr, *endl_buf; char **end_ptr, *prp, *vrp, *line_lim0; long s_save, p_save, v_save, buf_offs; FBUFPUB *output; line_ptr = line_buf = ip->image_adr; ip->image_adr = endl_buf = ip->image_ptr; buf_offs = -ip->length; end_ptr = ip->ptr_arr; output = ip->output; do { /* Level-3 output loop equals Level-2 * (different initializations). * So look at the below Level-2 code for comments. */ char *orig_ptr = line_ptr; start: line_lim0 = orig_ptr + 256; if (line_lim0 > endl_buf) line_lim0 = endl_buf; do { char *start_ptr = line_buf; s_save = -1; if ((cdata = *line_buf) == 0 || cdata == -1) { char *line_lim = line_buf + 127; do { if (*line_buf != cdata) { cdata = ~cdata; if (*line_buf != cdata) break; line_lim = line_buf; } if (line_buf >= line_lim) { s_save -= 1; line_lim += 127; } } while (++line_buf < endl_buf); s_save += line_buf - start_ptr; if (start_ptr != orig_ptr && line_buf < line_lim0) s_save -= 2; line_buf = start_ptr; cdata = *line_buf; } if (line_buf < endl_buf - 1) { char *line_lim = line_buf + 255 * 2; if (line_lim > endl_buf) line_lim = endl_buf; --line_lim; c_val = line_buf[1]; do line_buf += 2; while (line_buf < line_lim && line_buf[0] == cdata && line_buf[1] == c_val); } prp = line_buf; line_buf = start_ptr; p_save = (prp - line_buf) - 4; if (line_buf != orig_ptr && prp < line_lim0) p_save -= 2; v_save = -3; if (cdata == line_buf[buf_offs]) { char *line_lim = line_buf + 255; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && line_buf[0] == line_buf[buf_offs]); vrp = line_buf; line_buf = start_ptr; v_save += vrp - line_buf; if (line_buf != orig_ptr) { if (vrp < line_lim0) { if ((cdata = *vrp) == 0 || cdata == -1) { int limit = 3; line_lim = vrp; do if (*line_lim != cdata) { cdata = ~cdata; if (*line_lim != cdata) { v_save -= 2; break; } } else if (--limit == 0) break; while (++line_lim < line_lim0); } else v_save -= 2; cdata = *line_buf; } if (v_save >= 0 && v_save > p_save && v_save > s_save) { line_lim = line_buf + 2; if ((cdata = c_val) == 0 || cdata == -1) { do if (line_lim == vrp) goto ex; while (*line_lim++ == cdata); --line_lim; if (line_lim <= line_buf + 128 && vrp < line_lim + 127 && vrp < endl_buf) { c_val = ~c_val; do if (line_lim > vrp) goto ex; while (*line_lim++ == c_val); } } else if (line_lim <= line_lim0 && ((cdata = *line_lim++) == 0 || cdata == -1) && vrp < line_lim + 126 && vrp < endl_buf) do if (line_lim > vrp) { line_buf++; ex: s_save = v_save; line_buf++; break; } while (*line_lim++ == cdata); } } } } while (s_save < 0 && p_save < 0 && v_save < 0 && ++line_buf < line_lim0); if (line_buf != line_ptr) { if (line_buf < line_lim0) { *end_ptr++ = endl_buf; endl_buf = line_buf; line_buf = line_ptr; goto start; } FPUTC(output, 0x80); FPUTC(output, (char)(line_buf - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); } if (s_save >= 0 && s_save >= p_save && s_save >= v_save) { char *line_lim = line_buf + 127; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); cdata <<= 7; FPUTC(output, cdata | (char)(line_buf - line_ptr)); line_ptr = line_buf; } else if (p_save >= 0 && p_save >= v_save) { line_buf = prp; FPUTC(output, 0); FPUTC(output, (char)((line_buf - line_ptr) >> 1)); FPUTC(output, cdata); FPUTC(output, c_val); line_ptr = line_buf; } else if (v_save >= 0) { line_buf = vrp; FPUTC(output, 0); FPUTC(output, 0); FPUTC(output, (char)(line_buf - line_ptr) - 1); line_ptr = line_buf; } if (end_ptr != ip->ptr_arr) { endl_buf = *--end_ptr; goto start; } } while (line_buf < endl_buf); } static void l_3_p_1_encode(IBUF *ip) { char cdata, *line_buf, *line_ptr, *endl_buf; char **end_ptr, *prp, *vrp, *line_lim0; long s_save, p_save, v_save, buf_offs; FBUFPUB *output; line_ptr = line_buf = ip->image_adr; ip->image_adr = endl_buf = ip->image_ptr; buf_offs = -ip->length; end_ptr = ip->ptr_arr; output = ip->output; do { /* Level-3 output loop equals Level-2 * (different initializations). * So look at the below Level-2 code for comments. */ char *orig_ptr = line_ptr; start: line_lim0 = orig_ptr + 256; if (line_lim0 > endl_buf) line_lim0 = endl_buf; do { char *start_ptr = line_buf; s_save = -1; if ((cdata = *line_buf) == 0 || cdata == -1) { char *line_lim = line_buf + 127; do { if (*line_buf != cdata) { cdata = ~cdata; if (*line_buf != cdata) break; line_lim = line_buf; } if (line_buf >= line_lim) { s_save -= 1; line_lim += 127; } } while (++line_buf < endl_buf); s_save += line_buf - start_ptr; if (start_ptr != orig_ptr && line_buf < line_lim0) s_save -= 2; line_buf = start_ptr; cdata = *line_buf; } { char *line_lim = line_buf + 255; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); prp = line_buf; line_buf = start_ptr; p_save = (prp - line_buf) - 3; if (line_buf != orig_ptr && prp < line_lim0) p_save -= 2; } v_save = -3; if (cdata == line_buf[buf_offs]) { char *line_lim = line_buf + 255; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && line_buf[0] == line_buf[buf_offs]); vrp = line_buf; line_buf = start_ptr; v_save += vrp - line_buf; if (line_buf != orig_ptr) { if (vrp < line_lim0) { if ((cdata = *vrp) == 0 || cdata == -1) { int limit = 3; line_lim = vrp; do if (*line_lim != cdata) { cdata = ~cdata; if (*line_lim != cdata) { v_save -= 2; break; } } else if (--limit == 0) break; while (++line_lim < line_lim0); } else v_save -= 2; cdata = *line_buf; } if (v_save >= 0 && v_save > p_save && v_save > s_save) { line_lim = line_buf + 2; if ((cdata = line_buf[1]) == 0 || cdata == -1) { do if (line_lim == vrp) goto ex; while (*line_lim++ == cdata); --line_lim; if (line_lim <= line_buf + 128 && vrp < line_lim + 127 && vrp < endl_buf) { char c_val = cdata; c_val = ~c_val; do if (line_lim > vrp) goto ex; while (*line_lim++ == c_val); } } else if (line_lim <= line_lim0 && ((cdata = *line_lim++) == 0 || cdata == -1) && vrp < line_lim + 126 && vrp < endl_buf) do if (line_lim > vrp) { line_buf++; ex: s_save = v_save; line_buf++; break; } while (*line_lim++ == cdata); } } } } while (s_save < 0 && p_save < 0 && v_save < 0 && ++line_buf < line_lim0); if (line_buf != line_ptr) { if (line_buf < line_lim0) { *end_ptr++ = endl_buf; endl_buf = line_buf; line_buf = line_ptr; goto start; } FPUTC(output, 0x80); FPUTC(output, (char)(line_buf - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); } if (s_save >= 0 && s_save >= p_save && s_save >= v_save) { char *line_lim = line_buf + 127; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); cdata <<= 7; FPUTC(output, cdata | (char)(line_buf - line_ptr)); line_ptr = line_buf; } else if (p_save >= 0 && p_save >= v_save) { line_buf = prp; FPUTC(output, 0); FPUTC(output, (char)(line_buf - line_ptr)); FPUTC(output, cdata); line_ptr = line_buf; } else if (v_save >= 0) { line_buf = vrp; FPUTC(output, 0); FPUTC(output, 0); FPUTC(output, (char)(line_buf - line_ptr) - 1); line_ptr = line_buf; } if (end_ptr != ip->ptr_arr) { endl_buf = *--end_ptr; goto start; } } while (line_buf < endl_buf); } static void level_3_putline(IBUF *ip) { char *line_buf, *line_ptr, *endl_buf; FBUFPUB *output; line_buf = ip->line_adr; endl_buf = ip->pub.pbuf; output = ip->output; if (ip->out_vrc == 0) { if (ip->pub.bytes_left) return; line_ptr = endl_buf; /* * Make a complement copy of the first line. This is a trick * to avoid special casing extended vrc checking for the first * line in the raw encoder. */ do *line_ptr++ = ~*line_buf++; while (line_buf < endl_buf); goto mark3; } if (ip->pub.bytes_left) { ip->pub.pbuf += ip->pub.bytes_left; ip->pub.bytes_left = 0; if (ip->out_vrc - 1) if ((ip->out_vrc - 1) * ip->length < 256) { line_ptr = ip->image_ptr; ip->image_ptr += (ip->out_vrc - 1) * ip->length; line_buf = line_ptr; line_ptr += ip->length; do *line_ptr++ = *line_buf++; while (line_buf < ip->image_ptr); } else { if (ip->image_ptr != ip->image_adr) (*ip->raw_encode)(ip); FPUTC(output, 0); FPUTC(output, 0); FPUTC(output, 0xFF); FPUTC(output, (char)ip->out_vrc); } ip->out_vrc = 0; ip->image_ptr += ip->length; (*ip->raw_encode)(ip); ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; return; } line_ptr = ip->image_ptr; do if (*line_ptr++ != *line_buf++) { if (ip->out_vrc - 1) { if ((ip->out_vrc - 1) * ip->length >= 256) goto mark1; line_ptr = ip->image_ptr; ip->image_ptr += (ip->out_vrc - 1) * ip->length; line_buf = line_ptr; line_ptr += ip->length; do *line_ptr++ = *line_buf++; while (line_buf < ip->image_ptr); } goto mark2; } while (line_buf < endl_buf); do { if (ip->out_vrc == 256) { mark1: if (ip->image_ptr != ip->image_adr) (*ip->raw_encode)(ip); FPUTC(output, 0); FPUTC(output, 0); FPUTC(output, 0xFF); FPUTC(output, (char)ip->out_vrc); mark2: ip->out_vrc = 0; line_ptr = ip->image_ptr; line_ptr += ip->length; mark3: line_buf = ip->line_adr; ip->image_ptr = line_ptr; do *line_ptr++ = *line_buf++; while (line_buf < endl_buf); } ip->out_vrc++; if (--ip->lines_left <= 0) { if (ip->out_vrc - 1) if ((ip->out_vrc - 1) * ip->length < 256) { line_ptr = ip->image_ptr; ip->image_ptr += (ip->out_vrc - 1) * ip->length; line_buf = line_ptr; line_ptr += ip->length; do *line_ptr++ = *line_buf++; while (line_buf < ip->image_ptr); } else { if (ip->image_ptr != ip->image_adr) (*ip->raw_encode)(ip); FPUTC(output, 0); FPUTC(output, 0); FPUTC(output, 0xFF); FPUTC(output, (char)ip->out_vrc); } ip->out_vrc = 0; ip->image_ptr += ip->length; (*ip->raw_encode)(ip); ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; (*ip->user_exit)(); } } while (--ip->pub.vrc); ip->pub.vrc++; ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; } static void put_vrc(FBUFPUB *output) { IBUF *ip; char *p; ip = (IBUF *)output->pbuf; *output = ip[-1].temp; FPUTC(output, 0); FPUTC(output, 0); FPUTC(output, 0xFF); FPUTC(output, (char)ip[-1].out_vrc); ip[-1].out_vrc = 1; p = ip[-1].pbuf; do FPUTC(output, *p++); while (p < (char *)ip); } static void l_2_p_2_encode(IBUF *ip) { char cdata, c_val, *line_buf, *line_ptr, *endl_buf; char **end_ptr, *prp, *vrp, *line_lim0; long s_save, p_save, v_save, buf_offs; FBUFPUB *output; output = ip->output; buf_offs = ip->length; if (ip->out_vrc != 1) if (ip->out_vrc != 2 || buf_offs >= 256) { long limit = 1; ip->temp = *output; switch (ip->out_vrc) { case 2: limit += 2; case 3: case 4: limit += 1; } output->pbuf = ip->pbuf = ip->data - limit; output->bytes_left = limit; output->data_func = put_vrc; } endl_buf = ip->image_adr; end_ptr = ip->ptr_arr; do { /* OK, here's the heart of the Level-2 encoder... * The outer loop (within full-line loop) is set up for * simple (uncompressed) bytestring handling. * "line_ptr" points to next byte to write, "line_buf" * is a preview pointer to check for possible _s_olid, * _p_attern, or _v_ertical run compression. */ line_ptr = line_buf = ip->pub.pbuf; do { /* "line_lim0" is set as limit for bytestring handler. * NOTE: The offset 256 is the maximum Level-2 bytestring * counter, which results in a zero byte value if reached. * For Level-1 (compatibility) the maximum offset is 255. */ char *orig_ptr = line_ptr; start: line_lim0 = orig_ptr + 256; if (line_lim0 > endl_buf) line_lim0 = endl_buf; do { char *start_ptr = line_buf; s_save = -1; if ((cdata = *line_buf) == 0 || cdata == -1) { char *line_lim = line_buf + 127; do { if (*line_buf != cdata) { cdata = ~cdata; if (*line_buf != cdata) break; line_lim = line_buf; } if (line_buf >= line_lim) { s_save -= 1; line_lim += 127; } } while (++line_buf < endl_buf); s_save += line_buf - start_ptr; if (start_ptr != orig_ptr && line_buf < line_lim0) s_save -= 2; line_buf = start_ptr; cdata = *line_buf; } if (line_buf < endl_buf - 1) { char *line_lim = line_buf + 255 * 2; if (line_lim > endl_buf) line_lim = endl_buf; --line_lim; c_val = line_buf[1]; do line_buf += 2; while (line_buf < line_lim && line_buf[0] == cdata && line_buf[1] == c_val); } prp = line_buf; line_buf = start_ptr; p_save = (prp - line_buf) - 4; if (line_buf != orig_ptr && prp < line_lim0) p_save -= 2; v_save = -3; if (cdata == line_buf[buf_offs]) { char *line_lim = line_buf + 255; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && line_buf[0] == line_buf[buf_offs]); vrp = line_buf; line_buf = start_ptr; v_save += vrp - line_buf; if (line_buf != orig_ptr) { if (vrp < line_lim0) { if ((cdata = *vrp) == 0 || cdata == -1) { int limit = 3; line_lim = vrp; do if (*line_lim != cdata) { cdata = ~cdata; if (*line_lim != cdata) { v_save -= 2; break; } } else if (--limit == 0) break; while (++line_lim < line_lim0); } else v_save -= 2; cdata = *line_buf; } if (v_save >= 0 && v_save > p_save && v_save > s_save) { line_lim = line_buf + 2; if ((cdata = c_val) == 0 || cdata == -1) { do if (line_lim == vrp) goto ex; while (*line_lim++ == cdata); --line_lim; if (line_lim <= line_buf + 128 && vrp < line_lim + 127 && vrp < endl_buf) { c_val = ~c_val; do if (line_lim > vrp) goto ex; while (*line_lim++ == c_val); } } else if (line_lim <= line_lim0 && ((cdata = *line_lim++) == 0 || cdata == -1) && vrp < line_lim + 126 && vrp < endl_buf) do if (line_lim > vrp) { line_buf++; ex: s_save = v_save; line_buf++; break; } while (*line_lim++ == cdata); } } } } while (s_save < 0 && p_save < 0 && v_save < 0 && ++line_buf < line_lim0); if (line_buf != line_ptr) { if (line_buf < line_lim0) { *end_ptr++ = endl_buf; endl_buf = line_buf; line_buf = line_ptr; goto start; } FPUTC(output, 0x80); FPUTC(output, (char)(line_buf - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); } if (s_save >= 0 && s_save >= p_save && s_save >= v_save) { char *line_lim = line_buf + 127; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); cdata <<= 7; FPUTC(output, cdata | (char)(line_buf - line_ptr)); line_ptr = line_buf; } else if (p_save >= 0 && p_save >= v_save) { line_buf = prp; FPUTC(output, 0); FPUTC(output, (char)((line_buf - line_ptr) >> 1)); FPUTC(output, cdata); FPUTC(output, c_val); line_ptr = line_buf; } else if (v_save >= 0) { line_buf = vrp; FPUTC(output, 0); FPUTC(output, 0); FPUTC(output, (char)(line_buf - line_ptr) - 1); line_ptr = line_buf; } if (end_ptr != ip->ptr_arr) { endl_buf = *--end_ptr; goto start; } } while (line_buf < endl_buf); line_buf = ip->pub.pbuf; line_ptr = endl_buf; do *line_ptr++ = *line_buf++; while (line_buf < endl_buf); if (ip->out_vrc != 1) if (ip->out_vrc != 2 || buf_offs >= 256) { line_buf = output->pbuf; *output = ip->temp; do { line_ptr = ip->pbuf; do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); } while (--ip->out_vrc); return; } } while (--ip->out_vrc); } static void l_2_p_1_encode(IBUF *ip) { char cdata, *line_buf, *line_ptr, *endl_buf; char **end_ptr, *prp, *vrp, *line_lim0; long s_save, p_save, v_save, buf_offs; FBUFPUB *output; output = ip->output; buf_offs = ip->length; if (ip->out_vrc != 1) if (ip->out_vrc != 2 || buf_offs >= 256) { long limit = 1; ip->temp = *output; switch (ip->out_vrc) { case 2: limit += 2; case 3: case 4: limit += 1; } output->pbuf = ip->pbuf = ip->data - limit; output->bytes_left = limit; output->data_func = put_vrc; } endl_buf = ip->image_adr; end_ptr = ip->ptr_arr; do { /* OK, here's the heart of the Level-2 encoder... * The outer loop (within full-line loop) is set up for * simple (uncompressed) bytestring handling. * "line_ptr" points to next byte to write, "line_buf" * is a preview pointer to check for possible _s_olid, * _p_attern, or _v_ertical run compression. */ line_ptr = line_buf = ip->pub.pbuf; do { /* "line_lim0" is set as limit for bytestring handler. * NOTE: The offset 256 is the maximum Level-2 bytestring * counter, which results in a zero byte value if reached. * For Level-1 (compatibility) the maximum offset is 255. */ char *orig_ptr = line_ptr; start: line_lim0 = orig_ptr + 256; if (line_lim0 > endl_buf) line_lim0 = endl_buf; do { char *start_ptr = line_buf; s_save = -1; if ((cdata = *line_buf) == 0 || cdata == -1) { char *line_lim = line_buf + 127; do { if (*line_buf != cdata) { cdata = ~cdata; if (*line_buf != cdata) break; line_lim = line_buf; } if (line_buf >= line_lim) { s_save -= 1; line_lim += 127; } } while (++line_buf < endl_buf); s_save += line_buf - start_ptr; if (start_ptr != orig_ptr && line_buf < line_lim0) s_save -= 2; line_buf = start_ptr; cdata = *line_buf; } { char *line_lim = line_buf + 255; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); prp = line_buf; line_buf = start_ptr; p_save = (prp - line_buf) - 3; if (line_buf != orig_ptr && prp < line_lim0) p_save -= 2; } v_save = -3; if (cdata == line_buf[buf_offs]) { char *line_lim = line_buf + 255; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && line_buf[0] == line_buf[buf_offs]); vrp = line_buf; line_buf = start_ptr; v_save += vrp - line_buf; if (line_buf != orig_ptr) { if (vrp < line_lim0) { if ((cdata = *vrp) == 0 || cdata == -1) { int limit = 3; line_lim = vrp; do if (*line_lim != cdata) { cdata = ~cdata; if (*line_lim != cdata) { v_save -= 2; break; } } else if (--limit == 0) break; while (++line_lim < line_lim0); } else v_save -= 2; cdata = *line_buf; } if (v_save >= 0 && v_save > p_save && v_save > s_save) { line_lim = line_buf + 2; if ((cdata = line_buf[1]) == 0 || cdata == -1) { do if (line_lim == vrp) goto ex; while (*line_lim++ == cdata); --line_lim; if (line_lim <= line_buf + 128 && vrp < line_lim + 127 && vrp < endl_buf) { char c_val = cdata; c_val = ~c_val; do if (line_lim > vrp) goto ex; while (*line_lim++ == c_val); } } else if (line_lim <= line_lim0 && ((cdata = *line_lim++) == 0 || cdata == -1) && vrp < line_lim + 126 && vrp < endl_buf) do if (line_lim > vrp) { line_buf++; ex: s_save = v_save; line_buf++; break; } while (*line_lim++ == cdata); } } } } while (s_save < 0 && p_save < 0 && v_save < 0 && ++line_buf < line_lim0); if (line_buf != line_ptr) { if (line_buf < line_lim0) { *end_ptr++ = endl_buf; endl_buf = line_buf; line_buf = line_ptr; goto start; } FPUTC(output, 0x80); FPUTC(output, (char)(line_buf - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); } if (s_save >= 0 && s_save >= p_save && s_save >= v_save) { char *line_lim = line_buf + 127; if (line_lim > endl_buf) line_lim = endl_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); cdata <<= 7; FPUTC(output, cdata | (char)(line_buf - line_ptr)); line_ptr = line_buf; } else if (p_save >= 0 && p_save >= v_save) { line_buf = prp; FPUTC(output, 0); FPUTC(output, (char)(line_buf - line_ptr)); FPUTC(output, cdata); line_ptr = line_buf; } else if (v_save >= 0) { line_buf = vrp; FPUTC(output, 0); FPUTC(output, 0); FPUTC(output, (char)(line_buf - line_ptr) - 1); line_ptr = line_buf; } if (end_ptr != ip->ptr_arr) { endl_buf = *--end_ptr; goto start; } } while (line_buf < endl_buf); line_buf = ip->pub.pbuf; line_ptr = endl_buf; do *line_ptr++ = *line_buf++; while (line_buf < endl_buf); if (ip->out_vrc != 1) if (ip->out_vrc != 2 || buf_offs >= 256) { line_buf = output->pbuf; *output = ip->temp; do { line_ptr = ip->pbuf; do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); } while (--ip->out_vrc); return; } } while (--ip->out_vrc); } static void level_2_putline(IBUF *ip) { char *line_buf, *line_ptr, *endl_buf; line_buf = ip->line_adr; endl_buf = ip->pub.pbuf; if (ip->out_vrc == 0) { if (ip->pub.bytes_left) return; line_ptr = ip->image_adr; /* * Make a complement copy of the first line. This is a trick * to avoid special casing extended vrc checking for the first * line in the raw encoder. */ do *line_ptr++ = ~*line_buf++; while (line_buf < endl_buf); line_buf = ip->line_adr; line_ptr = endl_buf; } else { if (ip->pub.bytes_left) { ip->pub.pbuf += ip->pub.bytes_left; ip->pub.bytes_left = 0; (*ip->raw_encode)(ip); ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; return; } line_ptr = endl_buf; do { if (*line_ptr != *line_buf) { (*ip->raw_encode)(ip); break; } line_ptr++; line_buf++; } while (line_buf < endl_buf); } while (line_buf < endl_buf) *line_ptr++ = *line_buf++; do { if (ip->out_vrc == 256) (*ip->raw_encode)(ip); ip->out_vrc++; if (--ip->lines_left <= 0) { (*ip->raw_encode)(ip); ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; (*ip->user_exit)(); } } while (--ip->pub.vrc); ip->pub.vrc++; ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; } static void l_1_p_2_encode(IBUF *ip) { char cdata, c_val, *line_buf, *line_ptr, *endl_buf, *start_ptr; FBUFPUB *output; int i; output = ip->output; if (ip->out_vrc != 1) { long limit = 1; ip->temp = *output; switch (ip->out_vrc) { case 2: limit += 2; case 3: case 4: limit += 1; } output->pbuf = ip->pbuf = ip->data - limit; output->bytes_left = limit; output->data_func = put_vrc; } line_ptr = line_buf = ip->pub.pbuf; do { endl_buf = line_buf + ip->byte_width; do { char *line_lim0 = line_buf + 255; if (line_lim0 > endl_buf) line_lim0 = endl_buf; for (;;) { if ((cdata = *line_buf++) == 0 || cdata == -1) { char *line_lim = --line_buf + 127; if (line_lim > endl_buf) line_lim = endl_buf; start_ptr = line_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); i = (int)(line_buf - start_ptr); if (i >= 3 || start_ptr == line_ptr || line_buf >= line_lim0) { entry: if (start_ptr != line_ptr) { FPUTC(output, 0x80); FPUTC(output, (char)(start_ptr - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < start_ptr); } cdata <<= 7; cdata |= (char)i; FPUTC(output, cdata); line_ptr = line_buf; break; } if (i == 2) { char cval2; line_lim = line_buf; for (;;) if ((c_val = *line_lim++) == 0 || c_val == -1) { if (line_lim >= line_lim0) goto entry; if (*line_lim == c_val) goto entry; } else { if (line_lim >= line_lim0 - 2) break; cval2 = *line_lim++; if (c_val != *line_lim++) break; if (cval2 != *line_lim++) break; if (line_lim >= line_lim0) goto entry; if (line_lim < line_lim0 - 1 && line_lim[0] == c_val && line_lim[1] == cval2) goto entry; } } line_buf = start_ptr + 1; } if (line_buf < endl_buf - 2 && cdata == line_buf[1]) { c_val = line_buf[0]; if (c_val == line_buf[2]) { char *line_lim = --line_buf + 255 * 2; if (line_lim > endl_buf) line_lim = endl_buf; start_ptr = line_buf; --line_lim; do line_buf += 2; while (line_buf < line_lim && line_buf[0] == cdata && line_buf[1] == c_val); i = (int)(line_buf - start_ptr) >> 1; if (i >= 3 || start_ptr == line_ptr || line_buf >= line_lim0) { if (start_ptr != line_ptr) { FPUTC(output, 0x80); FPUTC(output, (char)(start_ptr - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < start_ptr); } FPUTC(output, 0); FPUTC(output, (char)i); FPUTC(output, cdata); FPUTC(output, c_val); line_ptr = line_buf; break; } line_buf = start_ptr + 1; } } if (line_buf >= line_lim0) { FPUTC(output, 0x80); FPUTC(output, (char)(line_buf - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); break; } } } while (line_buf < endl_buf); } while (endl_buf < ip->image_adr); if (--ip->out_vrc) { line_buf = output->pbuf; *output = ip->temp; ++ip->out_vrc; do { line_ptr = ip->pbuf; do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); } while (--ip->out_vrc); } } static void l_1_p_1_encode(IBUF *ip) { char cdata, c_val, *line_buf, *line_ptr, *endl_buf, *start_ptr; FBUFPUB *output; int i; output = ip->output; if (ip->out_vrc != 1) { long limit = 1; ip->temp = *output; switch (ip->out_vrc) { case 2: limit += 2; case 3: case 4: limit += 1; } output->pbuf = ip->pbuf = ip->data - limit; output->bytes_left = limit; output->data_func = put_vrc; } line_ptr = line_buf = ip->pub.pbuf; do { endl_buf = line_buf + ip->byte_width; do { char *line_lim0 = line_buf + 255; if (line_lim0 > endl_buf) line_lim0 = endl_buf; for (;;) { if ((cdata = *line_buf++) == 0 || cdata == -1) { char *line_lim = --line_buf + 127; if (line_lim > endl_buf) line_lim = endl_buf; start_ptr = line_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); i = (int)(line_buf - start_ptr); if (i >= 3 || start_ptr == line_ptr || line_buf >= line_lim0) { put_solid: if (start_ptr != line_ptr) { FPUTC(output, 0x80); FPUTC(output, (char)(start_ptr - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < start_ptr); } cdata <<= 7; cdata |= (char)i; FPUTC(output, cdata); line_ptr = line_buf; break; } if (i == 2) { line_lim = line_buf; for (;;) if ((c_val = *line_lim++) == 0 || c_val == -1) { if (line_lim >= line_lim0) goto put_solid; if (*line_lim == c_val) goto put_solid; } else { if (line_lim >= line_lim0 - 1) break; if (c_val != *line_lim++) break; if (c_val != *line_lim++) break; if (line_lim >= line_lim0) goto put_solid; if (*line_lim == c_val) goto put_solid; } } line_buf = start_ptr + 1; } if (line_buf < endl_buf - 1 && cdata == line_buf[0] && cdata == line_buf[1]) { char *line_lim = --line_buf + 255; if (line_lim > endl_buf) line_lim = endl_buf; start_ptr = line_buf; do line_buf++; while (line_buf < line_lim && *line_buf == cdata); i = (int)(line_buf - start_ptr); if (i >= 5 || start_ptr == line_ptr || line_buf >= line_lim0) { put_pattern: if (start_ptr != line_ptr) { FPUTC(output, 0x80); FPUTC(output, (char)(start_ptr - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < start_ptr); } FPUTC(output, 0); FPUTC(output, (char)i); FPUTC(output, cdata); line_ptr = line_buf; break; } if (i == 4) { line_lim = line_buf; for (;;) if ((c_val = *line_lim++) == 0 || c_val == -1) { if (line_lim >= line_lim0) goto put_pattern; if (*line_lim == c_val) goto put_pattern; } else { if (line_lim >= line_lim0 - 1) break; if (c_val != *line_lim++) break; if (c_val != *line_lim++) break; if (line_lim >= line_lim0) goto put_pattern; if (*line_lim == c_val) goto put_pattern; } } line_buf = start_ptr + 1; } if (line_buf >= line_lim0) { FPUTC(output, 0x80); FPUTC(output, (char)(line_buf - line_ptr)); do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); break; } } } while (line_buf < endl_buf); } while (endl_buf < ip->image_adr); if (--ip->out_vrc) { line_buf = output->pbuf; *output = ip->temp; ++ip->out_vrc; do { line_ptr = ip->pbuf; do FPUTC(output, *line_ptr++); while (line_ptr < line_buf); } while (--ip->out_vrc); } } static void level_1_putline(IBUF *ip) { char *line_buf, *line_ptr, *endl_buf; line_buf = ip->line_adr; endl_buf = ip->pub.pbuf; line_ptr = endl_buf; if (ip->out_vrc == 0) { if (ip->pub.bytes_left) return; } else { if (ip->pub.bytes_left) { ip->pub.pbuf += ip->pub.bytes_left; ip->pub.bytes_left = 0; (*ip->raw_encode)(ip); ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; return; } do { if (*line_ptr != *line_buf) { (*ip->raw_encode)(ip); break; } line_ptr++; line_buf++; } while (line_buf < endl_buf); } while (line_buf < endl_buf) *line_ptr++ = *line_buf++; do { if (ip->out_vrc == 255) (*ip->raw_encode)(ip); ip->out_vrc++; if (--ip->lines_left <= 0) { (*ip->raw_encode)(ip); ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; (*ip->user_exit)(); } } while (--ip->pub.vrc); ip->pub.vrc++; ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length; }