%% 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
if the input was accepted and stored in the decoder, no action necessary. - DK4_EDSTM_FINISHED
if a sequence of 5 input text characters was completed, use dk4a85_dec_output() to obtain the corresponding binary 4 bytes. - DK4_EDSTM_STOP
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
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
if there are no final bytes in the decoder, no action necessary. - DK4_EDSTM_FINISHED
if there are final bytes in the decoder, use dk4a85_dec_output() to retrieve them. - DK4_EDSTM_ERROR
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; }