]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
expose hex_decode APIs
authorColin Vidal <colin@isc.org>
Fri, 16 May 2025 16:33:13 +0000 (18:33 +0200)
committerColin Vidal <colin@isc.org>
Wed, 1 Oct 2025 10:16:05 +0000 (12:16 +0200)
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).

lib/isc/hex.c
lib/isc/include/isc/hex.h

index abb38cb59075d25a7e78a4590ca08498117472dd..cf174daa983d1ef6a0fac6839fe178d836f86993 100644 (file)
@@ -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;
 }
 
index dd36f943913b890ddc0d0f469fa603cbc0f92338..76675c7fad991f4d1c1bead90225a3328a983623 100644 (file)
 
 #include <isc/types.h>
 
+/*%
+ * 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);
 /*!<