eb4825d30f6db96df09a4cd0487be7ba0d9c279c
[platform/upstream/nettle.git] / tools / output.c
1 /* output.c
2
3    Copyright (C) 2002, 2003, 2009 Niels Möller
4
5    This file is part of GNU Nettle.
6
7    GNU Nettle is free software: you can redistribute it and/or
8    modify it under the terms of either:
9
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at your
12        option) any later version.
13
14    or
15
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at your
18        option) any later version.
19
20    or both in parallel, as here.
21
22    GNU Nettle is distributed in the hope that it will be useful,
23    but WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see http://www.gnu.org/licenses/.
30 */
31
32 #if HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <assert.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "output.h"
43
44 /* For TMP_ALLOC */ 
45 #include "nettle-internal.h"
46
47 void
48 sexp_output_init(struct sexp_output *output, FILE *f,
49                  unsigned width, int prefer_hex)
50 {
51   output->f = f;
52   output->line_width = width;
53   output->coding = NULL;
54   output->prefer_hex = prefer_hex;
55   output->hash = NULL;
56   output->ctx = NULL;
57   
58   output->pos = 0;
59   output->soft_newline = 0;
60 }
61
62 void
63 sexp_output_hash_init(struct sexp_output *output,
64                       const struct nettle_hash *hash, void *ctx)
65 {
66   output->hash = hash;
67   output->ctx = ctx;
68   hash->init(ctx);
69 }
70
71 static void
72 sexp_put_raw_char(struct sexp_output *output, uint8_t c)
73 {
74   if (putc(c, output->f) < 0)
75     die("Write failed: %s\n", strerror(errno));
76
77   output->pos++;
78   output->soft_newline = 0;
79 }
80
81 void
82 sexp_put_newline(struct sexp_output *output,
83                  unsigned indent)
84 {
85   if (output->soft_newline)
86     output->soft_newline = 0;
87   else
88     {
89       unsigned i;
90
91       sexp_put_raw_char(output, '\n');
92       output->pos = 0;
93   
94       for(i = 0; i < indent; i++)
95         sexp_put_raw_char(output, ' ');
96   
97       output->pos = indent;
98     }
99 }
100
101 /* Put a newline, but only if it is followed by another newline,
102    collaps to one newline only. */
103 void
104 sexp_put_soft_newline(struct sexp_output *output,
105                       unsigned indent)
106 {
107   sexp_put_newline(output, indent);
108   output->soft_newline = 1;
109 }
110
111 void
112 sexp_put_char(struct sexp_output *output, uint8_t c)
113 {
114   if (output->coding)
115     {
116       /* Two is enough for both base16 and base64. */
117       uint8_t encoded[2];
118       unsigned done;
119
120       unsigned i;
121
122       done = output->coding->encode_update(&output->base64, encoded,
123                                            1, &c);
124       assert(done <= sizeof(encoded));
125       
126       for (i = 0; i<done; i++)
127         {
128           if (output->line_width
129               && output->pos >= output->line_width
130               && output->pos >= (output->coding_indent + 10))
131             sexp_put_newline(output, output->coding_indent);
132           
133           sexp_put_raw_char(output, encoded[i]);
134         }
135     }
136   else if (output->hash)
137     output->hash->update(output->ctx, 1, &c);
138   else
139     sexp_put_raw_char(output, c);
140 }
141
142 void
143 sexp_put_data(struct sexp_output *output,
144               unsigned length, const uint8_t *data)
145 {
146   unsigned i;
147
148   for (i = 0; i<length; i++)
149     sexp_put_char(output, data[i]);
150 }
151
152 static void
153 sexp_put_length(struct sexp_output *output, 
154                 unsigned length)
155 {
156   unsigned digit = 1;
157
158   for (;;)
159     {
160       unsigned next = digit * 10;
161       if (next > length)
162         break;
163       digit = next;
164     }
165
166   for (; digit; length %= digit, digit /= 10)
167     sexp_put_char(output, '0' + length / digit);
168 }
169
170 void
171 sexp_put_code_start(struct sexp_output *output,
172                     const struct nettle_armor *coding)
173 {
174   assert(!output->coding);
175   
176   output->coding_indent = output->pos;
177   
178   output->coding = coding;
179   output->coding->encode_init(&output->base64);
180 }
181
182 void
183 sexp_put_code_end(struct sexp_output *output)
184 {
185   /* Enough for both hex and base64 */
186   uint8_t encoded[BASE64_ENCODE_FINAL_LENGTH];
187   unsigned done;
188
189   assert(output->coding);
190
191   done = output->coding->encode_final(&output->base64, encoded);
192
193   assert(done <= sizeof(encoded));
194   
195   output->coding = NULL;
196
197   sexp_put_data(output, done, encoded);
198 }
199
200 void
201 sexp_put_string(struct sexp_output *output, enum sexp_mode mode,
202                 struct nettle_buffer *string)
203 {
204   if (!string->size)
205     sexp_put_data(output, 2,
206                   (mode == SEXP_ADVANCED) ? "\"\"": "0:");
207
208   else if (mode == SEXP_ADVANCED)
209     {
210       unsigned i;
211       int token = (string->contents[0] < '0' || string->contents[0] > '9');
212       int quote_friendly = 1;
213 #define CONTROL_SIZE 0x20
214       static const char escape_names[CONTROL_SIZE] =
215         {
216           0,0,0,0,0,0,0,0, 'b','t','n',0,'f','r',0,0,
217           0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
218         };
219
220       for (i = 0; i<string->size; i++)
221         {
222           uint8_t c = string->contents[i];
223           
224           if (token & !TOKEN_CHAR(c))
225             token = 0;
226           
227           if (quote_friendly)
228             {
229               if (c >= 0x7f)
230                 quote_friendly = 0;
231               else if (c < CONTROL_SIZE && !escape_names[c])
232                 quote_friendly = 0;
233             }
234         }
235       
236       if (token)
237         sexp_put_data(output, string->size, string->contents);
238
239       else if (quote_friendly)
240         {
241           sexp_put_char(output, '"');
242
243           for (i = 0; i<string->size; i++)
244             {
245               int escape = 0;
246               uint8_t c = string->contents[i];
247
248               assert(c < 0x7f);
249               
250               if (c == '\\' || c == '"')
251                 escape = 1;
252               else if (c < CONTROL_SIZE)
253                 {
254                   escape = 1;
255                   c = escape_names[c];
256                   assert(c);
257                 }
258               if (escape)
259                 sexp_put_char(output, '\\');
260
261               sexp_put_char(output, c);
262             }
263           
264           sexp_put_char(output, '"');
265         }
266       else 
267         {
268           uint8_t delimiter;
269           const struct nettle_armor *coding;
270           
271           if (output->prefer_hex)
272             {
273               delimiter = '#';
274               coding = &nettle_base16;
275             }
276           else
277             {
278               delimiter = '|';
279               coding = &nettle_base64;
280             }
281           
282           sexp_put_char(output, delimiter);
283           sexp_put_code_start(output, coding);
284           sexp_put_data(output, string->size, string->contents);
285           sexp_put_code_end(output);
286           sexp_put_char(output, delimiter);
287         }
288 #undef CONTROL_SIZE
289     }
290   else
291     {
292       sexp_put_length(output, string->size);
293       sexp_put_char(output, ':');
294       sexp_put_data(output, string->size, string->contents);
295     }
296 }
297
298 void
299 sexp_put_digest(struct sexp_output *output)
300 {
301   TMP_DECL(digest, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE);
302   TMP_ALLOC(digest, output->hash->digest_size);
303   
304   assert(output->hash);
305
306   output->hash->digest(output->ctx, output->hash->digest_size, digest);
307
308   sexp_put_code_start(output, &nettle_base16);
309   sexp_put_data(output, output->hash->digest_size, digest);
310   sexp_put_code_end(output);
311 }
312