From b7b495188eac91d42020d230b77610f20dbe891a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se>
Date: Wed, 30 Oct 2002 23:10:52 +0100
Subject: [PATCH] Deleted hex functions, moved to Nettle's base16 files.
 (struct sexp_output): Represent the current encoding as a nettle_armor
 pointer and a state struct. (sexp_output_init): Deleted MODE argument. Now
 passed to functions that need it. (sexp_get_char): Updated to new base64
 conventions. (sexp_get_base64_string): Likewise. (sexp_put_raw_char): New
 function. (sexp_put_newline): Use sexp_put_raw_char. (sexp_put_char): Use
 nettle_armor interface for encoding data. Use OUTPUT->coding_indent for line
 breaking, so the INDENT argument was deleted. (sexp_put_code_start): New
 function, replacing sexp_put_base64_start. (sexp_put_code_end): New function,
 replacing sexp_put_base64_end. (sexp_put_data): Deleted argument INDENT.
 (sexp_puts): Likewise. (sexp_put_length): Likewise. (sexp_put_list_start):
 Likewise. (sexp_put_list_end): Likewise. (sexp_put_display_start): Likewise.
 (sexp_put_display_end): Likewise. (sexp_put_string): Likewise. Also changed
 base64 handling. (sexp_convert_string): Deleted argument INDENT. New argument
 MODE_OUT. (sexp_convert_list): New argument MODE_OUT. (sexp_convert_file):
 Likewise. (sexp_convert_item): Likewise. Also handle output in transport
 mode. (match_argument): Simple string comparison. (main): Adapted to above
 changes.

Rev: src/nettle/examples/sexp-conv.c:1.10
---
 examples/sexp-conv.c | 357 +++++++++++++++++++------------------------
 1 file changed, 153 insertions(+), 204 deletions(-)

diff --git a/examples/sexp-conv.c b/examples/sexp-conv.c
index 952eacca..5ae47b1d 100644
--- a/examples/sexp-conv.c
+++ b/examples/sexp-conv.c
@@ -3,8 +3,10 @@
  * Conversion tool for handling the different flavours of sexp
  * syntax. */
 
+#include "base16.h"
 #include "base64.h"
 #include "buffer.h"
+#include "nettle-meta.h"
 
 #include <assert.h>
 #include <errno.h>
@@ -39,8 +41,6 @@ enum sexp_mode
   {
     SEXP_CANONICAL = 0,
     SEXP_ADVANCED = 1,
-    /* OR:ed with SEXP_CANONICAL or SEXP_ADVANCED when reading
-     * transport data */
     SEXP_TRANSPORT = 2,
   };
 
@@ -63,86 +63,15 @@ enum sexp_coding
     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 */
   union {
     struct base64_decode_ctx base64;
-    struct hex_decode_ctx hex;
+    struct base16_decode_ctx hex;
   };
 
   /* Terminator for current coding */
@@ -172,19 +101,23 @@ struct sexp_output
 {
   FILE *f;
 
-  enum sexp_coding coding;
-  enum sexp_mode mode;
-  struct base64_encode_ctx base64;
-
+  const struct nettle_armor *coding;
+  unsigned coding_indent;
+  
+  union {
+    struct base64_decode_ctx base64;
+    /* NOTE: There's no context for hex encoding */
+  } state;
+  
   unsigned pos;
 };
 
 static void
-sexp_output_init(struct sexp_output *output, FILE *f, enum sexp_mode mode)
+sexp_output_init(struct sexp_output *output, FILE *f)
 {
   output->f = f;
-  output->coding = SEXP_PLAIN;
-  output->mode = mode;
+  output->coding = NULL;
+
   output->pos = 0;
 }
 
@@ -226,7 +159,7 @@ sexp_get_char(struct sexp_input *input, uint8_t *out)
 
 	  if (c == '}')
 	    {
-	      if (base64_decode_status(&input->base64))
+	      if (base64_decode_final(&input->base64))
 		{
 		  input->token = SEXP_TRANSPORT_END;
 		  return 0;
@@ -373,14 +306,24 @@ sexp_get_base64_string(struct sexp_input *input)
 
       if (c == '|')
 	{
-	  if (!base64_decode_status(&ctx))
+	  if (!base64_decode_final(&ctx))
 	    die("Invalid base64 string.\n");
 	  return;
 	}
       
-      if (base64_decode_single(&ctx, &decoded, c)
-	  && !NETTLE_BUFFER_PUTC(&input->string, decoded))
-	die("Virtual memory exhasuted.\n");	
+      switch(base64_decode_single(&ctx, &decoded, c))
+	{
+	case 0:
+	  break;
+	case 1:
+	  if (!NETTLE_BUFFER_PUTC(&input->string, decoded))
+	    die("Virtual memory exhasuted.\n");
+	  break;
+	case -1:
+	  die("Invalid base64 string.\n");
+	default:
+	  abort();
+	}
     }
 }
 
