sexp-format.c 5.34 KB
Newer Older
1
/* sexp-format.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
 *
 * Writing s-expressions.
 */

/* nettle, low-level cryptographics library
 *
 * Copyright (C) 2002 Niels Mller
 *  
 * 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
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include "sexp.h"
#include "buffer.h"

33
#include <assert.h>
34
35
36
37
38
39
40
41
42
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if HAVE_LIBGMP
# include "bignum.h"
#endif

43
44
/* Code copied from sexp-conv.c: sexp_put_length */
static unsigned
Niels Möller's avatar
Niels Möller committed
45
format_prefix(struct nettle_buffer *buffer,
46
47
	      unsigned length)
{
48
49
50
51
52
53
54
55
  unsigned digit = 1;
  unsigned prefix_length = 1;
  
  for (;;)
    {
      unsigned next = digit * 10;
      if (next > length)
	break;
56

57
58
59
      prefix_length++;
      digit = next;
    }
60

61
62
63
64
65
66
67
68
69
70
71
  if (buffer)
    {
      for (; digit; length %= digit, digit /= 10)
	if (!NETTLE_BUFFER_PUTC(buffer, '0' + length / digit))
	  return 0;
      
      if (!NETTLE_BUFFER_PUTC(buffer, ':'))
	return 0;
    }

  return prefix_length + 1;
72
73
}

74
static unsigned
75
76
77
format_length_string(struct nettle_buffer *buffer,
		     unsigned length, const char *s)
{
78
79
80
  unsigned done = format_prefix(buffer, length);
  if (!done)
    return 0;
81

82
83
84
85
  if (buffer && !nettle_buffer_write(buffer, length, s))
    return 0;
  
  return done + length;
86
87
}

88
static unsigned
89
90
91
92
93
94
format_string(struct nettle_buffer *buffer,
	      const char *s)
{
  return format_length_string(buffer, strlen(s), s);
}

95
96
unsigned
sexp_vformat(struct nettle_buffer *buffer, const char *format, va_list args)
97
98
{
  unsigned nesting = 0;
99
  unsigned done = 0;
100

101
102
103
  for (;;)
    switch (*format++)
      {
104
105
106
      default:
	abort();

107
      case '\0':
108
109
110
111
	assert(!nesting);
	    
	return done;

112
      case '(':
113
114
	if (buffer && !NETTLE_BUFFER_PUTC(buffer, '('))
	  return 0;
115

116
	done++;
117
118
119
120
	nesting++;
	break;

      case ')':
121
122
123
124
125
	assert (nesting);
	if (buffer && !NETTLE_BUFFER_PUTC(buffer, ')'))
	  return 0;

	done++;
126
127
128
129
130
131
	nesting--;
	break;

      case '%':
	switch (*format++)
	  {
132
133
134
	  default:
	    abort();
	    
135
136
137
138
139
140
141
142
143
144
145
	  case 'z':
	    {
	      const char *s = va_arg(args, const char *);
	      unsigned length = format_string(buffer, s);

	      if (!length)
		return 0;

	      done += length;
	      break;
	    }
146
147
	  case 's':
	    {
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
	      unsigned length = va_arg(args, unsigned);
	      const char *s = va_arg(args, const char *);
	      unsigned prefix_length = format_prefix(buffer, length);
	      
	      if (!prefix_length)
		return 0;

	      done += prefix_length;

	      if (buffer && !nettle_buffer_write(buffer, length, s))
		return 0;

	      done += length;

	      break;
	    }
	  case 'l':
	    {
	      unsigned length = va_arg(args, unsigned);
167
	      const char *s = va_arg(args, const char *);
168
169
170
171
172
173
174
175
176
177
178
179

	      if (buffer && !nettle_buffer_write(buffer, length, s))
		return 0;
	      
	      done += length;
	      break;
	    }
	  case 'i':
	    {
	      uint32_t x = va_arg(args, uint32_t);
	      unsigned length;
	      
180
	      if (x < 0x80)
181
		length = 1;
182
	      else if (x < 0x8000L)
183
		length = 2;
184
	      else if (x < 0x800000L)
185
		length = 3;
186
	      else if (x < 0x80000000L)
187
		length = 4;
188
189
190
	      else
		length = 5;
	      
191
192
193
194
195
196
197
198
199
	      if (buffer && !(NETTLE_BUFFER_PUTC(buffer, '0' + length)
			      && NETTLE_BUFFER_PUTC(buffer, ':')))
		return 0;

	      done += (2 + length);

	      if (buffer)
		switch(length)
		{
200
201
202
203
204
		case 5:
		  /* Leading byte needed for the sign. */
		  if (!NETTLE_BUFFER_PUTC(buffer, 0))
		    return 0;
		  /* Fall through */
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
		case 4:
		  if (!NETTLE_BUFFER_PUTC(buffer, x >> 24))
		    return 0;
		  /* Fall through */
		case 3:
		  if (!NETTLE_BUFFER_PUTC(buffer, (x >> 16) & 0xff))
		    return 0;
		  /* Fall through */
		case 2:
		  if (!NETTLE_BUFFER_PUTC(buffer, (x >> 8) & 0xff))
		    return 0;
		  /* Fall through */
		case 1:
		  if (!NETTLE_BUFFER_PUTC(buffer, x & 0xff))
		    return 0;
		  break;
		default:
		  abort();
		}
224
225
226
227
228
229
230
	      break;
	    }
	  case 'b':
	    {
#if HAVE_LIBGMP
	      const MP_INT *n = va_arg(args, const MP_INT *);
	      unsigned length;
231
	      unsigned prefix_length;
232
	      
233
	      length = nettle_mpz_sizeinbase_256_s(n);
234
235
236
237
238
	      prefix_length = format_prefix(buffer, length);
	      if (!prefix_length)
		return 0;

	      done += prefix_length;
239

240
241
242
243
244
245
246
247
248
249
250
	      if (buffer)
		{
		  uint8_t *space = nettle_buffer_space(buffer, length);
		  if (!space)
		    return 0;
		  
		  nettle_mpz_get_str_256(length, space, n);
		}

	      done += length;
	      
251
252
253
254
255
256
257
258
#else /* ! HAVE_LIBGMP */
	      abort();
#endif /* ! HAVE_LIBGMP */
	      break;
	    }
	  }
      }
}
259
260
261
262
263
264
265
266
267
268
269
270
271

unsigned
sexp_format(struct nettle_buffer *buffer, const char *format, ...)
{
  va_list args;
  unsigned done;
  
  va_start(args, format);
  done = sexp_vformat(buffer, format, args);
  va_end(args);

  return done;
}