1%% options 2 3copyright owner = Dirk Krause 4copyright year = 2015-xxxx 5SPDX-License-Identifier: BSD-3-Clause 6 7 8%% header 9 10/** @file dk4rld.h Run-length decoder. 11 12Use dk4rld_init() to initialize the decoder before feeding data to it. 13 14Feed the encoded data into the decoder byte by byte, use the 15dk4rld_add() function. 16If the function returns DK4_EDSTM_ACCEPT, the input was successfully stored 17into the internal data structures, not need for further action. 18If the function returns DK4_EDSTM_FINISHED, an output secquence was 19completed, either a run or a literal byte sequence. Use dk4rld_output() 20to retrieve output data. 21If the dk4rld_add function returns DK4_EDSTM_STOP, an end of data 22(EOD) marker was found; do not feed further bytes into the decoder. 23 24After feeding all input bytes into the decoder, use dk4rld_finish() to check 25syntax. If the function returns DK4_EDSTM_ERROR, the input data stream 26was not properly run-length encoded. 27*/ 28 29 30#ifndef DK4CONF_H_INCLUDED 31#if DK4_BUILDING_DKTOOLS4 32#include "dk4conf.h" 33#else 34#include <dktools-4/dk4conf.h> 35#endif 36#endif 37 38#ifndef DK4ERROR_H_INCLUDED 39#if DK4_BUILDING_DKTOOLS4 40#include <libdk4base/dk4error.h> 41#else 42#include <dktools-4/dk4error.h> 43#endif 44#endif 45 46/** Run length decoder. 47*/ 48typedef struct { 49 unsigned char ob[128]; /**< Output buffer. */ 50 size_t oused; /**< Number of used bytes in ob. */ 51 size_t ll; /**< Number of expected bytes. */ 52 int st; /**< Current state. */ 53} dk4_rl_dec_t; 54 55 56#ifdef __cplusplus 57extern "C" { 58#endif 59 60/** Initialize decoder. 61 @param dec Decoder to initialize. 62 @param erp Error report, may be NULL. 63 64 Error codes: 65 - DK4_E_INVALID_ARGUMENTS if enc is NULL. 66*/ 67void 68dk4rld_init(dk4_rl_dec_t *dec, dk4_er_t *erp); 69 70/** Add one encoded byte to decoder. 71 @param dec Decoder. 72 @param inbyte Byte to process. 73 @param erp Error report, may be NULL. 74 @return Action to take, one from: 75 - DK4_EDSTM_ACCEPT<br> 76 if the byte was successfully added 77 to the internal data structures, no further action necessary. 78 - DK4_EDSTM_FINISHED<br> 79 if output is available, use dk4rld_output() to retrieve output. 80 - DK4_EDSTM_STOP<br> 81 if an EOD marker was detected. Do not feed further bytes 82 to the decoder. 83 - DK4_EDSTM_ERROR<br> 84 if an error occured. 85 86 Error codes: 87 - DK4_E_INVALID_ARGUMENTS if enc is NULL. 88*/ 89int 90dk4rld_add(dk4_rl_dec_t *dec, unsigned char inbyte, dk4_er_t *erp); 91 92/** Finish decoding. 93 @param dec Decoder. 94 @param erp Error report, may be NULL. 95 @return Action to take, one from: 96 - DK4_EDSTM_ACCEPT<br> 97 if no remaining data is stored in the decoder, no further 98 action necessary. 99 - DK4_EDSTM_FINISHED<br> 100 if output is available, use dk4rld_output() to retrieve output. 101 - DK4_EDSTM_ERROR<br> 102 if an error occured. 103 104 Error codes: 105 - DK4_E_INVALID_ARGUMENTS<br> 106 if enc is NULL. 107 - DK4_E_SYNTAX<br> 108 if data indicated by the run-length byte or literally-length 109 byte is missing. 110*/ 111int 112dk4rld_finish(dk4_rl_dec_t *dec, dk4_er_t *erp); 113 114/** Retrieve decoder output. 115 @param dptr Address of pointer to set to decoder output, 116 should be initialized to NULL. 117 @param szptr Address of variable to receive buffer size, 118 should be initialized to 0. 119 @param dec Decoder. 120 @param erp Error report, may be NULL. 121 @return 1 if data is available, 0 otherwise. 122 123 Error codes: 124 - DK4_E_INVALID_ARGUMENTS if enc is NULL. 125*/ 126int 127dk4rld_output( 128 const unsigned char **dptr, 129 size_t *szptr, 130 dk4_rl_dec_t const *dec, 131 dk4_er_t *erp 132); 133 134#ifdef __cplusplus 135} 136#endif 137 138%% module 139 140#include "dk4conf.h" 141 142#if DK4_HAVE_ASSERT_H 143#ifndef ASSERT_H_INCLUDED 144#include <assert.h> 145#define ASSERT_H_INCLUDED 1 146#endif 147#endif 148 149#include <libdk4c/dk4rld.h> 150#include <libdk4c/dk4edstm.h> 151#include <libdk4base/dk4mem.h> 152 153 154 155$!trace-include 156 157 158 159/** Decoder states. 160*/ 161enum { 162 /** Start state, exepect run length 163 or literal data length. 164 */ 165 RLD_ST_EXPECT_KEY_BYTE = 0, 166 167 /** Expect byte value for run. 168 */ 169 RLD_ST_EXPECT_RUN_BYTE , 170 171 /** Expect literal byte. 172 */ 173 RLD_ST_EXPECT_LITERAL_BYTE , 174 175 /** No further input accepted as 176 EOD marker was found. 177 */ 178 RLD_ST_EOD_FOUND 179}; 180 181 182 183void 184dk4rld_init(dk4_rl_dec_t *dec, dk4_er_t *erp) 185{ 186 $? "+ dk4rld_init" 187#if DK4_USE_ASSERT 188 assert(NULL != dec); 189#endif 190 if (NULL != dec) { 191 DK4_MEMRES(dec, sizeof(dk4_rl_dec_t)); 192 dec->oused = 0; 193 dec->ll = 0; 194 dec->st = RLD_ST_EXPECT_KEY_BYTE; 195 } else { 196 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 197 } $? "- dk4rld_init" 198} 199 200 201 202int 203dk4rld_add(dk4_rl_dec_t *dec, unsigned char inbyte, dk4_er_t *erp) 204{ 205 int back = DK4_EDSTM_ERROR; 206 $? "+ dk4rld_add" 207#if DK4_USE_ASSERT 208 assert(NULL != dec); 209#endif 210 if (NULL != dec) { 211 switch (dec->st) { 212 case RLD_ST_EXPECT_KEY_BYTE : { 213 if ((unsigned char)128U > inbyte) { 214 /* 215 Literal byte sequence 216 */ 217 dec->st = RLD_ST_EXPECT_LITERAL_BYTE; 218 dec->ll = (size_t)inbyte + 1; 219 back = DK4_EDSTM_ACCEPT; 220 } else { 221 if ((unsigned char)128U < inbyte) { 222 /* 223 Run of equal bytes 224 */ 225 dec->st = RLD_ST_EXPECT_RUN_BYTE; 226 dec->ll = (size_t)257 - (size_t)inbyte; 227 back = DK4_EDSTM_ACCEPT; 228 } else { 229 /* 230 EOD marker found 231 */ 232 dec->st = RLD_ST_EOD_FOUND; 233 back = DK4_EDSTM_STOP; 234 } 235 } 236 } break; 237 case RLD_ST_EXPECT_RUN_BYTE : { 238 dk4mem_set(&(dec->ob[0]), dec->ll, inbyte, NULL); 239 dec->oused = dec->ll; 240 dec->st = RLD_ST_EXPECT_KEY_BYTE; 241 back = DK4_EDSTM_FINISHED; 242 } break; 243 case RLD_ST_EXPECT_LITERAL_BYTE : { 244 dec->ob[0] = inbyte; 245 dec->oused = 1; 246 dec->ll -= 1; 247 if (0 == dec->ll) { 248 dec->st = RLD_ST_EXPECT_KEY_BYTE; 249 } 250 back = DK4_EDSTM_FINISHED; 251 } break; 252 default : { 253 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); 254 } break; 255 } 256 } else { 257 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 258 } $? "- dk4rld_add %d", back 259 return back; 260} 261 262 263 264int 265dk4rld_finish(dk4_rl_dec_t *dec, dk4_er_t *erp) 266{ 267 int back = DK4_EDSTM_ERROR; 268 $? "+ dk4rld_finish" 269#if DK4_USE_ASSERT 270 assert(NULL != dec); 271#endif 272 if (NULL != dec) { 273 switch (dec->st) { 274 case RLD_ST_EXPECT_KEY_BYTE : case RLD_ST_EOD_FOUND : { 275 back = DK4_EDSTM_ACCEPT; 276 } break; 277 default : { 278 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); 279 } break; 280 } 281 } else { 282 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 283 } $? "- dk4rld_finish %d", back 284 return back; 285} 286 287 288 289int 290dk4rld_output( 291 const unsigned char **dptr, 292 size_t *szptr, 293 dk4_rl_dec_t const *dec, 294 dk4_er_t *erp 295) 296{ 297 int back = 0; 298 $? "+ dk4rld_output" 299#if DK4_USE_ASSERT 300 assert(NULL != dptr); 301 assert(NULL != szptr); 302 assert(NULL != dec); 303#endif 304 if (NULL != dec) { 305 if (0 < dec->oused) { 306 *dptr = &(dec->ob[0]); 307 *szptr = dec->oused; 308 back = 1; 309 } else { 310 *dptr = NULL; 311 *szptr = 0; 312 } 313 } else { 314 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 315 } $? "- dk4rld_output %d", back 316 return back; 317} 318 319