@@ -567,83 +510,77 @@ sexp_get_token(struct sexp_input *input, enum sexp_mode mode)
 
 #define LINE_WIDTH 60
 
+static void
+sexp_put_raw_char(struct sexp_output *output, uint8_t c)
+{
+  output->pos++;
+  if (putc(c, output->f) < 0)
+    die("Write failed: %s\n", strerror(errno));
+}
+
 static void 
 sexp_put_newline(struct sexp_output *output,
 		 unsigned indent)
 {
   unsigned i;
-  if (putc('\n', output->f) < 0)
-    die("Write failed: %s\n", strerror(errno));
 
+  sexp_put_raw_char(output, '\n');
+  output->pos = 0;
+  
   for(i = 0; i < indent; i++)
-    if (putc(' ', output->f) < 0)
-      die("Write failed: %s\n", strerror(errno));
-
+    sexp_put_raw_char(output, ' ');
+  
   output->pos = indent;
 }
 
 static void
-sexp_put_char(struct sexp_output *output, unsigned indent,
-	      uint8_t c)
+sexp_put_char(struct sexp_output *output, uint8_t c)
 {
-  switch (output->coding)
+  if (output->coding)
     {
-    case SEXP_BASE64:
-      {
-	uint8_t encoded[2];
-	unsigned done;
-	unsigned i;
-      
-	done = base64_encode_single(&output->base64, encoded, c);
-
-	assert(done <= sizeof(encoded));
+      /* Two is enough for both hex and base64. */
+      uint8_t encoded[2];
+      unsigned done;
 
-	for (i = 0; i<done; i++)
+      unsigned i;
+      
+      done = output->coding->encode_update(&output->state, encoded,
+					   1, &c);
+      assert(done <= sizeof(encoded));
+      
+      for (i = 0; i<done; i++)
 	  {
-	    if (indent &&
-		output->pos > LINE_WIDTH
-		&& output->pos > (indent + 10))
-	      sexp_put_newline(output, indent);
-	  
-	    if (putc(encoded[i], output->f) < 0)
-	      die("Write failed: %s\n", strerror(errno));
+	    if (output->pos > LINE_WIDTH
+		&& output->pos > (output->coding_indent + 10))
+	      sexp_put_newline(output, output->coding_indent);
 
-	    output->pos++;
+	    sexp_put_raw_char(output, encoded[i]);
 	  }
-	break;
-      }
-    case SEXP_PLAIN:
-      output->pos++;
-      if (putc(c, output->f) < 0)
-	die("Write failed: %s\n", strerror(errno));
-      break;
-
-    case SEXP_HEX:
-      /* Not implemented */
-      abort();
     }
+  else
+    sexp_put_raw_char(output, c);
 }
 
 static void
