/* 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: dk4rle.ctr */ /* Copyright (C) 2015-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 dk4rle.c The dk4rle module. */ #line 127 "dk4rle.ctr" #include "dk4rle.h" #include "dk4edstm.h" #include "dk4mem.h" #include "dk4memcpl.h" #line 136 "dk4rle.ctr" /** Run length encoder state. */ enum { /** No run detected yet. */ RLE_ENC_STATE_NO_RUN = 0, /** Currently in a run. */ RLE_ENC_STATE_RUN }; /** Calculate byte for a run length. @param sz Length of the run. @return Byte value to indicate length. */ static unsigned char dk4rle_run_length_byte(size_t sz) { return ((unsigned char)(257 - sz)); } /** Calculate byte for a literal length. @param sz Length of literal data. @return Byte value to indicate the length. */ static unsigned char dk4rle_literal_length_byte(size_t sz) { return ((unsigned char)(sz - 1)); } void dk4rle_init(dk4_rl_enc_t *enc, int weod, dk4_er_t *erp) { if (NULL != enc) { enc->ib = &(enc->ob[1]); enc->oused = 0; enc->iused = 0; enc->ao_si = 0; enc->ao_ss = 0; enc->ao_iu = 0; enc->ao_st = RLE_ENC_STATE_NO_RUN; enc->st = RLE_ENC_STATE_NO_RUN; enc->lwo = 0; enc->weod = ((0 != weod) ? 1 : 0); } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } static void dk4rle_process_lwo(dk4_rl_enc_t *enc) { if (0 < enc->ao_ss) { dk4mem_cpy_to_left( enc->ib, &((enc->ib)[enc->ao_si]), enc->ao_ss, NULL ); } enc->iused = enc->ao_iu; enc->st = enc->ao_st; enc->lwo = 0; } int dk4rle_add(dk4_rl_enc_t *enc, unsigned char ibyte, dk4_er_t *erp) { int back = DK4_EDSTM_ERROR; int cr = 0; /* Flag: Change to run */ #line 226 "dk4rle.ctr" if (NULL != enc) { if (0 != enc->lwo) { dk4rle_process_lwo(enc); } #line 229 "dk4rle.ctr" back = DK4_EDSTM_ACCEPT; (enc->ib)[enc->iused] = ibyte; enc->iused += 1; switch (enc->st) { case RLE_ENC_STATE_RUN : { /* In a run. */ if ((enc->ib)[enc->iused - 1] != (enc->ib)[enc->iused - 2]) { #line 239 "dk4rle.ctr" /* End of run, change to normal mode. */ enc->ob[0] = dk4rle_run_length_byte(enc->iused - 1); enc->oused = 2; back = DK4_EDSTM_FINISHED; enc->ao_si = enc->iused - 1; enc->ao_ss = 1; enc->ao_iu = 1; enc->ao_st = RLE_ENC_STATE_NO_RUN; } else { /* No end of run, continue. */ if (128 <= enc->iused) { #line 255 "dk4rle.ctr" /* Full 128 byte run, output. */ enc->ob[0] = dk4rle_run_length_byte(128); enc->oused = 2; back = DK4_EDSTM_FINISHED; enc->ao_si = 0; enc->ao_ss = 0; enc->ao_iu = 0; enc->ao_st = RLE_ENC_STATE_NO_RUN; } } } break; default : { /* Not in a run. */ if (4 <= enc->iused) { if (enc->ib[enc->iused - 1] == enc->ib[enc->iused - 2]) { if (enc->ib[enc->iused - 1] == enc->ib[enc->iused - 3]) { if (enc->ib[enc->iused - 1] == enc->ib[enc->iused - 4]) { cr = 1; #line 277 "dk4rle.ctr" } } } } if (1 == cr) { #line 283 "dk4rle.ctr" if (4 < enc->iused) { enc->ob[0] = dk4rle_literal_length_byte(enc->iused - 4); enc->oused = (enc->iused - 3); back = DK4_EDSTM_FINISHED; enc->ao_si = enc->iused - 4; enc->ao_ss = 4; enc->ao_iu = 4; enc->ao_st = RLE_ENC_STATE_RUN; } else { enc->st = RLE_ENC_STATE_RUN; } } else { if (128 <= enc->iused) { if ((enc->ib)[127] == (enc->ib)[126]) { if ((enc->ib)[127] == (enc->ib)[125]) { #line 298 "dk4rle.ctr" enc->ob[0] = dk4rle_literal_length_byte(125); enc->oused = 126; back = DK4_EDSTM_FINISHED; enc->ao_si = 125; enc->ao_ss = 3; enc->ao_iu = 3; enc->ao_st = RLE_ENC_STATE_NO_RUN; } else { #line 306 "dk4rle.ctr" enc->ob[0] = dk4rle_literal_length_byte(126); enc->oused = 127; back = DK4_EDSTM_FINISHED; enc->ao_si = 126; enc->ao_ss = 2; enc->ao_iu = 2; enc->ao_st = RLE_ENC_STATE_NO_RUN; } } else { #line 315 "dk4rle.ctr" enc->ob[0] = dk4rle_literal_length_byte(128); enc->oused = 129; back = DK4_EDSTM_FINISHED; enc->ao_si = 0; enc->ao_ss = 0; enc->ao_iu = 0; enc->ao_st = RLE_ENC_STATE_NO_RUN; } } } } break; } if (DK4_EDSTM_FINISHED == back) { enc->lwo = 1; #line 329 "dk4rle.ctr" } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 333 "dk4rle.ctr" return back; } int dk4rle_finish(dk4_rl_enc_t *enc, dk4_er_t *erp) { int back = DK4_EDSTM_ERROR; #line 343 "dk4rle.ctr" if (NULL != enc) { if (0 != enc->lwo) { dk4rle_process_lwo(enc); } back = DK4_EDSTM_ACCEPT; if (0 < enc->iused) { #line 347 "dk4rle.ctr" switch (enc->st) { case RLE_ENC_STATE_RUN : { #line 349 "dk4rle.ctr" enc->ob[0] = dk4rle_run_length_byte(enc->iused); enc->oused = 2; back = DK4_EDSTM_FINISHED; enc->ao_si = 0; enc->ao_ss = 0; enc->ao_iu = 0; enc->ao_st = RLE_ENC_STATE_NO_RUN; if (0 != enc->weod) { #line 357 "dk4rle.ctr" enc->ob[2] = (unsigned char)128; enc->oused = 3; } } break; default : { #line 362 "dk4rle.ctr" enc->ob[0] = dk4rle_literal_length_byte(enc->iused); enc->oused = enc->iused + 1; back = DK4_EDSTM_FINISHED; enc->ao_si = 0; enc->ao_ss = 0; enc->ao_iu = 0; enc->ao_st = RLE_ENC_STATE_NO_RUN; if (0 != enc->weod) { #line 370 "dk4rle.ctr" enc->ob[enc->iused] = (unsigned char)128; enc->oused += 1; } } break; } } else { if (0 != enc->weod) { #line 377 "dk4rle.ctr" enc->ob[0] = (unsigned char)128; enc->oused = 1; back = DK4_EDSTM_FINISHED; enc->ao_si = 0; enc->ao_ss = 0; enc->ao_iu = 0; enc->ao_st = RLE_ENC_STATE_NO_RUN; } } if (DK4_EDSTM_FINISHED == back) { enc->lwo = 1; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 392 "dk4rle.ctr" return back; } int dk4rle_output( const unsigned char **dptr, size_t *szptr, dk4_rl_enc_t *enc, dk4_er_t *erp ) { int back = 0; if ((NULL != enc) && (NULL != dptr) && (NULL != szptr)) { if (0 < enc->oused) { *dptr = &(enc->ob[0]); *szptr = enc->oused; back = 1; } else { *dptr = NULL; *szptr = 0; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } /* Below is the first working code for the module. This code worked perfectly fine, but for performance reasons I wanted to avoid the memory copy operations from input buffer to output buffer. If there is any problem with the current code, we have the chance to go back and test with the original code. */ #if 0 /* ---------- Header ---------- */ #include "dk4error.h" /** Run length encoder. */ typedef struct { unsigned char ob[144]; /**< Output buffer. */ unsigned char ib[128]; /**< Input buffer. */ size_t iused; /**< Number of bytes in ib. */ size_t oused; /**< Number of bytes in ob. */ int st; /**< Current state. */ int weod; /**< Flag: Write EOD marker at end. */ } dk4_rl_enc_t; #ifdef __cplusplus extern "C" { #endif /** Initialize encoder before using it. @param enc Encoder to initialize. @param weod Flag: Write EOD marker at end of data. @param erp Error report, may be NULL. Error codes: - DK4_E_INVALID_ARGUMENTS if enc is NULL. */ void dk4rle_init(dk4_rl_enc_t *enc, int weod, dk4_er_t *erp); /** Add a single byte to the encoder. @param enc Encoder. @param ibyte Input byte to process. @param erp Error report, may be NULL. @return Action to take, one from: - DK4_EDSTM_ACCEPT
if the input byte was successfully stored in the internal data structures without completing a run. No further action necessary. - DK4_EDSTM_FINISHED
if a run was completed. Use dk4rle_output() to obtain the output data. - DK4_EDSTM_ERROR
if an error occured. Error codes: - DK4_E_INVALID_ARGUMENTS if enc is NULL. */ int dk4rle_add(dk4_rl_enc_t *enc, unsigned char ibyte, dk4_er_t *erp); /** Finish data stream, process final data still stored in the encoder. @param enc Encoder. @param erp Error report, may be NULL. @return Action to take, one from: - DK4_EDSTM_ACCEPT
if the input byte was successfully stored in the internal data structures without completing a run. No further action necessary. - DK4_EDSTM_FINISHED
if a run was completed. Use dk4rle_output() to obtain the output data. - DK4_EDSTM_ERROR
if an error occured. Error codes: - DK4_E_INVALID_ARGUMENTS if enc is NULL. */ int dk4rle_finish(dk4_rl_enc_t *enc, dk4_er_t *erp); /** Retrieve encoder output. @param dptr Address of pointer to set to output bytes, should be initialized to NULL. @param szptr Address of size variable for buffer length, should be initialized to 0. @param enc Encoder. @param erp Error report, may be NULL. @return 1 if there is data available, 0 otherwise. Error codes: - DK4_E_INVALID_ARGUMENTS if enc is NULL. */ int dk4rle_output( const unsigned char **dptr, size_t *szptr, dk4_rl_enc_t *enc, dk4_er_t *erp ); #ifdef __cplusplus } #endif /* ---------------------------- */ /* ---------- Module ---------- */ #include "dk4rle.h" #include "dk4edstm.h" #include "dk4mem.h" #include "dk4memcpl.h" #line 529 "dk4rle.ctr" /** Run length encoder state. */ enum { /** No run detected yet. */ RLE_ENC_STATE_NO_RUN = 0, /** Currently in a run. */ RLE_ENC_STATE_RUN }; void dk4rle_init(dk4_rl_enc_t *enc, int weod, dk4_er_t *erp) { #line 546 "dk4rle.ctr" if (NULL != enc) { DK4_MEMRES(enc, sizeof(dk4_rl_enc_t)); enc->st = RLE_ENC_STATE_NO_RUN; enc->iused = 0; enc->oused = 0; enc->weod = ((0 != weod) ? 1 : 0); } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 555 "dk4rle.ctr" } /** Calculate byte for a run length. @param sz Length of the run. @return Byte value to indicate length. */ static unsigned char dk4rle_run_length_byte(size_t sz) { return ((unsigned char)(257 - sz)); } /** Calculate byte for a literal length. @param sz Length of literal data. @return Byte value to indicate the length. */ static unsigned char dk4rle_literal_length_byte(size_t sz) { return ((unsigned char)(sz - 1)); } int dk4rle_add(dk4_rl_enc_t *enc, unsigned char ibyte, dk4_er_t *erp) { int back = DK4_EDSTM_ERROR; int cr = 0; /* Flag: Change run */ #line 585 "dk4rle.ctr" if (NULL != enc) { #line 586 "dk4rle.ctr" #line 587 "dk4rle.ctr" back = DK4_EDSTM_ACCEPT; #line 588 "dk4rle.ctr" enc->ib[enc->iused] = ibyte; #line 589 "dk4rle.ctr" enc->iused += 1; #line 590 "dk4rle.ctr" switch (enc->st) { case RLE_ENC_STATE_RUN : { #line 592 "dk4rle.ctr" if (enc->ib[enc->iused - 1] != enc->ib[enc->iused - 2]) { /* Copy data to output buffer. */ enc->ob[1] = enc->ib[enc->iused - 2]; /* Set run-length byte. */ enc->ob[0] = dk4rle_run_length_byte(enc->iused - 1); /* Set total byte size. */ enc->oused = 2; /* Keep input byte. */ enc->ib[0] = enc->ib[enc->iused - 1]; /* Number of input bytes is 1 now. */ enc->iused = 1; /* Output ready. */ back = DK4_EDSTM_FINISHED; /* No longer in a run. */ enc->st = RLE_ENC_STATE_NO_RUN; } else { if (128 <= enc->iused) { /* Copy data to output buffer. */ enc->ob[1] = enc->ib[0]; /* Set run-length byte. */ enc->ob[0] = dk4rle_run_length_byte(128); /* Set total byte size. */ enc->oused = 2; /* No input bytes available. */ enc->iused = 0; /* Output ready. */ back = DK4_EDSTM_FINISHED; /* No longer in a run. */ enc->st = RLE_ENC_STATE_NO_RUN; } } } break; default : { #line 638 "dk4rle.ctr" if (4 <= enc->iused) { #line 639 "dk4rle.ctr" if (enc->ib[enc->iused - 1] == enc->ib[enc->iused - 2]) { #line 640 "dk4rle.ctr" if (enc->ib[enc->iused - 1] == enc->ib[enc->iused - 3]) { #line 641 "dk4rle.ctr" if (enc->ib[enc->iused - 1] == enc->ib[enc->iused - 4]) { #line 642 "dk4rle.ctr" cr = 1; } } } if (1 == cr) { #line 647 "dk4rle.ctr" /* Start of run. */ if (4 < enc->iused) { /* Output the literal data before run. */ /* Copy data to output buffer. */ DK4_MEMCPY( &(enc->ob[1]), &(enc->ib[0]), (enc->iused - 4)); /* Set run-length byte. */ enc->ob[0] = dk4rle_literal_length_byte(enc->iused - 4); /* Set total byte size. */ enc->oused = enc->iused - 3; /* Keep last 4 bytes. */ dk4mem_cpy_to_left( &(enc->ib[0]), &(enc->ib[enc->iused - 4]), 4, NULL ); /* Number of used input bytes is 4. */ enc->iused = 4; back = DK4_EDSTM_FINISHED; } enc->st = RLE_ENC_STATE_RUN; } else { #line 677 "dk4rle.ctr" if (128 <= enc->iused) { if (enc->ib[enc->iused - 1] == enc->ib[enc->iused - 2]) { if (enc->ib[enc->iused - 1] == enc->ib[enc->iused - 3]) { /* Keep final 3 bytes, potentially start of run. */ /* Copy data to output buffer. */ DK4_MEMCPY( &(enc->ob[1]), &(enc->ib[0]), 125); /* Set run-length byte. */ enc->ob[0] = dk4rle_literal_length_byte(128 - 3); /* Set total byte size. */ enc->oused = 126; /* Keep last 3 bytes. */ dk4mem_cpy_to_left( &(enc->ib[0]), &(enc->ib[125]), 3, NULL ); /* Number of used bytes is 2. */ enc->iused = 3; } else { /* Keep final 2 bytes, potentially start of run. */ /* Copy data. */ DK4_MEMCPY( &(enc->ob[1]), &(enc->ib[0]), 126 ); /* Set run-length byte. */ enc->ob[0] = dk4rle_literal_length_byte(128 - 2); /* Set total byte size. */ enc->oused = 127; /* Keep last 2 bytes. */ dk4mem_cpy_to_left( &(enc->ib[0]), &(enc->ib[126]), 2, NULL ); /* Number of used bytes is 2. */ enc->iused = 2; } } else { /* No need to keep any final bytes. */ /* Copy data. */ DK4_MEMCPY( &(enc->ob[1]), &(enc->ib[0]), enc->iused ); /* Set run-length byte. */ enc->ob[0] = dk4rle_literal_length_byte(128); /* Set total byte size. */ enc->oused = 129; /* No input byte in buffer. */ enc->iused = 0; } back = DK4_EDSTM_FINISHED; } } } } break; } } else { #line 750 "dk4rle.ctr" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 752 "dk4rle.ctr" return back; } int dk4rle_finish(dk4_rl_enc_t *enc, dk4_er_t *erp) { int back = DK4_EDSTM_ERROR; #line 760 "dk4rle.ctr" if (NULL != enc) { back = DK4_EDSTM_ACCEPT; if (0 < enc->iused) { switch (enc->st) { case RLE_ENC_STATE_RUN : { /* Copy data to output buffer. */ enc->ob[1] = enc->ib[0]; /* Set run-length byte. */ enc->ob[0] = dk4rle_run_length_byte(enc->iused); /* Set total byte size. */ enc->oused = 2; if (0 != enc->weod) { /* Add EOD marker. */ enc->ob[2] = (unsigned char)128; enc->oused = 3; } } break; default : { /* Copy data to output buffer. */ DK4_MEMCPY( &(enc->ob[1]), &(enc->ib[0]), enc->iused ); /* Set literal length byte. */ enc->ob[0] = dk4rle_literal_length_byte(enc->iused); /* Set total byte size. */ enc->oused = 1 + enc->iused; if (0 != enc->weod) { /* Add EOD marker. */ enc->ob[1 + enc->iused] = (unsigned char)128; enc->oused += 1; } } break; } back = DK4_EDSTM_FINISHED; } else { if (0 != enc->weod) { enc->ob[0] = (unsigned char)128; enc->oused = 1; back = DK4_EDSTM_FINISHED; } } enc->iused = 0; enc->st = RLE_ENC_STATE_NO_RUN; } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 812 "dk4rle.ctr" return back; } int dk4rle_output( const unsigned char **dptr, size_t *szptr, dk4_rl_enc_t *enc, dk4_er_t *erp ) { int back = 0; #line 822 "dk4rle.ctr" if (NULL != enc) { if (0 < enc->oused) { *dptr = &(enc->ob[0]); *szptr = enc->oused; back = 1; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 831 "dk4rle.ctr" return back; } /* ---------------------------- */ #endif