diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/dk4a85d.ctr |
Initial commit
Diffstat (limited to 'support/dktools/dk4a85d.ctr')
-rw-r--r-- | support/dktools/dk4a85d.ctr | 402 |
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; +} + + |