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