/* WARNING: This file was generated by dkct. 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 */ /* Copyright (C) 2016-2017, Dirk Krause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dk4lzwe.c The dk4lzwe module. */ #line 179 "dk4lzwe.ctr" #include "dk4lzwe.h" #include "dk4mem.h" #include "dk4edstm.h" #line 188 "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 244 "dk4lzwe.ctr" 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 253 "dk4lzwe.ctr" back = 0; dk4error_set_simple_error_code(erp, DK4_E_BUG); } break; case DK4_EDSTM_FINISHED : { #line 257 "dk4lzwe.ctr" uc = dk4bit_shift_output(&(lzwptr->bs), NULL); if (8 > lzwptr->obu) { #line 259 "dk4lzwe.ctr" lzwptr->ob[lzwptr->obu] = uc; lzwptr->obu += 1; } else { #line 263 "dk4lzwe.ctr" back = 0; dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL); } } break; } } #line 270 "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 287 "dk4lzwe.ctr" 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 294 "dk4lzwe.ctr" } int dk4lzwe_init( dk4_lzwe_t *lzwptr, dk4_er_t *erp ) { int back = 0; #line 306 "dk4lzwe.ctr" if (NULL != lzwptr) { #line 307 "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 327 "dk4lzwe.ctr" dk4lzwe_clear_table_entries(lzwptr); back = dk4lzwe_shipout(lzwptr, LZW_CLT, erp); } #if TRACE_DEBUG else { #line 332 "dk4lzwe.ctr" } #endif } else { #line 336 "dk4lzwe.ctr" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 339 "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 361 "dk4lzwe.ctr" if (0 != lzwptr->hst) { #line 362 "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 374 "dk4lzwe.ctr" do { #line 375 "dk4lzwe.ctr" if ((unsigned short)0U != (lzwptr->p_tbl)[ind].ns) { #line 376 "dk4lzwe.ctr" if (lzwptr->cs == (lzwptr->p_tbl)[ind].os) { if (uc == (lzwptr->p_tbl)[ind].in) { found = 1; #line 379 "dk4lzwe.ctr" } } if (0 != found) { cc = 0; } else { #line 385 "dk4lzwe.ctr" ind += offs; ind = (ind % LZW_TABLE_SIZE); } } else { #line 390 "dk4lzwe.ctr" cc = 0; } #if TRACE_DEBUG passno++; #endif } while (0 < cc); #line 396 "dk4lzwe.ctr" #if TRACE_DEBUG #line 398 "dk4lzwe.ctr" #endif if (0 != found) { #line 400 "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 407 "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 412 "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 419 "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 428 "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 434 "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 440 "dk4lzwe.ctr" /* Increase number of bits if necessary. */ switch ( (int)(lzwptr->ns) ) { case 511 : { #line 445 "dk4lzwe.ctr" lzwptr->bits = 10; } break; case 1023 : { lzwptr->bits = 11; #line 449 "dk4lzwe.ctr" } break; case 2047 : { lzwptr->bits = 12; #line 452 "dk4lzwe.ctr" } break; } lzwptr->ns += 1U; lzwptr->cs = (((unsigned short)0x00FFU) & ((unsigned short)uc)); } } } else { #line 460 "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 468 "dk4lzwe.ctr" return back; } int dk4lzwe_add( dk4_lzwe_t *lzwptr, unsigned char uc, dk4_er_t *erp ) { int back = DK4_EDSTM_ERROR; #line 482 "dk4lzwe.ctr" 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 499 "dk4lzwe.ctr" return back; } int dk4lzwe_finish( dk4_lzwe_t *lzwptr, dk4_er_t *erp ) { int back = DK4_EDSTM_ERROR; unsigned char uc; #line 513 "dk4lzwe.ctr" 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 521 "dk4lzwe.ctr" if (0 == dk4lzwe_shipout(lzwptr, lzwptr->cs, erp)) { back = DK4_EDSTM_ERROR; #line 523 "dk4lzwe.ctr" } } /* Ship out end of data marker. */ if (0 == dk4lzwe_shipout(lzwptr, LZW_EOD, erp)) { back = DK4_EDSTM_ERROR; #line 529 "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 535 "dk4lzwe.ctr" } break; case DK4_EDSTM_FINISHED : { uc = dk4bit_shift_output(&(lzwptr->bs), NULL); if (8 > lzwptr->obu) { #line 539 "dk4lzwe.ctr" lzwptr->ob[lzwptr->obu] = uc; lzwptr->obu += 1; } else { #line 543 "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 554 "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 571 "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 586 "dk4lzwe.ctr" 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 594 "dk4lzwe.ctr" lzwptr->obu = 0; } else { #line 597 "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 609 "dk4lzwe.ctr" return back; } /* vim: set ai sw=4 ts=4 : */