%% 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;
}