%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% header /** @file dk4a85e.h ASCII-85 encoder. First initialize the encoder using the dk4a85_enc_init(). Now add the binary bytes one by one using the dk4a85_enc_add() function, as long as you have bytes available and the function returns DK4_EDSTM_ACCEPT or DK4_EDSTM_FINISHED. If the function returns DK4_EDSTM_ACCEPT, no further action is required, the byte was successfully stored in the internal data structures. If dk4a85_enc_add() returns DK4_EDSTM_FINISHED, a sequence of 4 binary bytes was processed successfully, a 1 character or 5 character sequence was produced. Use dk4a85_enc_output() to obtain the characters. Input data length is not necessarily a multiple of 4, so after feeding all binary bytes some values might still be stored in the encoder. Use dk4a85_enc_finish() to check whether an incomplete final sequence is available. If the function returns DK4_EDSTM_FINISHED, use dk4a85_enc_output() to obtain the text characters for the final bytes. */ #include "dk4conf.h" #include "dk4error.h" #include "dk4edstm.h" /** ASCII 85 encoder. */ typedef struct { char ob[6]; /**< Output bytes, 5 + finalizer */ unsigned char ib[4]; /**< Input bytes to process. */ size_t ci; /**< Index of current input byte. */ size_t os; /**< Number of outupt bytes available */ short az; /**< Allow z encoding */ } dk4_a85_enc_t; #ifdef __cplusplus extern "C" { #endif /** Initialize ASCII 85 encoder before adding data. @param enc Encoder to initialize. @param az Flag: Allow 'z' output character. @param erp Error report, may be NULL. Error codes: - DK4_E_INVALID_ARGUMENTS if enc is NULL. */ void dk4a85_enc_init(dk4_a85_enc_t *enc, int az, dk4_er_t *erp); /** Add one byte to encoder. @param enc Encoder to use. @param input Input byte to add. @param erp Error report, may be NULL. @return Action to take, one from: - DK4_EDSTM_ACCEPT
if input was accepted, no further action necessary at the moment. - DK4_EDSTM_FINISHED
if a sequence of 4 input bytes was completed, use dk4a85_enc_output() to obtain the text characters. - DK4_EDSTM_ERROR
if an error occured. Error codes: - DK4_E_INVALID_ARGUMENTS if enc is NULL. */ int dk4a85_enc_add(dk4_a85_enc_t *enc, unsigned char input, dk4_er_t *erp); /** Check for incomplete sequence in state machine after processing all input bytes. @param enc Encoder to use. @param erp Error report, may be NULL. @return Action to take, one from: - DK4_EDSTM_ACCEPT
if there is no incomplete sequence in the state machine, no further action necessary. - DK4_EDSTM_FINISHED
if an incomplete final sequence is available, use dk4a85_enc_output() to obtain the text characters. - DK4_EDSTM_ERROR
if an error occured. Error codes: - DK4_E_INVALID_ARGUMENTS if enc is NULL. */ int dk4a85_enc_finish(dk4_a85_enc_t *enc, dk4_er_t *erp); /** Retrieve text sequence. @param dptr Address of destination pointer to set, should be initialized to NULL. @param szptr Address of size variable to set, should be initialized to 0. @param enc Encoder to use. @param erp Error report, may be NULL. @return 1 on success (text available), 0 otherwise. Error codes: - DK4_E_INVALID_ARGUMENTS if enc, dptr, or szptr is NULL. */ int dk4a85_enc_output( const char **dptr, size_t *szptr, dk4_a85_enc_t *enc, dk4_er_t *erp ); #ifdef __cplusplus } #endif %% module #include "dk4a85e.h" #include "dk4edstm.h" #include "dk4mem.h" $!trace-include static const unsigned long dk4a85e_pow_85[] = { (85UL * 85UL * 85UL * 85UL), (85UL * 85UL * 85UL), (85UL * 85UL), 85UL }; void dk4a85_enc_init(dk4_a85_enc_t *enc, int az, dk4_er_t *erp) { if (NULL != enc) { DK4_MEMRES(enc, sizeof(dk4_a85_enc_t)); enc->ob[5] = '\0'; enc->ci = 0; enc->os = 0; enc->az = ((0 != az) ? 1 : 0); } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } int dk4a85_enc_add(dk4_a85_enc_t *enc, unsigned char input, dk4_er_t *erp) { unsigned long val; unsigned long v1; int back = DK4_EDSTM_ERROR; if (NULL != enc) { back = DK4_EDSTM_ACCEPT; enc->ib[enc->ci] = input; enc->ci += 1; if (4 <= enc->ci) { back = DK4_EDSTM_FINISHED; val = (((unsigned long)(enc->ib[0]) << 24) & 0xFF000000UL) | (((unsigned long)(enc->ib[1]) << 16) & 0x00FF0000UL) | (((unsigned long)(enc->ib[2]) << 8) & 0x0000FF00UL) | (((unsigned long)(enc->ib[3]) ) & 0x000000FFUL); if ((0UL == val) && (0 != enc->az)) { enc->ob[0] = 'z'; enc->ob[1] = '\0'; enc->os = 1; } else { v1 = val / dk4a85e_pow_85[0]; enc->ob[0] = (char)33 + (char)v1; val = val % dk4a85e_pow_85[0]; v1 = val / dk4a85e_pow_85[1]; enc->ob[1] = (char)33 + (char)v1; val = val % dk4a85e_pow_85[1]; v1 = val / dk4a85e_pow_85[2]; enc->ob[2] = (char)33 + (char)v1; val = val % dk4a85e_pow_85[2]; v1 = val / dk4a85e_pow_85[3]; enc->ob[3] = (char)33 + (char)v1; val = val % dk4a85e_pow_85[3]; enc->ob[4] = (char)33 + (char)val; enc->os = 5; } enc->ci = 0; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } int dk4a85_enc_finish(dk4_a85_enc_t *enc, dk4_er_t *erp) { unsigned long val; unsigned long v1; int back = DK4_EDSTM_ERROR; $? "+ dk4a85_enc_finish" if (NULL != enc) { if (0 == enc->ci) { back = DK4_EDSTM_ACCEPT; enc->ob[0] = '\0'; enc->os = 0; } else { switch (enc->ci) { case 1: { $? ". 1 input byte %02x", (int)(enc->ib[0]) back = DK4_EDSTM_FINISHED; val = (((unsigned long)(enc->ib[0]) << 24) & 0xFF000000UL); $? ". val = %lu %lx", val, val v1 = val / dk4a85e_pow_85[0]; enc->ob[0] = (char)33 + (char)v1; $? ". a1 = %lu", v1 val = val % dk4a85e_pow_85[0]; v1 = val / dk4a85e_pow_85[1]; enc->ob[1] = (char)33 + (char)v1; $? ". a2 = %lu", v1 enc->os = 2; enc->ci = 0; } break; case 2: { $? ". 2 input bytes %02x %02x", (int)(enc->ib[0]), (int)(enc->ib[1]) back = DK4_EDSTM_FINISHED; val = (((unsigned long)(enc->ib[0]) << 24) & 0xFF000000UL) | (((unsigned long)(enc->ib[1]) << 16) & 0x00FF0000UL); $? ". val = %lu %lx", val, val v1 = val / dk4a85e_pow_85[0]; enc->ob[0] = (char)33 + (char)v1; $? ". a1 = %lu", v1 val = val % dk4a85e_pow_85[0]; v1 = val / dk4a85e_pow_85[1]; enc->ob[1] = (char)33 + (char)v1; $? ". a2 = %lu", v1 val = val % dk4a85e_pow_85[1]; v1 = val / dk4a85e_pow_85[2]; enc->ob[2] = (char)33 + (char)v1; $? ". a3 = %lu", v1 enc->os = 3; enc->ci = 0; } break; case 3: { $? ". 3 input bytes %02x %02x %02x", (int)(enc->ib[0]), (int)(enc->ib[1]), (int)(enc->ib[2]) back = DK4_EDSTM_FINISHED; val = (((unsigned long)(enc->ib[0]) << 24) & 0xFF000000UL) | (((unsigned long)(enc->ib[1]) << 16) & 0x00FF0000UL) | (((unsigned long)(enc->ib[2]) << 8) & 0x0000FF00UL); $? ". val = %lu %lx", val, val v1 = val / dk4a85e_pow_85[0]; enc->ob[0] = (char)33 + (char)v1; $? ". a1 = %lu", v1 val = val % dk4a85e_pow_85[0]; v1 = val / dk4a85e_pow_85[1]; enc->ob[1] = (char)33 + (char)v1; $? ". a2 = %lu", v1 val = val % dk4a85e_pow_85[1]; v1 = val / dk4a85e_pow_85[2]; enc->ob[2] = (char)33 + (char)v1; $? ". a3 = %lu", v1 val = val % dk4a85e_pow_85[2]; v1 = val / dk4a85e_pow_85[3]; enc->ob[3] = (char)33 + (char)v1; $? ". a4 = %lu", v1 enc->os = 4; enc->ci = 0; } break; default: { $? ". 4 input bytes %02x %02x %02x %02x", (int)(enc->ib[0]), (int)(enc->ib[1]), (int)(enc->ib[2]), (int)(enc->ib[3]) back = DK4_EDSTM_FINISHED; val = (((unsigned long)(enc->ib[0]) << 24) & 0xFF000000UL) | (((unsigned long)(enc->ib[1]) << 16) & 0x00FF0000UL) | (((unsigned long)(enc->ib[2]) << 8) & 0x0000FF00UL) | (((unsigned long)(enc->ib[3]) ) & 0x000000FFUL); $? ". val = %lu %lx", val, val if ((0UL == val) && (0 != enc->az)) { enc->ob[0] = 'z'; enc->ob[1] = '\0'; enc->os = 1; } else { v1 = val / dk4a85e_pow_85[0]; enc->ob[0] = (char)33 + (char)v1; $? ". a1 = %lu", v1 val = val % dk4a85e_pow_85[0]; v1 = val / dk4a85e_pow_85[1]; enc->ob[1] = (char)33 + (char)v1; $? ". a2 = %lu", v1 val = val % dk4a85e_pow_85[1]; v1 = val / dk4a85e_pow_85[2]; enc->ob[2] = (char)33 + (char)v1; $? ". a3 = %lu", v1 val = val % dk4a85e_pow_85[2]; v1 = val / dk4a85e_pow_85[3]; enc->ob[3] = (char)33 + (char)v1; $? ". a4 = %lu", v1 val = val % dk4a85e_pow_85[3]; enc->ob[4] = (char)33 + (char)val; $? ". a5 = %lu", val enc->os = 5; } enc->ci = 0; } break; } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4a85_enc_finish" return back; } int dk4a85_enc_output( const char **dptr, size_t *szptr, dk4_a85_enc_t *enc, dk4_er_t *erp ) { int back = 0; if ((NULL != dptr) && (NULL != szptr) && (NULL != enc)) { *dptr = &(enc->ob[0]); *szptr = enc->os; if (0 < enc->os) { back = 1; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; }