sexp-transport.c 2.94 KB
Newer Older
1 2 3 4 5 6 7
/* sexp-transport.c
 *
 * Parsing s-expressions in transport format.
 */

/* nettle, low-level cryptographics library
 *
Niels Möller's avatar
Niels Möller committed
8
 * Copyright (C) 2002 Niels Möller
9 10 11 12 13 14 15 16 17 18 19 20 21
 *  
 * The nettle library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * The nettle library 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 Lesser General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with the nettle library; see the file COPYING.LIB.  If not, write to
22 23
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02111-1301, USA.
24 25
 */

26 27 28
#if HAVE_CONFIG_H
# include "config.h"
#endif
29 30 31 32

#include <assert.h>
#include <string.h>

33 34 35 36
#include "sexp.h"

#include "base64.h"

37 38 39
/* NOTE: Decodes the input string in place */
int
sexp_transport_iterator_first(struct sexp_iterator *iterator,
40
			      size_t length, uint8_t *input)
41 42 43 44
{
  /* We first base64 decode any transport encoded sexp at the start of
   * the input. */

45 46
  size_t in = 0;
  size_t out = 0;
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

  while (in < length)
    switch(input[in])
      {
      case ' ':  /* SPC, TAB, LF, CR */
      case '\t':
      case '\n':
      case '\r':
	in++;
	break;
	  
      case ';':  /* Comments */
	while (++in < length && input[in] != '\n')
	  ;
	break;
	  
      case '{':
	{
	  /* Found transport encoding */
	  struct base64_decode_ctx ctx;
67 68
	  size_t coded_length;
	  size_t end;
69 70 71 72 73 74 75 76

	  for (end = ++in; end < length && input[end] != '}'; end++)
	    ;

	  if (end == length)
	    return 0;
	    
	  base64_decode_init(&ctx);
77
	  coded_length = end - in;
78
	  
79 80
	  if (base64_decode_update(&ctx, &coded_length, input + out,
				   coded_length, input + in)
81 82
	      && base64_decode_final(&ctx))
	    {	  
83
	      out += coded_length;
84 85 86
	      in = end + 1;
	    }
	  else
87
	    return 0;
88
	  
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	  break;
	}
      default:
	/* Expression isn't in transport encoding. Rest of the input
	 * should be in canonical encoding. */
	goto transport_done;
      }
  
 transport_done:

  /* Here, we have two, possibly empty, input parts in canonical
   * encoding:
   *
   * 0...out-1,  in...length -1
   *
   * If the input was already in canonical encoding, out = 0 and in =
   * amount of leading space.
   *
   * If all input was in transport encoding, in == length.
   */
  if (!out)
    {
      input += in;
      length -= in;
    }
  else if (in == length)
    length = out;
  else if (out == in)
    /* Unusual case, nothing happens */
    ;
  else
    {
      /* Both parts non-empty */
      assert(out < in);
      memmove(input + out, input + in, length - in);
      length -= (in - out);
    }

  return sexp_iterator_first(iterator, length, input);
}