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