summaryrefslogtreecommitdiff
path: root/support/dktools/dk4a85d.ctr
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/dk4a85d.ctr
Initial commit
Diffstat (limited to 'support/dktools/dk4a85d.ctr')
-rw-r--r--support/dktools/dk4a85d.ctr402
1 files changed, 402 insertions, 0 deletions
diff --git a/support/dktools/dk4a85d.ctr b/support/dktools/dk4a85d.ctr
new file mode 100644
index 0000000000..ac17417f27
--- /dev/null
+++ b/support/dktools/dk4a85d.ctr
@@ -0,0 +1,402 @@
+%% options
+
+copyright owner = Dirk Krause
+copyright year = 2015-xxxx
+license = bsd
+
+
+
+%% header
+
+/** @file dk4a85d.h ASCII-85 decoder.
+
+First initialize the decoder structure, use the dk4a85_dec_init() function.
+
+Add bytes to the decoder using the dk4a85_dec_add() function
+as long as adding results in DK4_EDSTM_ACCEPT or
+DK4_EDSTM_FINISHED. On DK4_EDSTM_FINISHED use dk4a85_dec_output() to obtain
+the binary bytes.
+
+A return value DK4_EDSTM_STOP indicates that the end of data (EOD) marker
+was found in the data stream, you must not add further characters to the
+decoder.
+
+After adding all bytes use dk4a85_dec_finish() to check whether there
+is data for a final incomplete sequence stored in the decoder. If the test
+results in DK4_EDSTM_FINISHED, use dk4a85_dec_output() to obtain
+the binary bytes.
+
+The dk4a85_dec_finish() is also necessary if you stopped
+feeding input due to a DK4_EDSTM_STOP result from dk4a85_dec_add().
+
+Note: You can not directly call dk4a85_dec_output() after receiving
+DK4_EDSTM_STOP from dk4a85_dec_add(), the call to dk4a85_dec_finish()
+is required.
+*/
+
+#include "dk4conf.h"
+#include "dk4error.h"
+
+/** ASCII 85 decoder.
+*/
+typedef struct {
+ char ib[6]; /**< Input bytes, ASCII. */
+ unsigned char ob[4]; /**< Output bytes, binary. */
+ size_t os; /**< Output buffer size. */
+ size_t is; /**< Index of next input byte to receive. */
+ int tf; /**< Flag: Tilde found */
+} dk4_a85_dec_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Initialize decoder before using it.
+ @param dec Decoder to initialize.
+ @param erp Error report, may be NULL.
+*/
+void
+dk4a85_dec_init(dk4_a85_dec_t *dec, dk4_er_t *erp);
+
+/** Add one text character to the decoder.
+ @param dec Decoder to use.
+ @param input Input text character.
+ @param erp Error report, may be NULL.
+ @return Action to take, one from:
+ - DK4_EDSTM_ACCEPT<br>
+ if the input was accepted and stored in the decoder, no action
+ necessary.
+ - DK4_EDSTM_FINISHED<br>
+ if a sequence of 5 input text characters was completed, use
+ dk4a85_dec_output() to obtain the corresponding binary 4 bytes.
+ - DK4_EDSTM_STOP<br>
+ if an EOD (end of data) marker was found. Use
+ dk4a85_dec_finish() and take appropriate action to process
+ the final byte sequence.
+ - DK4_EDSTM_ERROR<br>
+ if an error occured.
+*/
+int
+dk4a85_dec_add(dk4_a85_dec_t *dec, char input, dk4_er_t *erp);
+
+/** Check whether final bytes are stored in the decoder.
+ @param dec Decoder to use.
+ @param erp Error report, may be NULL.
+ @return Action to take, one from:
+ - DK4_EDSTM_ACCEPT<br>
+ if there are no final bytes in the decoder, no action necessary.
+ - DK4_EDSTM_FINISHED<br>
+ if there are final bytes in the decoder, use dk4a85_dec_output()
+ to retrieve them.
+ - DK4_EDSTM_ERROR<br>
+ if an error occured.
+*/
+int
+dk4a85_dec_finish(dk4_a85_dec_t *dec, dk4_er_t *erp);
+
+/** Retrieve final bytes.
+ @param dptr Address of buffer pointer to set, should be
+ initialized to NULL.
+ @param szptr Address of size variable to set, should be
+ initialized to 0.
+ @param dec Decoder to use.
+ @param erp Error report, may be NULL.
+ @return 1 on success (bytes available, 0 otherwise).
+*/
+int
+dk4a85_dec_output(
+ const unsigned char **dptr, size_t *szptr, dk4_a85_dec_t *dec, dk4_er_t *erp
+);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+%% module
+
+#include "dk4a85d.h"
+#include "dk4mem.h"
+#include "dk4edstm.h"
+
+
+
+$!trace-include
+
+
+
+/** Powers of 85.
+*/
+static const unsigned long dk4a85e_pow_85[] = {
+ (85UL * 85UL * 85UL * 85UL),
+ (85UL * 85UL * 85UL),
+ (85UL * 85UL),
+ 85UL
+};
+
+
+
+void
+dk4a85_dec_init(dk4_a85_dec_t *dec, dk4_er_t *erp)
+{
+ if (NULL != dec) {
+ DK4_MEMRES(dec, sizeof(dk4_a85_dec_t));
+ dec->os = 0;
+ dec->is = 0;
+ dec->tf = 0;
+ } else {
+ dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
+ }
+}
+
+
+
+int
+dk4a85_dec_add(dk4_a85_dec_t *dec, char input, dk4_er_t *erp)
+{
+ unsigned long val;
+ int back = DK4_EDSTM_ERROR;
+ if (NULL != dec) {
+ if (0 != dec->tf) {
+ if ('>' == input) {
+ back = DK4_EDSTM_STOP;
+ } else {
+ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
+ }
+ } else {
+ switch (input) {
+ case ' ' : case '\t' : case '\r' : case '\n' : case 0x00 : case 0x0C : {
+ back = DK4_EDSTM_ACCEPT;
+ } break;
+ case '~' : {
+ back = DK4_EDSTM_ACCEPT;
+ dec->tf = 1;
+ } break;
+ case 'z' : {
+ if (0 == dec->is) {
+ dec->ob[0] = 0x00;
+ dec->ob[1] = 0x00;
+ dec->ob[2] = 0x00;
+ dec->ob[3] = 0x00;
+ dec->os = 4;
+ back = DK4_EDSTM_FINISHED;
+ } else {
+ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
+ }
+ } break;
+ default : {
+ if (((char)32 < input) && ((char)118 > input)) {
+ dec->ib[dec->is] = input;
+ dec->is += 1;
+ back = DK4_EDSTM_ACCEPT;
+ if (5 <= dec->is) {
+ val =
+ dk4a85e_pow_85[0] *
+ ((unsigned long)((unsigned char)(dec->ib[0] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[1] *
+ ((unsigned long)((unsigned char)(dec->ib[1] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[2] *
+ ((unsigned long)((unsigned char)(dec->ib[2] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[3] *
+ ((unsigned long)((unsigned char)(dec->ib[3] - (char)33)) & 0xFFUL)
+ +
+ ((unsigned long)((unsigned char)(dec->ib[4] - (char)33)) & 0xFFUL)
+ ;
+ dec->ob[0] = (unsigned char)((val >> 24) & 0xFFUL);
+ dec->ob[1] = (unsigned char)((val >> 16) & 0xFFUL);
+ dec->ob[2] = (unsigned char)((val >> 8) & 0xFFUL);
+ dec->ob[3] = (unsigned char)((val ) & 0xFFUL);
+ dec->is = 0;
+ dec->os = 4;
+ back = DK4_EDSTM_FINISHED;
+ }
+ } else {
+ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
+ }
+ } break;
+ }
+ }
+ } else {
+ dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
+ }
+ return back;
+}
+
+
+
+/*
+ During encoding sequences of 4 binary bytes b1, b2, b3, and b4
+ are converted to five base-85 values a1, a2, a3, a4, and a5
+ fullfilling the equation
+ v=b1*256^3+b2*256^2+b3*256+b4=a1*85^4+a2*85^3+a3*85^2+a4*85+a5
+
+ For complete sequences encoding and decoding are straightforward.
+
+ For an incomplete final sequence of n binary bytes (1<=n<=3),
+ only n+1 a values are encoded.
+ In the example we assume a 2 byte sequence b1 and b2.
+ The value v is calculated as
+ v=b1*256^3+b2*256^2+0*256+0=a1*85^4+a2*85^3+a3*85^2+a4*85+a5.
+ As we have 2 binary bytes, 3 text coefficients a1, a2, and a3
+ are written to encoded output, a4 and a5 are skipped.
+ From these 3 coefficients the decoder can calculate
+ v'=a1*85^4+a2*85^3+a3*85^2+0*85+0
+ which we can split into
+ v'=b1'*256^3+b2'*256^2+b3'*256+b4'
+ Obviously v' is less than or equal to v because v'=v-a4*85-a5.
+ We have v=v' only if a4=0 and a5=0, this results in
+ b3=0 and b4=0. Otherwise we have v>v'.
+ As the final 2 bytes of v are zero, decreasing v to v' results
+ in a non-zero value in the final 2 bytes and a decrease by
+ 1 in the first 2 bytes.
+ So if v' & 0x0000FFFF is nonzero we have to calculate
+ v = v' + 0x00010000 before splitting v into b1, b2, b3, and b4.
+*/
+
+
+
+int
+dk4a85_dec_finish(dk4_a85_dec_t *dec, dk4_er_t *erp)
+{
+ unsigned long val; /* 32 bit value */
+ int back = DK4_EDSTM_ERROR;
+ $? "+ dk4a85_dec_finish"
+ if (NULL != dec) {
+ if (0 == dec->is) {
+ back = DK4_EDSTM_ACCEPT;
+ } else {
+ switch (dec->is) {
+ case 4: { $? ". 4 unused input bytes"
+ /* Calculate 32 bit value from encoded values.
+ */
+ val =
+ dk4a85e_pow_85[0] *
+ ((unsigned long)((unsigned char)(dec->ib[0] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[1] *
+ ((unsigned long)((unsigned char)(dec->ib[1] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[2] *
+ ((unsigned long)((unsigned char)(dec->ib[2] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[3] *
+ ((unsigned long)((unsigned char)(dec->ib[3] - (char)33)) & 0xFFUL)
+ ;
+ $? ". val = %lu %lx", val, val
+ /* Check whether truncation of a5 modified the 32 bit
+ value, correct least significant used byte if necessary.
+ */
+ if (0UL != (val & 0x000000FFUL)) {
+ val += 0x00000100UL;
+ }
+ /* Split 32 bit value into bytes.
+ */
+ $? ". val = %lu %lx", val, val
+ dec->ob[0] = (unsigned char)((val >> 24) & 0xFFUL);
+ dec->ob[1] = (unsigned char)((val >> 16) & 0xFFUL);
+ dec->ob[2] = (unsigned char)((val >> 8) & 0xFFUL);
+ /* Set input size, output size and result.
+ */
+ dec->is = 0;
+ dec->os = 3;
+ back = DK4_EDSTM_FINISHED;
+ } break;
+ case 3: { $? ". 3 unused input bytes"
+ /* Calculate 32 bit value from encoded values.
+ */
+ val =
+ dk4a85e_pow_85[0] *
+ ((unsigned long)((unsigned char)(dec->ib[0] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[1] *
+ ((unsigned long)((unsigned char)(dec->ib[1] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[2] *
+ ((unsigned long)((unsigned char)(dec->ib[2] - (char)33)) & 0xFFUL)
+ ;
+ $? ". val = %lu %lx", val, val
+ /* Check whether truncation of a4 and a5 modified the 32 bit
+ value, correct least significant used byte if necessary.
+ */
+ if (0UL != (val & 0x0000FFFFUL)) {
+ val += 0x00010000UL;
+ }
+ $? ". val = %lu %lx", val, val
+ /* Split 32 bit value into bytes.
+ */
+ dec->ob[0] = (unsigned char)((val >> 24) & 0xFFUL);
+ dec->ob[1] = (unsigned char)((val >> 16) & 0xFFUL);
+ /* Set input size, output size and result.
+ */
+ dec->is = 0;
+ dec->os = 2;
+ back = DK4_EDSTM_FINISHED;
+ } break;
+ case 2: { $? ". 2 unused input bytes"
+ /* Calculate 32 bit value from encoded values.
+ */
+ val =
+ dk4a85e_pow_85[0] *
+ ((unsigned long)((unsigned char)(dec->ib[0] - (char)33)) & 0xFFUL)
+ +
+ dk4a85e_pow_85[1] *
+ ((unsigned long)((unsigned char)(dec->ib[1] - (char)33)) & 0xFFUL)
+ ;
+ $? ". val = %lu %lx", val, val
+ /* Check whether truncation of a3, a4, and a5 modified the 32 bit
+ value, correct least significant used byte if necessary.
+ */
+ if (0UL != (val & 0x00FFFFFFUL)) {
+ val += 0x01000000UL;
+ }
+ $? ". val = %lu %lx", val, val
+ /* Split 32 bit value into bytes.
+ */
+ dec->ob[0] = (unsigned char)((val >> 24) & 0xFFUL);
+ /* Set input size, output size and result.
+ */
+ dec->is = 0;
+ dec->os = 1;
+ back = DK4_EDSTM_FINISHED;
+ } break;
+ default: {
+ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
+ } break;
+ }
+ }
+ } else {
+ dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
+ } $? "- dk4a85_dec_finish"
+ return back;
+}
+
+
+
+int
+dk4a85_dec_output(
+ const unsigned char **dptr, size_t *szptr, dk4_a85_dec_t *dec, dk4_er_t *erp
+)
+{
+ int back = 0;
+ if ((NULL != dec) && (NULL != dptr) && (NULL != szptr)) {
+ if (0 < dec->os) {
+ *dptr = &(dec->ob[0]);
+ *szptr = dec->os;
+ back = 1;
+ } else {
+ *dptr = NULL;
+ *szptr = 0;
+ back = 0;
+ }
+ } else {
+ dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
+ }
+ return back;
+}
+
+