base16-decode.c 3.06 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
/* base16-encode.c
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

   Hex decoding.

   Copyright (C) 2002 Niels Möller

   This file is part of GNU Nettle.

   GNU Nettle is free software: you can redistribute it and/or
   modify it under the terms of either:

     * the GNU Lesser General Public License as published by the Free
       Software Foundation; either version 3 of the License, or (at your
       option) any later version.

   or

     * the GNU General Public License as published by the Free
       Software Foundation; either version 2 of the License, or (at your
       option) any later version.

   or both in parallel, as here.

   GNU Nettle is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received copies of the GNU General Public License and
   the GNU Lesser General Public License along with this program.  If
   not, see http://www.gnu.org/licenses/.
*/
Niels Möller's avatar
Niels Möller committed
33
 
34 35 36
#if HAVE_CONFIG_H
# include "config.h"
#endif
Niels Möller's avatar
Niels Möller committed
37 38 39 40

#include <assert.h>
#include <stdlib.h>

41 42
#include "base16.h"

Niels Möller's avatar
Niels Möller committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
void
base16_decode_init(struct base16_decode_ctx *ctx)
{
  ctx->word = ctx->bits = 0;
}

enum { HEX_INVALID = -1, HEX_SPACE=-2 };

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,
  };

/* Decodes a single byte. Returns amount of output (0 or 1), or -1 on
 * errors. */
int
base16_decode_single(struct base16_decode_ctx *ctx,
		     uint8_t *dst,
69
		     char src)
Niels Möller's avatar
Niels Möller committed
70
{
71 72
  /* Avoid signed char for indexing. */
  unsigned char usrc = src;
Niels Möller's avatar
Niels Möller committed
73 74
  int digit;

75
  if (usrc >= 0x80)
Niels Möller's avatar
Niels Möller committed
76 77
    return -1;

78
  digit = hex_decode_table[usrc];
Niels Möller's avatar
Niels Möller committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
  switch (digit)
    {
    case -1:
      return -1;
    case -2:
      return 0;
    default:
      assert(digit >= 0);
      assert(digit < 0x10);

      if (ctx->bits)
	{
	  *dst = (ctx->word << 4) | digit;
	  ctx->bits = 0;
	  return 1;
	}
      else
	{
	  ctx->word = digit;
	  ctx->bits = 4;
	  return 0;
	}
    }
}

int
base16_decode_update(struct base16_decode_ctx *ctx,
106
		     size_t *dst_length,
Niels Möller's avatar
Niels Möller committed
107
		     uint8_t *dst,
108
		     size_t src_length,
109
		     const char *src)
Niels Möller's avatar
Niels Möller committed
110
{
111 112
  size_t done;
  size_t i;
Niels Möller's avatar
Niels Möller committed
113

114
  for (i = done = 0; i<src_length; i++)
Niels Möller's avatar
Niels Möller committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    switch(base16_decode_single(ctx, dst + done, src[i]))
      {
      case -1:
	return 0;
      case 1:
	done++;
	/* Fall through */
      case 0:
	break;
      default:
	abort();
      }
  
  assert(done <= BASE16_DECODE_LENGTH(src_length));

  *dst_length = done;
  return 1;
}

int
base16_decode_final(struct base16_decode_ctx *ctx)
{
  return ctx->bits == 0;
}