var renames.
[crypto.git] / lib / silcutil / silcbuffmt.c
1 /*
2
3   silcbuffmt.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2006 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22
23 /************************** Types and definitions ***************************/
24
25 /* Check that buffer has enough room to format data in it, if not
26    allocate more. */
27 #define FORMAT_HAS_SPACE(__s__, __x__, __req__)                             \
28 do {                                                                        \
29   if (__req__ > silc_buffer_len((__x__)))                                   \
30     if (!silc_buffer_srealloc_size((__s__), (__x__),                        \
31                                    silc_buffer_truelen((__x__)) + __req__)) \
32       goto fail;                                                            \
33   flen += __req__;                                                          \
34 } while(0)
35
36 /* Check that there is data to be unformatted */
37 #define UNFORMAT_HAS_SPACE(__x__, __req__)      \
38 do {                                            \
39   if (__req__ > silc_buffer_len((__x__)))       \
40     goto fail;                                  \
41   if ((__req__ + 1) <= 0)                       \
42     goto fail;                                  \
43 } while(0)
44
45
46 /******************************* Formatting *********************************/
47
48 int silc_buffer_format(SilcBuffer dst, ...)
49 {
50   va_list ap;
51   int ret;
52
53   va_start(ap, dst);
54   ret = silc_buffer_sformat_vp(NULL, dst, ap);
55   va_end(ap);
56
57   return ret;
58 }
59
60 int silc_buffer_format_vp(SilcBuffer dst, va_list ap)
61 {
62   return silc_buffer_sformat_vp(NULL, dst, ap);
63 }
64
65 int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...)
66 {
67   va_list ap;
68   int ret;
69
70   va_start(ap, dst);
71   ret = silc_buffer_sformat_vp(stack, dst, ap);
72   va_end(ap);
73
74   return ret;
75 }
76
77 int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap)
78 {
79   SilcBufferParamType fmt;
80   int flen = 0;
81
82   /* Parse the arguments by formatting type. */
83   while (1) {
84     fmt = va_arg(ap, SilcBufferParamType);
85
86     switch(fmt) {
87     case SILC_BUFFER_PARAM_OFFSET:
88       {
89         int offst = va_arg(ap, int);
90         if (!offst)
91           break;
92         if (offst > 1) {
93           if (offst > silc_buffer_len(dst))
94             goto fail;
95           silc_buffer_pull(dst, offst);
96           flen += offst;
97         } else {
98           silc_buffer_push(dst, -(offst));
99           flen += -(offst);
100         }
101         break;
102       }
103     case SILC_BUFFER_PARAM_SI8_CHAR:
104       {
105         char x = (char)va_arg(ap, int);
106         FORMAT_HAS_SPACE(stack, dst, 1);
107         silc_buffer_put(dst, &x, 1);
108         silc_buffer_pull(dst, 1);
109         break;
110       }
111     case SILC_BUFFER_PARAM_UI8_CHAR:
112       {
113         unsigned char x = (unsigned char)va_arg(ap, int);
114         FORMAT_HAS_SPACE(stack, dst, 1);
115         silc_buffer_put(dst, &x, 1);
116         silc_buffer_pull(dst, 1);
117         break;
118       }
119     case SILC_BUFFER_PARAM_SI16_SHORT:
120       {
121         unsigned char xf[2];
122         SilcInt16 x = (SilcInt16)va_arg(ap, int);
123         FORMAT_HAS_SPACE(stack, dst, 2);
124         SILC_PUT16_MSB(x, xf);
125         silc_buffer_put(dst, xf, 2);
126         silc_buffer_pull(dst, 2);
127         break;
128       }
129     case SILC_BUFFER_PARAM_UI16_SHORT:
130       {
131         unsigned char xf[2];
132         SilcUInt16 x = (SilcUInt16)va_arg(ap, int);
133         FORMAT_HAS_SPACE(stack, dst, 2);
134         SILC_PUT16_MSB(x, xf);
135         silc_buffer_put(dst, xf, 2);
136         silc_buffer_pull(dst, 2);
137         break;
138       }
139     case SILC_BUFFER_PARAM_SI32_INT:
140       {
141         unsigned char xf[4];
142         SilcInt32 x = va_arg(ap, SilcInt32);
143         FORMAT_HAS_SPACE(stack, dst, 4);
144         SILC_PUT32_MSB(x, xf);
145         silc_buffer_put(dst, xf, 4);
146         silc_buffer_pull(dst, 4);
147         break;
148       }
149     case SILC_BUFFER_PARAM_UI32_INT:
150       {
151         unsigned char xf[4];
152         SilcUInt32 x = va_arg(ap, SilcUInt32);
153         FORMAT_HAS_SPACE(stack, dst, 4);
154         SILC_PUT32_MSB(x, xf);
155         silc_buffer_put(dst, xf, 4);
156         silc_buffer_pull(dst, 4);
157         break;
158       }
159     case SILC_BUFFER_PARAM_SI64_INT:
160       {
161         unsigned char xf[8];
162         SilcInt64 x = va_arg(ap, SilcInt64);
163         FORMAT_HAS_SPACE(stack, dst, sizeof(SilcInt64));
164         SILC_PUT64_MSB(x, xf);
165         silc_buffer_put(dst, xf, sizeof(SilcInt64));
166         silc_buffer_pull(dst, sizeof(SilcInt64));
167         break;
168       }
169     case SILC_BUFFER_PARAM_UI64_INT:
170       {
171         unsigned char xf[8];
172         SilcUInt64 x = va_arg(ap, SilcUInt64);
173         FORMAT_HAS_SPACE(stack, dst, sizeof(SilcUInt64));
174         SILC_PUT64_MSB(x, xf);
175         silc_buffer_put(dst, xf, sizeof(SilcUInt64));
176         silc_buffer_pull(dst, sizeof(SilcUInt64));
177         break;
178       }
179     case SILC_BUFFER_PARAM_UI8_STRING:
180     case SILC_BUFFER_PARAM_UI16_STRING:
181     case SILC_BUFFER_PARAM_UI32_STRING:
182     case SILC_BUFFER_PARAM_UI8_STRING_ALLOC:
183     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
184     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
185       {
186         unsigned char *x = va_arg(ap, unsigned char *);
187         SilcUInt32 tmp_len = strlen(x);
188         FORMAT_HAS_SPACE(stack, dst, tmp_len);
189         silc_buffer_put(dst, x, tmp_len);
190         silc_buffer_pull(dst, tmp_len);
191         break;
192       }
193     case SILC_BUFFER_PARAM_UI8_NSTRING:
194     case SILC_BUFFER_PARAM_UI16_NSTRING:
195     case SILC_BUFFER_PARAM_UI32_NSTRING:
196     case SILC_BUFFER_PARAM_UI_XNSTRING:
197     case SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC:
198     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
199     case SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC:
200     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
201       {
202         unsigned char *x = va_arg(ap, unsigned char *);
203         SilcUInt32 tmp_len = va_arg(ap, SilcUInt32);
204         if (x && tmp_len) {
205           FORMAT_HAS_SPACE(stack, dst, tmp_len);
206           silc_buffer_put(dst, x, tmp_len);
207           silc_buffer_pull(dst, tmp_len);
208         }
209         break;
210       }
211     case SILC_BUFFER_PARAM_END:
212       goto ok;
213       break;
214     default:
215       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
216                       "format the data.", fmt));
217       goto fail;
218       break;
219     }
220   }
221
222  fail:
223   SILC_LOG_DEBUG(("Error occured while formatting data"));
224   silc_buffer_push(dst, flen);
225   return -1;
226
227  ok:
228   /* Push the buffer back to where it belongs. */
229   silc_buffer_push(dst, flen);
230   return flen;
231 }
232
233
234 /****************************** Unformatting ********************************/
235
236 int silc_buffer_unformat(SilcBuffer src, ...)
237 {
238   va_list ap;
239   int ret;
240
241   va_start(ap, src);
242   ret = silc_buffer_unformat_vp(src, ap);
243   va_end(ap);
244
245   return ret;
246 }
247
248 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
249 {
250   SilcBufferParamType fmt;
251   unsigned char *start_ptr = src->data;
252   int len = 0;
253
254   /* Parse the arguments by formatting type. */
255   while(1) {
256     fmt = va_arg(ap, SilcBufferParamType);
257
258     switch(fmt) {
259     case SILC_BUFFER_PARAM_OFFSET:
260       {
261         int offst = va_arg(ap, int);
262         if (!offst)
263           break;
264         if (offst > 1) {
265           UNFORMAT_HAS_SPACE(src, offst);
266           silc_buffer_pull(src, offst);
267         } else {
268           silc_buffer_push(src, -(offst));
269         }
270         break;
271       }
272     case SILC_BUFFER_PARAM_SI8_CHAR:
273       {
274         char *x = va_arg(ap, char *);
275         UNFORMAT_HAS_SPACE(src, 1);
276         if (x)
277           *x = src->data[0];
278         silc_buffer_pull(src, 1);
279         break;
280       }
281     case SILC_BUFFER_PARAM_UI8_CHAR:
282       {
283         unsigned char *x = va_arg(ap, unsigned char *);
284         UNFORMAT_HAS_SPACE(src, 1);
285         if (x)
286           *x = src->data[0];
287         silc_buffer_pull(src, 1);
288         break;
289       }
290     case SILC_BUFFER_PARAM_SI16_SHORT:
291       {
292         SilcInt16 *x = va_arg(ap, SilcInt16 *);
293         UNFORMAT_HAS_SPACE(src, 2);
294         if (x)
295           SILC_GET16_MSB(*x, src->data);
296         silc_buffer_pull(src, 2);
297         break;
298       }
299     case SILC_BUFFER_PARAM_UI16_SHORT:
300       {
301         SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
302         UNFORMAT_HAS_SPACE(src, 2);
303         if (x)
304           SILC_GET16_MSB(*x, src->data);
305         silc_buffer_pull(src, 2);
306         break;
307       }
308     case SILC_BUFFER_PARAM_SI32_INT:
309       {
310         SilcInt32 *x = va_arg(ap, SilcInt32 *);
311         UNFORMAT_HAS_SPACE(src, 4);
312         if (x)
313           SILC_GET32_MSB(*x, src->data);
314         silc_buffer_pull(src, 4);
315         break;
316       }
317     case SILC_BUFFER_PARAM_UI32_INT:
318       {
319         SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
320         UNFORMAT_HAS_SPACE(src, 4);
321         if (x)
322           SILC_GET32_MSB(*x, src->data);
323         silc_buffer_pull(src, 4);
324         break;
325       }
326     case SILC_BUFFER_PARAM_SI64_INT:
327       {
328         SilcInt64 *x = va_arg(ap, SilcInt64 *);
329         UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
330         if (x)
331           SILC_GET64_MSB(*x, src->data);
332         silc_buffer_pull(src, sizeof(SilcInt64));
333         break;
334       }
335     case SILC_BUFFER_PARAM_UI64_INT:
336       {
337         SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
338         UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
339         if (x)
340           SILC_GET64_MSB(*x, src->data);
341         silc_buffer_pull(src, sizeof(SilcUInt64));
342         break;
343       }
344     case SILC_BUFFER_PARAM_UI8_STRING:
345       {
346         SilcUInt8 len2;
347         unsigned char **x = va_arg(ap, unsigned char **);
348         UNFORMAT_HAS_SPACE(src, 1);
349         len2 = (SilcUInt8)src->data[0];
350         silc_buffer_pull(src, 1);
351         UNFORMAT_HAS_SPACE(src, len2);
352         if (x)
353           *x = src->data;
354         silc_buffer_pull(src, len2);
355         break;
356       }
357     case SILC_BUFFER_PARAM_UI16_STRING:
358       {
359         SilcUInt16 len2;
360         unsigned char **x = va_arg(ap, unsigned char **);
361         UNFORMAT_HAS_SPACE(src, 2);
362         SILC_GET16_MSB(len2, src->data);
363         silc_buffer_pull(src, 2);
364         UNFORMAT_HAS_SPACE(src, len2);
365         if (x)
366           *x = src->data;
367         silc_buffer_pull(src, len2);
368         break;
369       }
370     case SILC_BUFFER_PARAM_UI8_STRING_ALLOC:
371       {
372         SilcUInt8 len2;
373         unsigned char **x = va_arg(ap, unsigned char **);
374         UNFORMAT_HAS_SPACE(src, 1);
375         len2 = (SilcUInt8)src->data[0];
376         silc_buffer_pull(src, 1);
377         UNFORMAT_HAS_SPACE(src, len2);
378         if (x && len2) {
379           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
380           memcpy(*x, src->data, len2);
381         }
382         silc_buffer_pull(src, len2);
383         break;
384       }
385     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
386       {
387         SilcUInt16 len2;
388         unsigned char **x = va_arg(ap, unsigned char **);
389         UNFORMAT_HAS_SPACE(src, 2);
390         SILC_GET16_MSB(len2, src->data);
391         silc_buffer_pull(src, 2);
392         UNFORMAT_HAS_SPACE(src, len2);
393         if (x && len2) {
394           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
395           memcpy(*x, src->data, len2);
396         }
397         silc_buffer_pull(src, len2);
398         break;
399       }
400     case SILC_BUFFER_PARAM_UI32_STRING:
401       {
402         SilcUInt32 len2;
403         unsigned char **x = va_arg(ap, unsigned char **);
404         UNFORMAT_HAS_SPACE(src, 4);
405         SILC_GET32_MSB(len2, src->data);
406         silc_buffer_pull(src, 4);
407         UNFORMAT_HAS_SPACE(src, len2);
408         if (x)
409           *x = src->data;
410         silc_buffer_pull(src, len2);
411         break;
412       }
413     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
414       {
415         SilcUInt32 len2;
416         unsigned char **x = va_arg(ap, unsigned char **);
417         UNFORMAT_HAS_SPACE(src, 4);
418         SILC_GET32_MSB(len2, src->data);
419         silc_buffer_pull(src, 4);
420         UNFORMAT_HAS_SPACE(src, len2);
421         if (x && len2) {
422           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
423           memcpy(*x, src->data, len2);
424         }
425         silc_buffer_pull(src, len2);
426         break;
427       }
428     case SILC_BUFFER_PARAM_UI8_NSTRING:
429       {
430         SilcUInt8 len2;
431         unsigned char **x = va_arg(ap, unsigned char **);
432         SilcUInt8 *len = va_arg(ap, SilcUInt8 *);
433         UNFORMAT_HAS_SPACE(src, 1);
434         len2 = (SilcUInt8)src->data[0];
435         silc_buffer_pull(src, 1);
436         UNFORMAT_HAS_SPACE(src, len2);
437         if (len)
438           *len = len2;
439         if (x)
440           *x = src->data;
441         silc_buffer_pull(src, len2);
442         break;
443       }
444     case SILC_BUFFER_PARAM_UI16_NSTRING:
445       {
446         SilcUInt16 len2;
447         unsigned char **x = va_arg(ap, unsigned char **);
448         SilcUInt16 *len = va_arg(ap, SilcUInt16 *);
449         UNFORMAT_HAS_SPACE(src, 2);
450         SILC_GET16_MSB(len2, src->data);
451         silc_buffer_pull(src, 2);
452         UNFORMAT_HAS_SPACE(src, len2);
453         if (len)
454           *len = len2;
455         if (x)
456           *x = src->data;
457         silc_buffer_pull(src, len2);
458         break;
459       }
460     case SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC:
461       {
462         SilcUInt8 len2;
463         unsigned char **x = va_arg(ap, unsigned char **);
464         SilcUInt8 *len = va_arg(ap, SilcUInt8 *);
465         UNFORMAT_HAS_SPACE(src, 1);
466         len2 = (SilcUInt8)src->data[0];
467         silc_buffer_pull(src, 1);
468         UNFORMAT_HAS_SPACE(src, len2);
469         if (len)
470           *len = len2;
471         if (x && len2) {
472           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
473           memcpy(*x, src->data, len2);
474         }
475         silc_buffer_pull(src, len2);
476         break;
477       }
478     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
479       {
480         SilcUInt16 len2;
481         unsigned char **x = va_arg(ap, unsigned char **);
482         SilcUInt16 *len = va_arg(ap, SilcUInt16 *);
483         UNFORMAT_HAS_SPACE(src, 2);
484         SILC_GET16_MSB(len2, src->data);
485         silc_buffer_pull(src, 2);
486         UNFORMAT_HAS_SPACE(src, len2);
487         if (len)
488           *len = len2;
489         if (x && len2) {
490           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
491           memcpy(*x, src->data, len2);
492         }
493         silc_buffer_pull(src, len2);
494         break;
495       }
496     case SILC_BUFFER_PARAM_UI32_NSTRING:
497       {
498         SilcUInt32 len2;
499         unsigned char **x = va_arg(ap, unsigned char **);
500         SilcUInt32 *len = va_arg(ap, SilcUInt32 *);
501         UNFORMAT_HAS_SPACE(src, 4);
502         SILC_GET32_MSB(len2, src->data);
503         silc_buffer_pull(src, 4);
504         UNFORMAT_HAS_SPACE(src, len2);
505         if (len)
506           *len = len2;
507         if (x)
508           *x = src->data;
509         silc_buffer_pull(src, len2);
510         break;
511       }
512     case SILC_BUFFER_PARAM_UI_XNSTRING:
513       {
514         unsigned char **x = va_arg(ap, unsigned char **);
515         SilcUInt32 len = va_arg(ap, SilcUInt32);
516         UNFORMAT_HAS_SPACE(src, len);
517         if (len && x)
518           *x = src->data;
519         silc_buffer_pull(src, len);
520         break;
521       }
522     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
523       {
524         unsigned char **x = va_arg(ap, unsigned char **);
525         SilcUInt32 len = va_arg(ap, SilcUInt32);
526         UNFORMAT_HAS_SPACE(src, len);
527         if (len && x) {
528           *x = silc_calloc(len + 1, sizeof(unsigned char));
529           memcpy(*x, src->data, len);
530         }
531         silc_buffer_pull(src, len);
532         break;
533       }
534     case SILC_BUFFER_PARAM_END:
535       goto ok;
536       break;
537     default:
538       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
539                       "format the data.", fmt));
540       goto fail;
541       break;
542     }
543   }
544
545  fail:
546   SILC_LOG_DEBUG(("Error occured while unformatting buffer"));
547   len = src->data - start_ptr;
548   silc_buffer_push(src, len);
549   return -1;
550
551  ok:
552   /* Push the buffer back to the start. */
553   len = src->data - start_ptr;
554   silc_buffer_push(src, len);
555   return len;
556 }
557
558
559 /**************************** Utility functions *****************************/
560
561 /* Formats strings into a buffer */
562
563 int silc_buffer_strformat(SilcBuffer dst, ...)
564 {
565   int len = silc_buffer_truelen(dst);
566   va_list va;
567
568   va_start(va, dst);
569
570   /* Parse the arguments by formatting type. */
571   while(1) {
572     char *string = va_arg(va, char *);
573     unsigned char *d;
574     SilcInt32 slen;
575
576     if (!string)
577       continue;
578     if (string == (char *)SILC_BUFFER_PARAM_END)
579       goto ok;
580
581     slen = strlen(string);
582     d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
583     if (!d)
584       return -1;
585     dst->head = d;
586     memcpy(dst->head + len, string, slen);
587     len += slen;
588     dst->head[len] = '\0';
589   }
590
591   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
592   va_end(va);
593   return -1;
594
595  ok:
596   dst->end = dst->head + len;
597   dst->data = dst->head;
598   dst->tail = dst->end;
599
600   va_end(va);
601   return len;
602 }
603
604 /* Formats strings into a buffer.  Allocates memory from SilcStack. */
605
606 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
607 {
608   int len = silc_buffer_truelen(dst);
609   va_list va;
610
611   va_start(va, dst);
612
613   /* Parse the arguments by formatting type. */
614   while(1) {
615     char *string = va_arg(va, char *);
616     unsigned char *d;
617     SilcInt32 slen;
618
619     if (!string)
620       continue;
621     if (string == (char *)SILC_BUFFER_PARAM_END)
622       goto ok;
623
624     slen = strlen(string);
625     d = silc_srealloc_ua(stack, len + 1, dst->head,
626                          sizeof(*dst->head) * (slen + len + 1));
627     if (!d)
628       return -1;
629     dst->head = d;
630     memcpy(dst->head + len, string, slen);
631     len += slen;
632     dst->head[len] = '\0';
633   }
634
635   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
636   va_end(va);
637   return -1;
638
639  ok:
640   dst->end = dst->head + len;
641   dst->data = dst->head;
642   dst->tail = dst->end;
643
644   va_end(va);
645   return len;
646 }