1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2015-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7
8
9%%	header
10
11/**	@file	dk4ahd.h	ASCIIHex decoder.
12
13First initialize the decoder using the dk4ahex_dec_init() function.
14
15Add text characters using the dk4ahex_dec_add() function.
16The function returns DK4_EDSTM_ACCEPT if the text character was successfully
17stored in the decoder without completing a byte.
18The DK4_EDSTM_FINISHED return code indicates that a byte was finished, use
19dk4ahex_dec_output() to retrieve it.
20The DK4_EDSTM_STOP return code indicates that an end of data (EOD) marker
21was found.
22
23After feeding all text characters into the decoder use dk4ahex_dec_finish()
24to check whether there is an unprocessed half-byte stored.
25If the function returns DK4_EDSTM_FINISHED, use dk4ahex_dec_output() to
26retrieve the final byte.
27
28Note: The call to dk4ahex_dec_finish() is also necessary after
29obtaining DK4_EDSTM_STOP from dk4ahex_dec_add().
30
31*/
32
33
34#ifndef	DK4CONF_H_INCLUDED
35#if	DK4_BUILDING_DKTOOLS4
36#include "dk4conf.h"
37#else
38#include <dktools-4/dk4conf.h>
39#endif
40#endif
41
42#ifndef	DK4ERROR_H_INCLUDED
43#if	DK4_BUILDING_DKTOOLS4
44#include <libdk4base/dk4error.h>
45#else
46#include <dktools-4/dk4error.h>
47#endif
48#endif
49
50
51/**	ASCII-Hex decoder.
52*/
53typedef struct {
54  int			cpos;	/**< Current position. */
55  unsigned char		obyte;	/**< Output byte. */
56} dk4_ahex_dec_t;
57
58#ifdef __cplusplus
59extern "C" {
60#endif
61
62/**	Initialize decoder.
63	@param	dec	Decoder to initialize.
64	@param	erp	Error report, may be NULL.
65*/
66void
67
68dk4ahex_dec_init(dk4_ahex_dec_t *dec, dk4_er_t *erp);
69
70/**	Add text character to decoder.
71	@param	dec	Decoder.
72	@param	tc	Text character to add.
73	@param	erp	Error report, may be NULL.
74	@return	Action to take:
75	- DK4_EDSTM_ACCEPT<br>
76	  if the text was saved in the decoder, no action necessary.
77	- DK4_EDSTM_FINISHED<br>
78	  if a byte was completed, use dk4ahex_dec_output() to retrieve
79	  the byte.
80	- DK4_EDSTM_STOP<br>
81	  if the end of data (EOD) marker was detected.
82	  Use dk4ahex_dec_finish() to check whether there is still data
83	  in the decoder.
84	- DK4_EDSTM_ERROR<br>
85	  if an error occured.
86*/
87int
88
89dk4ahex_dec_add(dk4_ahex_dec_t *dec, char tc, dk4_er_t *erp);
90
91/**	Check for final byte.
92	@param	dec	Decoder.
93	@param	erp	Error report, may be NULL.
94	@return	Action to take, one from:
95	- DK4_EDSTM_ACCEPT<br>
96	  if there is no action necessary.
97	- DK4_EDSTM_FINISHED<br>
98	  if there is data available, use dk4ahex_dec_output() to retrieve
99	  the byte.
100	- DK4_EDSTM_ERROR<br>
101	  if an error occured.
102*/
103int
104
105dk4ahex_dec_finish(dk4_ahex_dec_t *dec, dk4_er_t *erp);
106
107/**	Retrieve current decoder content.
108	@param	dec	Decoder.
109	@param	erp	Error report, may be NULL.
110	@return	The current byte stored in the decoder.
111*/
112unsigned char
113
114dk4ahex_dec_output(dk4_ahex_dec_t const *dec, dk4_er_t *erp);
115
116#ifdef __cplusplus
117}
118#endif
119
120%%	module
121
122#include "dk4conf.h"
123
124#if	DK4_HAVE_ASSERT_H
125#ifndef	ASSERT_H_INCLUDED
126#include <assert.h>
127#define	ASSERT_H_INCLUDED 1
128#endif
129#endif
130
131#include <libdk4c/dk4ahd.h>
132#include <libdk4base/dk4mem.h>
133#include <libdk4c/dk4edstm.h>
134
135
136
137$!trace-include
138
139
140
141void
142
143dk4ahex_dec_init(dk4_ahex_dec_t *dec, dk4_er_t *erp)
144{
145#if	DK4_USE_ASSERT
146  assert(NULL != dec);
147#endif
148  if (NULL != dec) {
149    DK4_MEMRES(dec, sizeof(dk4_ahex_dec_t));
150    dec->cpos =  0;
151    dec->obyte = 0x00;
152  } else {
153    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
154  }
155}
156
157
158
159int
160
161dk4ahex_dec_add(dk4_ahex_dec_t *dec, char tc, dk4_er_t *erp)
162{
163  int		 back = DK4_EDSTM_ERROR;
164#if	DK4_USE_ASSERT
165  assert(NULL != dec);
166#endif
167  if (NULL != dec) {
168    switch (tc) {
169      case ' ' : case '\t' : case '\r' : case '\n' : case 0x00 : case 0x0C : {
170        back = DK4_EDSTM_ACCEPT;
171      } break;
172      case '>' : {
173        back = DK4_EDSTM_STOP;
174      } break;
175      case '0' : {
176        if (0 != dec->cpos) {
177          dec->cpos  = 2;
178	} else {
179	  dec->obyte = 0x00;
180	  dec->cpos  = 1;
181	}
182      } break;
183      case '1' : {
184        if (0 != dec->cpos) {
185	  dec->obyte |= 0x01; dec->cpos  = 2;
186	} else {
187	  dec->obyte = 0x10; dec->cpos  = 1;
188	}
189      } break;
190      case '2' : {
191        if (0 != dec->cpos) {
192	  dec->obyte |= 0x02; dec->cpos  = 2;
193	} else {
194	  dec->obyte = 0x20; dec->cpos  = 1;
195	}
196      } break;
197      case '3' : {
198        if (0 != dec->cpos) {
199	  dec->obyte |= 0x03; dec->cpos  = 2;
200	} else {
201	  dec->obyte = 0x30; dec->cpos  = 1;
202	}
203      } break;
204      case '4' : {
205        if (0 != dec->cpos) {
206	  dec->obyte |= 0x04; dec->cpos  = 2;
207	} else {
208	  dec->obyte = 0x40; dec->cpos  = 1;
209	}
210      } break;
211      case '5' : {
212        if (0 != dec->cpos) {
213	  dec->obyte |= 0x05; dec->cpos  = 2;
214	} else {
215	  dec->obyte = 0x50; dec->cpos  = 1;
216	}
217      } break;
218      case '6' : {
219        if (0 != dec->cpos) {
220	  dec->obyte |= 0x06; dec->cpos  = 2;
221	} else {
222	  dec->obyte = 0x60; dec->cpos  = 1;
223	}
224      } break;
225      case '7' : {
226        if (0 != dec->cpos) {
227	  dec->obyte |= 0x07; dec->cpos  = 2;
228	} else {
229	  dec->obyte = 0x70; dec->cpos  = 1;
230	}
231      } break;
232      case '8' : {
233        if (0 != dec->cpos) {
234	  dec->obyte |= 0x08; dec->cpos  = 2;
235	} else {
236	  dec->obyte = 0x80; dec->cpos  = 1;
237	}
238      } break;
239      case '9' : {
240        if (0 != dec->cpos) {
241	  dec->obyte |= 0x09; dec->cpos  = 2;
242	} else {
243	  dec->obyte = 0x90; dec->cpos  = 1;
244	}
245      } break;
246      case 'a' : case 'A' : {
247        if (0 != dec->cpos) {
248	  dec->obyte |= 0x0A; dec->cpos  = 2;
249	} else {
250	  dec->obyte = 0xA0; dec->cpos  = 1;
251	}
252      } break;
253      case 'b' : case 'B' : {
254        if (0 != dec->cpos) {
255	  dec->obyte |= 0x0B; dec->cpos  = 2;
256	} else {
257	  dec->obyte = 0xB0; dec->cpos  = 1;
258	}
259      } break;
260      case 'c' : case 'C' : {
261        if (0 != dec->cpos) {
262	  dec->obyte |= 0x0C; dec->cpos  = 2;
263	} else {
264	  dec->obyte = 0xC0; dec->cpos  = 1;
265	}
266      } break;
267      case 'd' : case 'D' : {
268        if (0 != dec->cpos) {
269	  dec->obyte |= 0x0D; dec->cpos  = 2;
270	} else {
271	  dec->obyte = 0xD0; dec->cpos  = 1;
272	}
273      } break;
274      case 'e' : case 'E' : {
275        if (0 != dec->cpos) {
276	  dec->obyte |= 0x0E; dec->cpos  = 2;
277	} else {
278	  dec->obyte = 0xE0; dec->cpos  = 1;
279	}
280      } break;
281      case 'f' : case 'F' : {
282        if (0 != dec->cpos) {
283	  dec->obyte |= 0x0F; dec->cpos  = 2;
284	} else {
285	  dec->obyte = 0xF0; dec->cpos  = 1;
286	}
287      } break;
288    }
289    if (2 == dec->cpos) {
290      dec->cpos = 0;
291      back = DK4_EDSTM_FINISHED;
292    }
293  } else {
294    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
295  }
296  return back;
297}
298
299
300
301int
302
303dk4ahex_dec_finish(dk4_ahex_dec_t *dec, dk4_er_t *erp)
304{
305  int		 back	=	DK4_EDSTM_ERROR;
306#if	DK4_USE_ASSERT
307  assert(NULL != dec);
308#endif
309  if (NULL != dec) {
310    switch (dec->cpos) {
311      case 1: {
312        back = DK4_EDSTM_FINISHED;
313      } break;
314      default : {
315        back = DK4_EDSTM_ACCEPT;
316      } break;
317    }
318  } else {
319    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
320  }
321  return back;
322}
323
324
325
326unsigned char
327
328dk4ahex_dec_output(dk4_ahex_dec_t const *dec, dk4_er_t *erp)
329{
330  unsigned char back	= 0x00;
331#if	DK4_USE_ASSERT
332  assert(NULL != dec);
333#endif
334  if (NULL != dec) {
335    back = dec->obyte;
336  } else {
337    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
338  }
339  return back;
340}
341
342