Commit b7b49518 authored by Niels Möller's avatar Niels Möller
Browse files

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
parent 0507d532
......@@ -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"))
<