-sexp_put_data(struct sexp_output *output, unsigned indent,
+sexp_put_data(struct sexp_output *output,
 	      unsigned length, const uint8_t *data)
 {
   unsigned i;
 
   for (i = 0; i<length; i++)
-    sexp_put_char(output, indent, data[i]);
+    sexp_put_char(output, data[i]);
 }
 
 static void
-sexp_puts(struct sexp_output *output, unsigned indent,
+sexp_puts(struct sexp_output *output,
 	  const uint8_t *s)
 {
   while (*s)
-    sexp_put_char(output, indent, *s++);
+    sexp_put_char(output, *s++);
 }
 
 static void
-sexp_put_length(struct sexp_output *output, unsigned indent,
+sexp_put_length(struct sexp_output *output, 
 		unsigned length)
 {
   unsigned digit = 1;
@@ -657,47 +594,50 @@ sexp_put_length(struct sexp_output *output, unsigned indent,
     }
 
   for (; digit; length %= digit, digit /= 10)
-    sexp_put_char(output, indent, '0' + length / digit);
+    sexp_put_char(output, '0' + length / digit);
 }
 
 static void
-sexp_put_base64_start(struct sexp_output *output, uint8_t c)
+sexp_put_code_start(struct sexp_output *output,
+		    const struct nettle_armor *coding,
+		    uint8_t c)
 {
-  assert(output->coding == SEXP_PLAIN);
+  assert(!output->coding);
   
-  sexp_put_char(output, 0, c);
-
-  base64_encode_init(&output->base64);
-  output->coding = SEXP_BASE64;
+  sexp_put_raw_char(output, c);
+  output->coding_indent = output->pos;
+  
+  output->coding = coding;
+  output->coding->encode_init(&output->state);
 }
 
 static void
-sexp_put_base64_end(struct sexp_output *output, uint8_t c)
+sexp_put_code_end(struct sexp_output *output, uint8_t c)
 {
+  /* Enough for both hex and base64 */
   uint8_t encoded[BASE64_ENCODE_FINAL_LENGTH];
   unsigned done;
 
-  assert(output->coding = SEXP_BASE64);
+  assert(output->coding);
 
-  done = base64_encode_final(&output->base64, encoded);
+  done = output->coding->encode_final(&output->state, encoded);
 
   assert(done <= sizeof(encoded));
   
-  output->coding = SEXP_PLAIN;
+  output->coding = NULL;
 
-  sexp_put_data(output, 0, done, encoded);
-  sexp_put_char(output, 0, c);
+  sexp_put_data(output, done, encoded);
+  sexp_put_char(output, c);
 }
 
 static void
-sexp_put_string(struct sexp_output *output, unsigned indent,
+sexp_put_string(struct sexp_output *output, enum sexp_mode mode,
 		struct nettle_buffer *string)
 {
   if (!string->size)
-    sexp_puts(output, indent,
-	      (output->mode == SEXP_ADVANCED) ? "\"\"": "0:");
+    sexp_puts(output, (mode == SEXP_ADVANCED) ? "\"\"": "0:");
 
-  else if (output->mode == SEXP_ADVANCED)
+  else if (mode == SEXP_ADVANCED)
     {
       unsigned i;
       int token = (string->contents[0] < '0' || string->contents[0] > '9');
@@ -722,11 +662,11 @@ sexp_put_string(struct sexp_output *output, unsigned indent,
 	}
       
       if (token)
-	sexp_put_data(output, indent, string->size, string->contents);
+	sexp_put_data(output, string->size, string->contents);
 
       else if (quote_friendly)
 	{
-	  sexp_put_char(output, indent, '"');
+	  sexp_put_char(output, '"');
 
 	  for (i = 0; i<string->size; i++)
 	    {
@@ -744,78 +684,78 @@ sexp_put_string(struct sexp_output *output, unsigned indent,
 		  assert(c);
 		}
 	      if (escape)
-		sexp_put_char(output, indent, '\\');
+		sexp_put_char(output, '\\');
 
-	      sexp_put_char(output, indent, c);
+	      sexp_put_char(output, c);
 	    }
 	  
-	  sexp_put_char(output, indent, '"');
+	  sexp_put_char(output, '"');
 	}
       else
 	{
-	  sexp_put_base64_start(output, '|');
-	  sexp_put_data(output, output->pos,
-			string->size, string->contents);
-	  sexp_put_base64_end(output, '|');
+	  sexp_put_code_start(output, &nettle_base64, '|');
+	  sexp_put_data(output, string->size, string->contents);
+	  sexp_put_code_end(output, '|');
 	}
     }
   else
     {
-      sexp_put_length(output, indent, string->size);
-      sexp_put_char(output, indent, ':');
-      sexp_put_data(output, indent, string->size, string->contents);
+      sexp_put_length(output, string->size);
+      sexp_put_char(output, ':');
+      sexp_put_data(output, string->size, string->contents);
     }
 }
 
 static void
-sexp_put_list_start(struct sexp_output *output, unsigned indent)
+sexp_put_list_start(struct sexp_output *output)
 {
-  sexp_put_char(output, indent, '(');
+  sexp_put_char(output, '(');
 }
 
 static void
-sexp_put_list_end(struct sexp_output *output, unsigned indent)
+sexp_put_list_end(struct sexp_output *output)
 {
-  sexp_put_char(output, indent, ')');
+  sexp_put_char(output, ')');
 }
 
 static void
-sexp_put_display_start(struct sexp_output *output, unsigned indent)
+sexp_put_display_start(struct sexp_output *output)
 {
-  sexp_put_char(output, indent, '[');
+  sexp_put_char(output, '[');
 }
 
 static void
-sexp_put_display_end(struct sexp_output *output, unsigned indent)
+sexp_put_display_end(struct sexp_output *output)
 {
-  sexp_put_char(output, indent, ']');
+  sexp_put_char(output, ']');
 }
 
 static void
-sexp_convert_string(struct sexp_input *input, enum sexp_mode mode,
-		    struct sexp_output *output, unsigned indent)
+sexp_convert_string(struct sexp_input *input, enum sexp_mode mode_in,
+		    struct sexp_output *output, enum sexp_mode mode_out)
 {
-  sexp_get_token(input, mode);
+  sexp_get_token(input, mode_in);
   if (input->token == SEXP_STRING)
-    sexp_put_string(output, indent, &input->string);
+    sexp_put_string(output, mode_out, &input->string);
   else
     die("Invalid string.\n");
 }
 
 static int
-sexp_convert_item(struct sexp_input *input, enum sexp_mode mode,
-		  struct sexp_output *output, unsigned indent);
+sexp_convert_item(struct sexp_input *input, enum sexp_mode mode_in,
+		  struct sexp_output *output, enum sexp_mode mode_out,
+		  unsigned indent);
 
 static void
-sexp_convert_list(struct sexp_input *input, enum sexp_mode mode,
-		  struct sexp_output *output, 
+sexp_convert_list(struct sexp_input *input, enum sexp_mode mode_in,
+		  struct sexp_output *output, enum sexp_mode mode_out,
 		  unsigned indent)
 {
   unsigned item;
 
   for (item = 0;; item++)
     {
-      sexp_get_token(input, mode);
+      sexp_get_token(input, mode_in);
   
       /* Check for end of list */
       if (input->token == SEXP_LIST_END
@@ -823,37 +763,38 @@ sexp_convert_list(struct sexp_input *input, enum sexp_mode mode,
 	  || input->token == SEXP_TRANSPORT_END)
 	return;
 
-      if (output->mode == SEXP_ADVANCED)
+      if (mode_out == SEXP_ADVANCED)
 	{
 	  /* FIXME: Adapt pretty printing to handle a big first
 	   * element. */
 	  if (item == 1)
 	    {
-	      sexp_put_char(output, indent, ' ');
+	      sexp_put_char(output, ' ');
 	      indent = output->pos;
 	    }
 	  else if (item > 1)
 	    sexp_put_newline(output, indent);
 	}
       
-      if (!sexp_convert_item(input, mode, output, indent))
+      if (!sexp_convert_item(input, mode_in, output, mode_out, indent))
 	/* Should be detected above */
 	abort();
     }
 }
 
 static void
-sexp_convert_file(struct sexp_input *input, struct sexp_output *output)
+sexp_convert_file(struct sexp_input *input, enum sexp_mode mode_in,
+		  struct sexp_output *output, enum sexp_mode mode_out)
 {
-  sexp_get_token(input, SEXP_ADVANCED);
+  sexp_get_token(input, mode_in);
 
   while (input->token != SEXP_EOF)
     {
-      sexp_convert_item(input, SEXP_ADVANCED, output, 0);
-      if (output->mode == SEXP_ADVANCED)
+      sexp_convert_item(input, mode_in, output, mode_out, 0);
+      if (mode_out != SEXP_CANONICAL)
 	sexp_put_newline(output, 0);
 	  
-      sexp_get_token(input, SEXP_ADVANCED);
+      sexp_get_token(input, mode_in);
     }
 
   if (fflush(output->f) < 0)
@@ -875,17 +816,24 @@ sexp_skip_token(struct sexp_input *input, enum sexp_mode mode,
  *
  * Should be called after getting the first token. */
 static int
-sexp_convert_item(struct sexp_input *input, enum sexp_mode mode,
-		  struct sexp_output *output, unsigned indent)
+sexp_convert_item(struct sexp_input *input, enum sexp_mode mode_in,
+		  struct sexp_output *output, enum sexp_mode mode_out,
+		  unsigned indent)
 {
-  switch(input->token)
+  if (mode_out == SEXP_TRANSPORT)
+    {
+      sexp_put_code_start(output, &nettle_base64, '{');
+      sexp_convert_item(input, mode_in, output, SEXP_CANONICAL, 0);
+      sexp_put_code_end(output, '}');
+    }
+  else switch(input->token)
     {
     case SEXP_LIST_START:
       input->level++;
       
-      sexp_put_list_start(output, indent);
-      sexp_convert_list(input, mode, output, indent);
-      sexp_put_list_end(output, indent);
+      sexp_put_list_start(output);
+      sexp_convert_list(input, mode_in, output, mode_out, indent);
+      sexp_put_list_end(output);
 
       if (input->level)
 	{
@@ -911,18 +859,18 @@ sexp_convert_item(struct sexp_input *input, enum sexp_mode mode,
       break;
 
     case SEXP_STRING:
-      sexp_put_string(output, indent, &input->string);
+      sexp_put_string(output, mode_out, &input->string);
       break;
     case SEXP_DISPLAY_START:
-      sexp_put_display_start(output, indent);
-      sexp_convert_string(input, mode, output, indent);
-      sexp_skip_token(input, mode, SEXP_DISPLAY_END);
-      sexp_put_display_end(output, indent);
-      sexp_convert_string(input, mode, output, indent);
+      sexp_put_display_start(output);
+      sexp_convert_string(input, mode_in, output, mode_out);
+      sexp_skip_token(input, mode_in, SEXP_DISPLAY_END);
+      sexp_put_display_end(output);
+      sexp_convert_string(input, mode_in, output, mode_out);
       break;
       
     case SEXP_TRANSPORT_START:
-      if (mode != SEXP_ADVANCED)
+      if (mode_in == SEXP_CANONICAL)
 	die("Base64 not allowed in canonical mode.\n");
       else
 	{
@@ -935,7 +883,7 @@ sexp_convert_item(struct sexp_input *input, enum sexp_mode mode,
 	  base64_decode_init(&input->base64);
 
 	  /* FIXME: sexp_convert_list is wrong. */
-	  sexp_convert_list(input, SEXP_CANONICAL, output, indent);
+	  sexp_convert_list(input, SEXP_CANONICAL, output, mode_out, indent);
 	  
 	  input->coding = SEXP_PLAIN;
 	  input->level = old_level;
@@ -944,7 +892,7 @@ sexp_convert_item(struct sexp_input *input, enum sexp_mode mode,
     case SEXP_TRANSPORT_END:
       /* FIXME: Should be moved do sexp_convert_transport */
       if ( (input->coding != SEXP_BASE64)
-	   || input->level || !base64_decode_status(&input->base64))
+	   || input->level || !base64_decode_final(&input->base64))
 	die("Invalid base64.\n");
 
       break;
@@ -957,6 +905,8 @@ sexp_convert_item(struct sexp_input *input, enum sexp_mode mode,
 static int
 match_argument(const char *given, const char *name)
 {
+  /* FIXME: Allow abbreviations */
+  return !strcmp(given, name);
 }
 
 int
@@ -972,12 +922,11 @@ main(int argc, char **argv)
     switch (c)
       {
       case 's':
-	/* FIXME: Allow abbreviations */
-	if (!strcmp(optarg, "advanced"))
+	if (match_argument(optarg, "advanced"))
 	  mode = SEXP_ADVANCED;
-	else if (!strcmp(optarg, "transport"))
+	else if (match_argument(optarg, "transport"))
 	  mode = SEXP_TRANSPORT;
-	else if (!strcmp(optarg, "canonical"))
+	else if (match_argument(optarg, "canonical"))
 	  mode = SEXP_CANONICAL;
 	else
 	  die("Available syntax variants: advanced, transport, canonical\n");
@@ -995,9 +944,9 @@ main(int argc, char **argv)
       }
   
   sexp_input_init(&input, stdin);
-  sexp_output_init(&output, stdout, mode);
+  sexp_output_init(&output, stdout);
 
-  sexp_convert_file(&input, &output);
+  sexp_convert_file(&input, SEXP_ADVANCED, &output, mode);
 
   return EXIT_SUCCESS;
 }
-- 
GitLab