From: Colin Vidal Date: Fri, 16 May 2025 16:33:13 +0000 (+0200) Subject: expose hex_decode APIs X-Git-Tag: v9.21.14~13^2~7 X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=e34dd2b73ef17c3ca57adee1d5f73a85f3e5fb10;p=thirdparty%2Fbind9.git expose hex_decode APIs Functions hex_decode_init(), hex_decode_char() and hex_decode_finish() are now exposed, as well as the context hex_decode_ctx_t. They now are respectively called isc_hex_decodeinit(), isc_hex_decodechar(), isc_hex_decodefinish() and isc_hex_decodectx_t. This enable to re-implement the functionality of isc_hex_decodestring() in contextes where the input is not a NULL-terminated string, but, for example, individual characters extracted (and avoid creating an intermediate buffer to store them). This also enable to decode a stream of hex characters where only hex characters are expected (i.e. no white spaces). --- diff --git a/lib/isc/hex.c b/lib/isc/hex.c index abb38cb5907..cf174daa983 100644 --- a/lib/isc/hex.c +++ b/lib/isc/hex.c @@ -83,25 +83,15 @@ isc_hex_totext(isc_region_t *source, int wordlength, const char *wordbreak, return ISC_R_SUCCESS; } -/*% - * State of a hex decoding process in progress. - */ -typedef struct { - int length; /*%< Desired length of binary data or -1 */ - isc_buffer_t *target; /*%< Buffer for resulting binary data */ - int digits; /*%< Number of buffered hex digits */ - int val[2]; -} hex_decode_ctx_t; - -static void -hex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target) { +void +isc_hex_decodeinit(isc_hex_decodectx_t *ctx, int length, isc_buffer_t *target) { ctx->digits = 0; ctx->length = length; ctx->target = target; } -static isc_result_t -hex_decode_char(hex_decode_ctx_t *ctx, int c) { +isc_result_t +isc_hex_decodechar(isc_hex_decodectx_t *ctx, int c) { uint8_t hexval; hexval = isc_hex_char(c); @@ -126,8 +116,8 @@ hex_decode_char(hex_decode_ctx_t *ctx, int c) { return ISC_R_SUCCESS; } -static isc_result_t -hex_decode_finish(hex_decode_ctx_t *ctx) { +isc_result_t +isc_hex_decodefinish(isc_hex_decodectx_t *ctx) { if (ctx->length > 0) { return ISC_R_UNEXPECTEDEND; } @@ -140,14 +130,14 @@ hex_decode_finish(hex_decode_ctx_t *ctx) { isc_result_t isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { unsigned int before, after; - hex_decode_ctx_t ctx; + isc_hex_decodectx_t ctx; isc_textregion_t *tr; isc_token_t token; bool eol; REQUIRE(length >= -2); - hex_decode_init(&ctx, length, target); + isc_hex_decodeinit(&ctx, length, target); before = isc_buffer_usedlength(target); while (ctx.length != 0) { @@ -165,14 +155,14 @@ isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { } tr = &token.value.as_textregion; for (i = 0; i < tr->length; i++) { - RETERR(hex_decode_char(&ctx, tr->base[i])); + RETERR(isc_hex_decodechar(&ctx, tr->base[i])); } } after = isc_buffer_usedlength(target); if (ctx.length < 0) { isc_lex_ungettoken(lexer, &token); } - RETERR(hex_decode_finish(&ctx)); + RETERR(isc_hex_decodefinish(&ctx)); if (length == -2 && before == after) { return ISC_R_UNEXPECTEDEND; } @@ -181,9 +171,9 @@ isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { isc_result_t isc_hex_decodestring(const char *cstr, isc_buffer_t *target) { - hex_decode_ctx_t ctx; + isc_hex_decodectx_t ctx; - hex_decode_init(&ctx, -1, target); + isc_hex_decodeinit(&ctx, -1, target); for (;;) { int c = *cstr++; if (c == '\0') { @@ -192,9 +182,9 @@ isc_hex_decodestring(const char *cstr, isc_buffer_t *target) { if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { continue; } - RETERR(hex_decode_char(&ctx, c)); + RETERR(isc_hex_decodechar(&ctx, c)); } - RETERR(hex_decode_finish(&ctx)); + RETERR(isc_hex_decodefinish(&ctx)); return ISC_R_SUCCESS; } diff --git a/lib/isc/include/isc/hex.h b/lib/isc/include/isc/hex.h index dd36f943913..76675c7fad9 100644 --- a/lib/isc/include/isc/hex.h +++ b/lib/isc/include/isc/hex.h @@ -17,6 +17,16 @@ #include +/*% + * State of a hex decoding process in progress. + */ +typedef struct { + int length; /*%< Desired length of binary data or -1 */ + isc_buffer_t *target; /*%< Buffer for resulting binary data */ + int digits; /*%< Number of buffered hex digits */ + int val[2]; +} isc_hex_decodectx_t; + /* * An `isc__hex_char` table entry is non-zero if the character is a hex digit; * You can subtract the table entry from the character to convert the hex digit @@ -58,6 +68,54 @@ isc_hex_totext(isc_region_t *source, int wordlength, const char *wordbreak, * necessary. */ +/* + * The 3 following functions are internally used and wrapped by + * `isc_hex_decodestring()`, which can be directly used for simpler cases. + * However, for more complex cases (or cases which, for instance, must not have + * white spaces, or if the input is not a null-terminated string) using those + * lower-level API might be usefull. + */ + +void +isc_hex_decodeinit(isc_hex_decodectx_t *ctx, int length, isc_buffer_t *target); +/*!< + * \brief Initialize the hex decoder context + * + * Requires: + *\li 'ctx' is non-null. + *\li 'length' is the number of bytes that will have to be decoded + *\li 'target' is the buffer which the decoded hex chars will be written to. + */ + +isc_result_t +isc_hex_decodechar(isc_hex_decodectx_t *ctx, int c); +/*!< + * \brief Decode an individual hex character + * + * Requires: + *\li 'ctx' is non-null. + *\li 'c' is the hexadecimal character to decode + * + * Returns: + * \li #ISC_R_BADHEX -- 'c' is not an hexadecimal char + * \li #ISC_R_SUCCESS -- 'c' is decoded + */ + +isc_result_t +isc_hex_decodefinish(isc_hex_decodectx_t *ctx); +/*!< + * \brief Verifies that all the decoded characters used the expected length + * passed to `hex_decode_init()` + * + * Requires: + *\li 'ctx' is non-null. + * + * Returns: + * \li #ISC_R_UNEXPECTEDEND -- less bytes than expected has been decoded + * \li #ISC_R_BADHEX -- last decoded character is not an hexadecimal one + * \li #ISC_R_SUCCESS -- all the bytes are decoded as expected + */ + isc_result_t isc_hex_decodestring(const char *cstr, isc_buffer_t *target); /*!<