/* Copyright (C) 2016-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk4lzwe.ctr */ /** @file dk4lzwe.c The dk4lzwe module. */ #line 196 "dk4lzwe.ctr" #include "dk4conf.h" #include "dk4lzwe.h" #include "dk4mem.h" #include "dk4edstm.h" #if DK4_HAVE_ASSERT_H #ifndef ASSERT_H_INCLUDED #include #define ASSERT_H_INCLUDED 1 #endif #endif #line 211 "dk4lzwe.ctr" /** Code to clear tables. */ #define LZW_CLT ((unsigned short)256U) /** Code to indicate end of data. */ #define LZW_EOD ((unsigned short)257U) /** First user-made state. */ #define LZW_START ((unsigned short)258U) /** Bitmask values. */ static const unsigned short bit_values[] = { 0x0001U, 0x0002U, 0x0004U, 0x0008U, 0x0010U, 0x0020U, 0x0040U, 0x0080U, 0x0100U, 0x0200U, 0x0400U, 0x0800U, 0x1000U, 0x2000U, 0x4000U, 0x8000U }; /** Write bit sequence to output buffer. @param lzwptr LZW compression structure. @param val Bit sequence to write. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_BUFFER_TOO_SMALL
if the output buffer is full before finishing, - DK4_E_INVALID_ARGUMENTS
should not happen. */ static int dk4lzwe_shipout( dk4_lzwe_t *lzwptr, unsigned short val, dk4_er_t *erp ) { int back = 1; int res; unsigned short i; unsigned char uc; #line 267 "dk4lzwe.ctr" #if DK4_USE_ASSERT assert(NULL != lzwptr); #endif i = lzwptr->bits; while (0 < i--) { res = dk4bit_shift_add( &(lzwptr->bs), ((((unsigned short)0) != (val & bit_values[i])) ? (1) : (0)), NULL ); switch (res) { case DK4_EDSTM_ERROR : { #line 279 "dk4lzwe.ctr" back = 0; dk4error_set_simple_error_code(erp, DK4_E_BUG); } break; case DK4_EDSTM_FINISHED : { #line 283 "dk4lzwe.ctr" uc = dk4bit_shift_output(&(lzwptr->bs), NULL); if (8 > lzwptr->obu) { #line 285 "dk4lzwe.ctr" lzwptr->ob[lzwptr->obu] = uc; lzwptr->obu += 1; } else { #line 289 "dk4lzwe.ctr" back = 0; dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL); } } break; } } #line 296 "dk4lzwe.ctr" return back; } /** Clear all table entries. @param lzwptr Encoder to clean up. */ static void dk4lzwe_clear_table_entries( dk4_lzwe_t *lzwptr ) { dk4_lzw_cell_t *cptr; size_t i; #line 313 "dk4lzwe.ctr" #if DK4_USE_ASSERT assert(NULL != lzwptr); #endif cptr = lzwptr->p_tbl; for (i = 0; i < LZW_TABLE_SIZE; i++) { cptr[i].os = (unsigned short)0U; cptr[i].ns = (unsigned short)0U; cptr[i].in = (unsigned char)0x00; } #line 323 "dk4lzwe.ctr" } int dk4lzwe_init( dk4_lzwe_t *lzwptr, dk4_er_t *erp ) { int back = 0; #line 335 "dk4lzwe.ctr" #if DK4_USE_ASSERT assert(NULL != lzwptr); #endif if (NULL != lzwptr) { #line 339 "dk4lzwe.ctr" /* Default values for al components */ dk4mem_reset(lzwptr, sizeof(dk4_lzwe_t), NULL); lzwptr->p_tbl = NULL; lzwptr->obu = 0; lzwptr->mret = 0; lzwptr->hst = 0; lzwptr->bits = 9; lzwptr->cs = 0U; lzwptr->ns = LZW_START; dk4bit_shift_init(&(lzwptr->bs), NULL); /* Allocate memory for state transition table */ lzwptr->p_tbl = dk4mem_new(dk4_lzw_cell_t,LZW_TABLE_SIZE,erp); /* On success ship out initial clear table marker */ if (NULL != lzwptr->p_tbl) { #line 359 "dk4lzwe.ctr" dk4lzwe_clear_table_entries(lzwptr); back = dk4lzwe_shipout(lzwptr, LZW_CLT, erp); } #if TRACE_DEBUG else { #line 364 "dk4lzwe.ctr" } #endif } else { #line 368 "dk4lzwe.ctr" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 371 "dk4lzwe.ctr" return back; } static int dk4lzwe_i_add( dk4_lzwe_t *lzwptr, unsigned char uc, dk4_er_t *erp ) { int back = DK4_EDSTM_ERROR; #if TRACE_DEBUG int passno = 0; #endif int cc; int found; unsigned short ind; unsigned short offs; #line 393 "dk4lzwe.ctr" #if DK4_USE_ASSERT assert(NULL != lzwptr); #endif if (0 != lzwptr->hst) { #line 397 "dk4lzwe.ctr" /* Already input available, so we have to check the table for a matching rule */ ind = (lzwptr->cs) ^ ((((unsigned short)uc) << 4) & ((unsigned short)0x0FF0U)); #if 0 ind = ind % LZW_TABLE_SIZE; #endif offs = ((((unsigned short)0U) != ind) ? (LZW_TABLE_SIZE - ind) : (1)); cc = 1; found = 0; #line 409 "dk4lzwe.ctr" do { #line 410 "dk4lzwe.ctr" if ((unsigned short)0U != (lzwptr->p_tbl)[ind].ns) { #line 411 "dk4lzwe.ctr" if (lzwptr->cs == (lzwptr->p_tbl)[ind].os) { if (uc == (lzwptr->p_tbl)[ind].in) { found = 1; #line 414 "dk4lzwe.ctr" } } if (0 != found) { cc = 0; } else { #line 420 "dk4lzwe.ctr" ind += offs; ind = (ind % LZW_TABLE_SIZE); } } else { #line 425 "dk4lzwe.ctr" cc = 0; } #if TRACE_DEBUG passno++; #endif } while (0 < cc); #line 431 "dk4lzwe.ctr" #if TRACE_DEBUG #line 433 "dk4lzwe.ctr" #endif if (0 != found) { #line 435 "dk4lzwe.ctr" /* A matching rule was found, so we just change state. */ lzwptr->cs = (lzwptr->p_tbl)[ind].ns; back = DK4_EDSTM_ACCEPT; } else { #line 442 "dk4lzwe.ctr" /* No matching rule was found. We check whether or not we can add further entries to the table. */ if ((unsigned short)4094U <= lzwptr->ns) { #line 447 "dk4lzwe.ctr" /* Table is full, so we ship out the current state, clean we table and keep the input as new current state. */ if (0 != dk4lzwe_shipout(lzwptr, lzwptr->cs, erp)) { if (0 != dk4lzwe_shipout(lzwptr, LZW_CLT, erp)) { back = DK4_EDSTM_FINISHED; #line 454 "dk4lzwe.ctr" lzwptr->mret = 1; } } lzwptr->cs = (((unsigned short)0x00FFU) & ((unsigned short)uc)); lzwptr->bits = 9; lzwptr->ns = LZW_START; dk4lzwe_clear_table_entries(lzwptr); } else { #line 463 "dk4lzwe.ctr" /* There is still room in the table. Ship out current state, create new rule in the table and keep input as new current state. */ if (0 != dk4lzwe_shipout(lzwptr, lzwptr->cs, erp)) { back = DK4_EDSTM_FINISHED; #line 469 "dk4lzwe.ctr" lzwptr->mret = 1; } (lzwptr->p_tbl)[ind].os = lzwptr->cs; (lzwptr->p_tbl)[ind].ns = lzwptr->ns; (lzwptr->p_tbl)[ind].in = uc; #line 475 "dk4lzwe.ctr" /* Increase number of bits if necessary. */ switch ( (int)(lzwptr->ns) ) { case 511 : { #line 480 "dk4lzwe.ctr" lzwptr->bits = 10; } break; case 1023 : { lzwptr->bits = 11; #line 484 "dk4lzwe.ctr" } break; case 2047 : { lzwptr->bits = 12; #line 487 "dk4lzwe.ctr" } break; } lzwptr->ns += 1U; lzwptr->cs = (((unsigned short)0x00FFU) & ((unsigned short)uc)); } } } else { #line 495 "dk4lzwe.ctr" /* No current state yet (no input yet). Just store the input as current state. */ lzwptr->cs = (((unsigned short)0x00FFU) & ((unsigned short)uc)); lzwptr->hst = 1; back = DK4_EDSTM_ACCEPT; } #line 503 "dk4lzwe.ctr" return back; } int dk4lzwe_add( dk4_lzwe_t *lzwptr, unsigned char uc, dk4_er_t *erp ) { int back = DK4_EDSTM_ERROR; #line 517 "dk4lzwe.ctr" #if DK4_USE_ASSERT assert(NULL != lzwptr); #endif if (NULL != lzwptr) { if (NULL != lzwptr->p_tbl) { if (0 == lzwptr->mret) { back = dk4lzwe_i_add(lzwptr, uc, erp); } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 537 "dk4lzwe.ctr" return back; } int dk4lzwe_finish( dk4_lzwe_t *lzwptr, dk4_er_t *erp ) { int back = DK4_EDSTM_ERROR; unsigned char uc; #line 551 "dk4lzwe.ctr" #if DK4_USE_ASSERT assert(NULL != lzwptr); #endif if (NULL != lzwptr) { if (NULL != lzwptr->p_tbl) { if (0 == lzwptr->mret) { back = DK4_EDSTM_ACCEPT; /* Ship out current state, if any. */ if (0 != lzwptr->hst) { #line 562 "dk4lzwe.ctr" if (0 == dk4lzwe_shipout(lzwptr, lzwptr->cs, erp)) { back = DK4_EDSTM_ERROR; #line 564 "dk4lzwe.ctr" } } /* Ship out end of data marker. */ if (0 == dk4lzwe_shipout(lzwptr, LZW_EOD, erp)) { back = DK4_EDSTM_ERROR; #line 570 "dk4lzwe.ctr" } /* Apply final byte from bit shifter to output. */ switch ( dk4bit_shift_finish(&(lzwptr->bs), erp)) { case DK4_EDSTM_ERROR : { back = DK4_EDSTM_ERROR; #line 576 "dk4lzwe.ctr" } break; case DK4_EDSTM_FINISHED : { uc = dk4bit_shift_output(&(lzwptr->bs), NULL); if (8 > lzwptr->obu) { #line 580 "dk4lzwe.ctr" lzwptr->ob[lzwptr->obu] = uc; lzwptr->obu += 1; } else { #line 584 "dk4lzwe.ctr" back = DK4_EDSTM_ERROR; dk4error_set_simple_error_code( erp, DK4_E_BUFFER_TOO_SMALL ); } } break; } /* Check whether the caller must retrieve final output. */ if ((DK4_EDSTM_ACCEPT == back) && (0 < lzwptr->obu)) { back = DK4_EDSTM_FINISHED; #line 595 "dk4lzwe.ctr" lzwptr->mret = 1; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } dk4mem_free(lzwptr->p_tbl); lzwptr->p_tbl = NULL; } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 612 "dk4lzwe.ctr" return back; } int dk4lzwe_output( const unsigned char **dptr, size_t *szptr, dk4_lzwe_t *lzwptr, dk4_er_t *erp ) { int back = 0; #line 627 "dk4lzwe.ctr" #if DK4_USE_ASSERT assert(NULL != dptr); assert(NULL != szptr); assert(NULL != lzwptr); #endif if ((NULL != dptr) && (NULL != szptr) && (NULL != lzwptr)) { /* All arguments ok, do normal output operation. */ *dptr = &(lzwptr->ob[0]); *szptr = lzwptr->obu; back = ((0 < lzwptr->obu) ? (1) : (0)); lzwptr->mret = 0; #line 640 "dk4lzwe.ctr" lzwptr->obu = 0; } else { #line 643 "dk4lzwe.ctr" /* Argument error, indicate no data available. */ if (NULL != dptr) { *dptr = NULL; } if (NULL != szptr) { *szptr = 0; } dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 655 "dk4lzwe.ctr" return back; } /* vim: set ai sw=4 ts=4 : */