#ifndef BASE16_H
#define BASE16_H
struct base16_state {
int eof;
int bytes;
unsigned char carry;
};
#define BASE16_EOF 1
static const uint32_t base16_table_dec_32bit_d0[256] = {
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 257, 256,
0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 256, 256,
256, 256, 256, 256, 256, 160, 176, 192, 208, 224, 240, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 160, 176, 192, 208, 224, 240, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256
};
static const uint32_t base16_table_dec_32bit_d1[256] = {
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 257, 256,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256,
256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256
};
static really_inline int
base16_dec_loop_generic_32_inner(
const uint8_t **s, uint8_t **o, size_t *rounds)
{
const uint32_t val1 = base16_table_dec_32bit_d0[(*s)[0]]
| base16_table_dec_32bit_d1[(*s)[1]];
const uint32_t val2 = base16_table_dec_32bit_d0[(*s)[2]]
| base16_table_dec_32bit_d1[(*s)[3]];
if (val1 > 0xff || val2 > 0xff)
return 0;
(*o)[0] = (uint8_t)val1;
(*o)[1] = (uint8_t)val2;
*s += 4;
*o += 2;
*rounds -= 1;
return 1;
}
static really_inline void
base16_dec_loop_generic_32(
const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
{
if (*slen < 4)
return;
size_t rounds = (*slen - 4) / 4;
*slen -= rounds * 4;
*olen += rounds * 2;
do {
if (rounds >= 8) {
if (base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds))
continue;
break;
}
if (rounds >= 4) {
if (base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds))
continue;
break;
}
if (rounds >= 2) {
if (base16_dec_loop_generic_32_inner(s, o, &rounds) &&
base16_dec_loop_generic_32_inner(s, o, &rounds))
continue;
break;
}
base16_dec_loop_generic_32_inner(s, o, &rounds);
break;
} while (rounds > 0);
*slen += rounds * 4;
*olen -= rounds * 2;
}
nonnull((1,2,4,5))
static really_inline int base16_stream_decode(
struct base16_state *state,
const char *src,
size_t srclen,
uint8_t *out,
size_t *outlen)
{
int ret = 0;
const uint8_t *s = (const uint8_t *) src;
uint8_t *o = (uint8_t *) out;
uint32_t q;
size_t olen = 0;
size_t slen = srclen;
struct base16_state st;
st.eof = state->eof;
st.bytes = state->bytes;
st.carry = state->carry;
if (st.eof) {
*outlen = 0;
return ret;
}
switch (st.bytes)
{
#if defined(__SUNPRO_C)
#pragma error_messages(off, E_STATEMENT_NOT_REACHED)
#endif
for (;;)
#if defined(__SUNPRO_C)
#pragma error_messages(default, E_STATEMENT_NOT_REACHED)
#endif
{
case 0:
base16_dec_loop_generic_32(&s, &slen, &o, &olen);
if (slen-- == 0) {
ret = 1;
break;
}
if ((q = base16_table_dec_32bit_d0[*s++]) >= 255) {
st.eof = BASE16_EOF;
break;
}
st.carry = (uint8_t)q;
st.bytes = 1;
case 1:
if (slen-- == 0) {
ret = 1;
break;
}
if ((q = base16_table_dec_32bit_d1[*s++]) >= 255) {
st.eof = BASE16_EOF;
break;
}
*o++ = st.carry | (uint8_t)q;
st.carry = 0;
st.bytes = 0;
olen++;
}
}
state->eof = st.eof;
state->bytes = st.bytes;
state->carry = st.carry;
*outlen = olen;
return ret;
}
nonnull((1,3,4))
static really_inline int base16_decode(
const char *src, size_t srclen, uint8_t *out, size_t *outlen)
{
struct base16_state state = { .eof = 0, .bytes = 0, .carry = 0 };
return base16_stream_decode(&state, src, srclen, out, outlen) & !state.bytes;
}
nonnull_all
static really_inline int32_t parse_base16_sequence(
parser_t *parser,
const type_info_t *type,
const rdata_info_t *field,
rdata_t *rdata,
token_t *token)
{
if (is_contiguous(token)) {
struct base16_state state = { .eof = 0, .bytes = 0, .carry = 0 };
do {
size_t length = (token->length + 1) / 2;
if ((uintptr_t)rdata->limit - (uintptr_t)rdata->octets < length)
SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type));
if (!base16_stream_decode(&state, token->data, token->length, rdata->octets, &length))
SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type));
rdata->octets += length;
take(parser, token);
} while (is_contiguous(token));
if (state.bytes)
*rdata->octets++ = state.carry;
}
return have_delimiter(parser, type, token);
}
nonnull_all
static really_inline int32_t parse_base16(
parser_t *parser,
const type_info_t *type,
const rdata_info_t *field,
rdata_t *rdata,
const token_t *token)
{
size_t length = token->length / 2;
if ((uintptr_t)rdata->limit - (uintptr_t)rdata->octets < length)
SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type));
if (!base16_decode(token->data, token->length, rdata->octets, &length))
SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type));
rdata->octets += length;
return 0;
}
nonnull_all
static really_inline int32_t parse_salt(
parser_t *parser,
const type_info_t *type,
const rdata_info_t *field,
rdata_t *rdata,
const token_t *token)
{
if (token->length == 1 && token->data[0] == '-')
return (void)(*rdata->octets++ = 0), 0;
size_t length = token->length / 2;
uint8_t *octets = rdata->octets++;
if ((uintptr_t)rdata->limit - (uintptr_t)rdata->octets < (length + 1))
SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type));
if (!base16_decode(token->data, token->length, rdata->octets, &length))
SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type));
*octets = (uint8_t)length;
rdata->octets += length;
return 0;
}
#endif