From cb4dfc98a7b89f76bcebfdbcfaa23fea12123f12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se>
Date: Mon, 28 Oct 2002 23:07:35 +0100
Subject: [PATCH] (struct hex_decode_ctx): New hex decoding functions.
 (sexp_get_raw_char): New function. (sexp_get_char): Use sexp_get_raw_char.

Rev: src/nettle/examples/sexp-conv.c:1.9
---
 examples/sexp-conv.c | 120 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 103 insertions(+), 17 deletions(-)

diff --git a/examples/sexp-conv.c b/examples/sexp-conv.c
index 2acde89c..952eacca 100644
--- a/examples/sexp-conv.c
+++ b/examples/sexp-conv.c
@@ -62,15 +62,92 @@ enum sexp_coding
     SEXP_BASE64,
     SEXP_HEX,
   };
-    
+
+
+/* Hex functions should move out, eventually */
+struct hex_decode_ctx
+{
+  unsigned word;
+  unsigned count;
+};
+
+static void
+hex_decode_init(struct hex_decode_ctx *ctx)
+{
+  ctx->word = ctx->count = 0;
+}
+
+enum { HEX_INVALID = -1, HEX_SPACE=-2 };
+
+/* Returns -1 on error. */
+static int
+hex_decode_single(struct hex_decode_ctx *ctx,
+		  uint8_t *dst,
+		  uint8_t src)
+{
+  static const signed char hex_decode_table[0x80] =
+    {
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, 
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+      -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    };
+  
+  int digit;
+  if (src >= 0x80)
+    return -1;
+
+  /* FIXME: This code could use more clever choices of constants. */
+  digit = hex_decode_table[src];
+  switch (digit)
+    {
+    case -1:
+      return -1;
+    case -2:
+      return 0;
+    default:
+      assert(digit >= 0);
+      assert(digit < 0x10);
+
+      if (ctx->count)
+	{
+	  *dst = (ctx->word << 4) | digit;
+	  ctx->count = 0;
+	  return 1;
+	}
+      else
+	{
+	  ctx->word = digit;
+	  ctx->count = 1;
+	  return 0;
+	}
+    }
+}
+
+static int
+hex_decode_status(struct hex_decode_ctx *ctx)
+{
+  return !ctx->count;
+}
+
 struct sexp_input
 {
   FILE *f;
   
   enum sexp_coding coding;
   /* Used in transport mode */
-  struct base64_decode_ctx base64;
+  union {
+    struct base64_decode_ctx base64;
+    struct hex_decode_ctx hex;
+  };
 
+  /* Terminator for current coding */
+  uint8_t terminator;
+  
   /* Type of current token */
   enum sexp_token token;
 
@@ -114,6 +191,23 @@ sexp_output_init(struct sexp_output *output, FILE *f, enum sexp_mode mode)
 
 /* Input */
 
+/* Returns zero at EOF */
+static int
+sexp_get_raw_char(struct sexp_input *input, uint8_t *out)
+{
+  int c = getc(input->f);
+  
+  if (c < 0)
+    {
+      if (ferror(input->f))
+	die("Read error: %s\n", strerror(errno));
+
+      return 0;
+    }
+  *out = c;
+  return 1;
+}
+
 /* Returns 1 on success. For special tokens,
  * return 0 and set input->token accordingly. */
 static int
@@ -125,8 +219,9 @@ sexp_get_char(struct sexp_input *input, uint8_t *out)
       for (;;)
 	{
 	  int done;
-	  int c = getc(input->f);
-	  if (c < 0)
+	  uint8_t c;
+	  
+	  if (!sexp_get_raw_char(input, &c))
 	    die("Unexpected end of file in base64 data.\n");
 
 	  if (c == '}')
@@ -145,21 +240,12 @@ sexp_get_char(struct sexp_input *input, uint8_t *out)
 	    return 1;
 	}
     case SEXP_PLAIN:
-      {
-	int c = getc(input->f);
+      if (sexp_get_raw_char(input, out))
+	return 1;
       
-	if (c < 0)
-	  {
-	    if (ferror(input->f))
-	      die("Read error: %s\n", strerror(errno));
-	  
-	    input->token = SEXP_EOF;
-	    return 0;
-	  }
+      input->token = SEXP_EOF;
+      return 0;
 
-	*out = c;
-	return 1;
-      }
     case SEXP_HEX:
       /* Not yet implemented */
       abort();
-- 
GitLab