Protocol version 1.2 integrations
[crypto.git] / lib / silcutil / silcbuffmt.c
1 /*
2
3   silcbuffmt.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 /* Macro to check whether there is enough free space to add the
25    required amount of data. For unformatting this means that there must
26    be the data that is to be extracted. */
27 #define MY_HAS_SPACE(__x__, __req__)            \
28   do {                                          \
29     if (__req__ > (__x__)->len)                 \
30       goto fail;                                \
31   } while(0)
32
33 /* Formats the arguments sent and puts them into the buffer sent as
34    argument. The buffer must be initialized beforehand and it must have
35    enough free space to include the formatted data. If this function
36    fails caller should not trust the buffer anymore and should free it.
37    This function is used, for example, to create packets to send over
38    network. */
39
40 int silc_buffer_format(SilcBuffer dst, ...)
41 {
42   va_list ap;
43   int ret;
44
45   va_start(ap, dst);
46   ret = silc_buffer_format_vp(dst, ap);
47   va_end(ap);
48
49   return ret;
50 }
51
52 int silc_buffer_format_vp(SilcBuffer dst, va_list ap)
53 {
54   SilcBufferParamType fmt;
55   unsigned char *start_ptr = dst->data;
56   int len;
57
58   /* Parse the arguments by formatting type. */
59   while (1) {
60     fmt = va_arg(ap, SilcBufferParamType);
61
62     switch(fmt) {
63     case SILC_BUFFER_PARAM_SI8_CHAR:
64       {
65         char x = (char)va_arg(ap, int);
66         MY_HAS_SPACE(dst, 1);
67         silc_buffer_put(dst, &x, 1);
68         silc_buffer_pull(dst, 1);
69         break;
70       }
71     case SILC_BUFFER_PARAM_UI8_CHAR:
72       {
73         unsigned char x = (unsigned char)va_arg(ap, int);
74         MY_HAS_SPACE(dst, 1);
75         silc_buffer_put(dst, &x, 1);
76         silc_buffer_pull(dst, 1);
77         break;
78       }
79     case SILC_BUFFER_PARAM_SI16_SHORT:
80       {
81         unsigned char xf[2];
82         SilcInt16 x = (SilcInt16)va_arg(ap, int);
83         MY_HAS_SPACE(dst, 2);
84         SILC_PUT16_MSB(x, xf);
85         silc_buffer_put(dst, xf, 2);
86         silc_buffer_pull(dst, 2);
87         break;
88       }
89     case SILC_BUFFER_PARAM_UI16_SHORT:
90       {
91         unsigned char xf[2];
92         SilcUInt16 x = (SilcUInt16)va_arg(ap, int);
93         MY_HAS_SPACE(dst, 2);
94         SILC_PUT16_MSB(x, xf);
95         silc_buffer_put(dst, xf, 2);
96         silc_buffer_pull(dst, 2);
97         break;
98       }
99     case SILC_BUFFER_PARAM_SI32_INT:
100       {
101         unsigned char xf[4];
102         SilcInt32 x = va_arg(ap, SilcInt32);
103         MY_HAS_SPACE(dst, 4);
104         SILC_PUT32_MSB(x, xf);
105         silc_buffer_put(dst, xf, 4);
106         silc_buffer_pull(dst, 4);
107         break;
108       }
109     case SILC_BUFFER_PARAM_UI32_INT:
110       {
111         unsigned char xf[4];
112         SilcUInt32 x = va_arg(ap, SilcUInt32);
113         MY_HAS_SPACE(dst, 4);
114         SILC_PUT32_MSB(x, xf);
115         silc_buffer_put(dst, xf, 4);
116         silc_buffer_pull(dst, 4);
117         break;
118       }
119     case SILC_BUFFER_PARAM_SI64_INT:
120       {
121         unsigned char xf[8];
122         SilcInt64 x = va_arg(ap, SilcInt64);
123         MY_HAS_SPACE(dst, sizeof(SilcInt64));
124         SILC_PUT64_MSB(x, xf);
125         silc_buffer_put(dst, xf, sizeof(SilcInt64));
126         silc_buffer_pull(dst, sizeof(SilcInt64));
127         break;
128       }
129     case SILC_BUFFER_PARAM_UI64_INT:
130       {
131         unsigned char xf[8];
132         SilcUInt64 x = va_arg(ap, SilcUInt64);
133         MY_HAS_SPACE(dst, sizeof(SilcUInt64));
134         SILC_PUT64_MSB(x, xf);
135         silc_buffer_put(dst, xf, sizeof(SilcUInt64));
136         silc_buffer_pull(dst, sizeof(SilcUInt64));
137         break;
138       }
139     case SILC_BUFFER_PARAM_UI8_STRING:
140     case SILC_BUFFER_PARAM_UI16_STRING:
141     case SILC_BUFFER_PARAM_UI32_STRING:
142     case SILC_BUFFER_PARAM_UI8_STRING_ALLOC:
143     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
144     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
145       {
146         unsigned char *x = va_arg(ap, unsigned char *);
147         SilcUInt32 tmp_len = strlen(x);
148         MY_HAS_SPACE(dst, tmp_len);
149         silc_buffer_put(dst, x, tmp_len);
150         silc_buffer_pull(dst, tmp_len);
151         break;
152       }
153     case SILC_BUFFER_PARAM_UI8_NSTRING:
154     case SILC_BUFFER_PARAM_UI16_NSTRING:
155     case SILC_BUFFER_PARAM_UI32_NSTRING:
156     case SILC_BUFFER_PARAM_UI_XNSTRING:
157     case SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC:
158     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
159     case SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC:
160     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
161       {
162         unsigned char *x = va_arg(ap, unsigned char *);
163         SilcUInt32 len = va_arg(ap, SilcUInt32);
164         MY_HAS_SPACE(dst, len);
165         silc_buffer_put(dst, x, len);
166         silc_buffer_pull(dst, len);
167         break;
168       }
169     case SILC_BUFFER_PARAM_END:
170       goto ok;
171       break;
172     default:
173       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
174                       "format the data.", fmt));
175       goto fail;
176       break;
177     }
178   }
179
180  fail:
181   SILC_LOG_DEBUG(("Error occured while formatting data"));
182   len = dst->data - start_ptr;
183   silc_buffer_push(dst, len);
184   return -1;
185
186  ok:
187   /* Push the buffer back to where it belongs. */
188   len = dst->data - start_ptr;
189   silc_buffer_push(dst, len);
190   return len;
191 }
192
193 /* Unformats the buffer sent as argument. The unformatted data is returned
194    to the variable argument list of pointers. The buffer must point to the
195    start of the data area to be unformatted. Buffer maybe be safely free'd
196    after this returns succesfully. */
197
198 int silc_buffer_unformat(SilcBuffer src, ...)
199 {
200   va_list ap;
201   int ret;
202
203   va_start(ap, src);
204   ret = silc_buffer_unformat_vp(src, ap);
205   va_end(ap);
206
207   return ret;
208 }
209
210 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
211 {
212   SilcBufferParamType fmt;
213   unsigned char *start_ptr = src->data;
214   int len = 0;
215
216   /* Parse the arguments by formatting type. */
217   while(1) {
218     fmt = va_arg(ap, SilcBufferParamType);
219
220     switch(fmt) {
221     case SILC_BUFFER_PARAM_SI8_CHAR:
222       {
223         char *x = va_arg(ap, char *);
224         MY_HAS_SPACE(src, 1);
225         if (x)
226           *x = src->data[0];
227         silc_buffer_pull(src, 1);
228         break;
229       }
230     case SILC_BUFFER_PARAM_UI8_CHAR:
231       {
232         unsigned char *x = va_arg(ap, unsigned char *);
233         MY_HAS_SPACE(src, 1);
234         if (x)
235           *x = src->data[0];
236         silc_buffer_pull(src, 1);
237         break;
238       }
239     case SILC_BUFFER_PARAM_SI16_SHORT:
240       {
241         SilcInt16 *x = va_arg(ap, SilcInt16 *);
242         MY_HAS_SPACE(src, 2);
243         if (x)
244           SILC_GET16_MSB(*x, src->data);
245         silc_buffer_pull(src, 2);
246         break;
247       }
248     case SILC_BUFFER_PARAM_UI16_SHORT:
249       {
250         SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
251         MY_HAS_SPACE(src, 2);
252         if (x)
253           SILC_GET16_MSB(*x, src->data);
254         silc_buffer_pull(src, 2);
255         break;
256       }
257     case SILC_BUFFER_PARAM_SI32_INT:
258       {
259         SilcInt32 *x = va_arg(ap, SilcInt32 *);
260         MY_HAS_SPACE(src, 4);
261         if (x)
262           SILC_GET32_MSB(*x, src->data);
263         silc_buffer_pull(src, 4);
264         break;
265       }
266     case SILC_BUFFER_PARAM_UI32_INT:
267       {
268         SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
269         MY_HAS_SPACE(src, 4);
270         if (x)
271           SILC_GET32_MSB(*x, src->data);
272         silc_buffer_pull(src, 4);
273         break;
274       }
275     case SILC_BUFFER_PARAM_SI64_INT:
276       {
277         SilcInt64 *x = va_arg(ap, SilcInt64 *);
278         MY_HAS_SPACE(src, sizeof(SilcInt64));
279         if (x)
280           SILC_GET64_MSB(*x, src->data);
281         silc_buffer_pull(src, sizeof(SilcInt64));
282         break;
283       }
284     case SILC_BUFFER_PARAM_UI64_INT:
285       {
286         SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
287         MY_HAS_SPACE(src, sizeof(SilcUInt64));
288         if (x)
289           SILC_GET64_MSB(*x, src->data);
290         silc_buffer_pull(src, sizeof(SilcUInt64));
291         break;
292       }
293     case SILC_BUFFER_PARAM_UI8_STRING:
294       {
295         SilcUInt8 len2;
296         unsigned char **x = va_arg(ap, unsigned char **);
297         MY_HAS_SPACE(src, 1);
298         len2 = (SilcUInt8)src->data[0];
299         silc_buffer_pull(src, 1);
300         MY_HAS_SPACE(src, len2);
301         if (x)
302           *x = src->data;
303         silc_buffer_pull(src, len2);
304         break;
305       }
306     case SILC_BUFFER_PARAM_UI16_STRING:
307       {
308         SilcUInt16 len2;
309         unsigned char **x = va_arg(ap, unsigned char **);
310         MY_HAS_SPACE(src, 2);
311         SILC_GET16_MSB(len2, src->data);
312         silc_buffer_pull(src, 2);
313         MY_HAS_SPACE(src, len2);
314         if (x)
315           *x = src->data;
316         silc_buffer_pull(src, len2);
317         break;
318       }
319     case SILC_BUFFER_PARAM_UI8_STRING_ALLOC:
320       {
321         SilcUInt8 len2;
322         unsigned char **x = va_arg(ap, unsigned char **);
323         MY_HAS_SPACE(src, 1);
324         len2 = (SilcUInt8)src->data[0];
325         silc_buffer_pull(src, 1);
326         MY_HAS_SPACE(src, len2);
327         if (x && len2) {
328           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
329           memcpy(*x, src->data, len2);
330         }
331         silc_buffer_pull(src, len2);
332         break;
333       }
334     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
335       {
336         SilcUInt16 len2;
337         unsigned char **x = va_arg(ap, unsigned char **);
338         MY_HAS_SPACE(src, 2);
339         SILC_GET16_MSB(len2, src->data);
340         silc_buffer_pull(src, 2);
341         MY_HAS_SPACE(src, len2);
342         if (x && len2) {
343           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
344           memcpy(*x, src->data, len2);
345         }
346         silc_buffer_pull(src, len2);
347         break;
348       }
349     case SILC_BUFFER_PARAM_UI32_STRING:
350       {
351         SilcUInt32 len2;
352         unsigned char **x = va_arg(ap, unsigned char **);
353         MY_HAS_SPACE(src, 4);
354         SILC_GET32_MSB(len2, src->data);
355         silc_buffer_pull(src, 4);
356         MY_HAS_SPACE(src, len2);
357         if (x)
358           *x = src->data;
359         silc_buffer_pull(src, len2);
360         break;
361       }
362     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
363       {
364         SilcUInt32 len2;
365         unsigned char **x = va_arg(ap, unsigned char **);
366         MY_HAS_SPACE(src, 4);
367         SILC_GET32_MSB(len2, src->data);
368         silc_buffer_pull(src, 4);
369         MY_HAS_SPACE(src, len2);
370         if (x && len2) {
371           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
372           memcpy(*x, src->data, len2);
373         }
374         silc_buffer_pull(src, len2);
375         break;
376       }
377     case SILC_BUFFER_PARAM_UI8_NSTRING:
378       {
379         SilcUInt8 len2;
380         unsigned char **x = va_arg(ap, unsigned char **);
381         SilcUInt8 *len = va_arg(ap, SilcUInt8 *);
382         MY_HAS_SPACE(src, 1);
383         len2 = (SilcUInt8)src->data[0];
384         silc_buffer_pull(src, 1);
385         MY_HAS_SPACE(src, len2);
386         if (len)
387           *len = len2;
388         if (x)
389           *x = src->data;
390         silc_buffer_pull(src, len2);
391         break;
392       }
393     case SILC_BUFFER_PARAM_UI16_NSTRING:
394       {
395         SilcUInt16 len2;
396         unsigned char **x = va_arg(ap, unsigned char **);
397         SilcUInt16 *len = va_arg(ap, SilcUInt16 *);
398         MY_HAS_SPACE(src, 2);
399         SILC_GET16_MSB(len2, src->data);
400         silc_buffer_pull(src, 2);
401         MY_HAS_SPACE(src, len2);
402         if (len)
403           *len = len2;
404         if (x)
405           *x = src->data;
406         silc_buffer_pull(src, len2);
407         break;
408       }
409     case SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC:
410       {
411         SilcUInt8 len2;
412         unsigned char **x = va_arg(ap, unsigned char **);
413         SilcUInt8 *len = va_arg(ap, SilcUInt8 *);
414         MY_HAS_SPACE(src, 1);
415         len2 = (SilcUInt8)src->data[0];
416         silc_buffer_pull(src, 1);
417         MY_HAS_SPACE(src, len2);
418         if (len)
419           *len = len2;
420         if (x && len2) {
421           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
422           memcpy(*x, src->data, len2);
423         }
424         silc_buffer_pull(src, len2);
425         break;
426       }
427     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
428       {
429         SilcUInt16 len2;
430         unsigned char **x = va_arg(ap, unsigned char **);
431         SilcUInt16 *len = va_arg(ap, SilcUInt16 *);
432         MY_HAS_SPACE(src, 2);
433         SILC_GET16_MSB(len2, src->data);
434         silc_buffer_pull(src, 2);
435         MY_HAS_SPACE(src, len2);
436         if (len)
437           *len = len2;
438         if (x && len2) {
439           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
440           memcpy(*x, src->data, len2);
441         }
442         silc_buffer_pull(src, len2);
443         break;
444       }
445     case SILC_BUFFER_PARAM_UI32_NSTRING:
446       {
447         SilcUInt32 len2;
448         unsigned char **x = va_arg(ap, unsigned char **);
449         SilcUInt32 *len = va_arg(ap, SilcUInt32 *);
450         MY_HAS_SPACE(src, 4);
451         SILC_GET32_MSB(len2, src->data);
452         silc_buffer_pull(src, 4);
453         MY_HAS_SPACE(src, len2);
454         if (len)
455           *len = len2;
456         if (x)
457           *x = src->data;
458         silc_buffer_pull(src, len2);
459         break;
460       }
461     case SILC_BUFFER_PARAM_UI_XNSTRING:
462       {
463         unsigned char **x = va_arg(ap, unsigned char **);
464         SilcUInt32 len = va_arg(ap, SilcUInt32);
465         MY_HAS_SPACE(src, len);
466         if (len && x)
467           *x = src->data;
468         silc_buffer_pull(src, len);
469         break;
470       }
471     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
472       {
473         unsigned char **x = va_arg(ap, unsigned char **);
474         SilcUInt32 len = va_arg(ap, SilcUInt32);
475         MY_HAS_SPACE(src, len);
476         if (len && x) {
477           *x = silc_calloc(len + 1, sizeof(unsigned char));
478           memcpy(*x, src->data, len);
479         }
480         silc_buffer_pull(src, len);
481         break;
482       }
483     case SILC_BUFFER_PARAM_END:
484       goto ok;
485       break;
486     default:
487       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
488                       "format the data.", fmt));
489       goto fail;
490       break;
491     }
492   }
493
494  fail:
495   SILC_LOG_DEBUG(("Error occured while unformatting buffer"));
496   len = src->data - start_ptr;
497   silc_buffer_push(src, len);
498   return -1;
499
500  ok:
501   /* Push the buffer back to the start. */
502   len = src->data - start_ptr;
503   silc_buffer_push(src, len);
504   return len;
505 }
506
507 /* Formats strings into a buffer */
508
509 int silc_buffer_strformat(SilcBuffer dst, ...)
510 {
511   int len = dst->truelen;
512   va_list va;
513
514   va_start(va, dst);
515
516   /* Parse the arguments by formatting type. */
517   while(1) {
518     char *string = va_arg(va, char *);
519
520     if (!string)
521       continue;
522     if (string == (char *)SILC_BUFFER_PARAM_END)
523       goto ok;
524
525     dst->head = silc_realloc(dst->head, sizeof(*dst->head) *
526                              (strlen(string) + len));
527     memcpy(dst->head + len, string, strlen(string));
528     len += strlen(string);
529   }
530
531   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
532   va_end(va);
533   return -1;
534
535  ok:
536   dst->end = dst->head + len;
537   dst->tail = dst->data = dst->end;
538   dst->len = 0;
539   dst->truelen = len;
540
541   va_end(va);
542   return len;
543 }