updates.
[silc.git] / lib / silcutil / silcbuffmt.c
1 /*
2
3   silcbuffmt.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 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 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         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         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         int16 x = (int16)va_arg(ap, int);
83         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         uint16 x = (uint16)va_arg(ap, int);
93         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         int32 x = va_arg(ap, int32);
103         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         uint32 x = va_arg(ap, uint32);
113         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         int64 x = va_arg(ap, int64);
123         HAS_SPACE(dst, 8);
124         SILC_PUT64_MSB(x, xf);
125         silc_buffer_put(dst, xf, 8);
126         silc_buffer_pull(dst, 8);
127         break;
128       }
129     case SILC_BUFFER_PARAM_UI64_INT:
130       {
131         unsigned char xf[8];
132         uint64 x = va_arg(ap, uint64);
133         HAS_SPACE(dst, 8);
134         SILC_PUT64_MSB(x, xf);
135         silc_buffer_put(dst, xf, 8);
136         silc_buffer_pull(dst, 8);
137         break;
138       }
139     case SILC_BUFFER_PARAM_UI16_STRING:
140     case SILC_BUFFER_PARAM_UI32_STRING:
141     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
142     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
143       {
144         unsigned char *x = va_arg(ap, unsigned char *);
145         uint32 tmp_len = strlen(x);
146         HAS_SPACE(dst, tmp_len);
147         silc_buffer_put(dst, x, tmp_len);
148         silc_buffer_pull(dst, tmp_len);
149         break;
150       }
151     case SILC_BUFFER_PARAM_UI16_NSTRING:
152     case SILC_BUFFER_PARAM_UI32_NSTRING:
153     case SILC_BUFFER_PARAM_UI_XNSTRING:
154     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
155     case SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC:
156     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
157       {
158         unsigned char *x = va_arg(ap, unsigned char *);
159         uint32 len = va_arg(ap, uint32);
160         HAS_SPACE(dst, len);
161         silc_buffer_put(dst, x, len);
162         silc_buffer_pull(dst, len);
163         break;
164       }
165     case SILC_BUFFER_PARAM_END:
166       goto ok;
167       break;
168     default:
169       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
170                       "format the data.", fmt));
171       goto fail;
172       break;
173     }
174   }
175
176  fail:
177   SILC_LOG_DEBUG(("Error occured while formatting data"));
178   return -1;
179
180  ok:
181   /* Push the buffer back to where it belongs. */
182   len = dst->data - start_ptr;
183   silc_buffer_push(dst, len);
184   return len;
185 }
186
187 /* Unformats the buffer sent as argument. The unformatted data is returned
188    to the variable argument list of pointers. The buffer must point to the
189    start of the data area to be unformatted. Buffer maybe be safely free'd
190    after this returns succesfully. */
191
192 int silc_buffer_unformat(SilcBuffer src, ...)
193 {
194   va_list ap;
195   int ret;
196
197   va_start(ap, src);
198   ret = silc_buffer_unformat_vp(src, ap);
199   va_end(ap);
200   
201   return ret;
202 }
203
204 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
205 {
206   SilcBufferParamType fmt;
207   unsigned char *start_ptr = src->data;
208   int len = 0;
209
210   /* Parse the arguments by formatting type. */
211   while(1) {
212     fmt = va_arg(ap, SilcBufferParamType);
213
214     switch(fmt) {
215     case SILC_BUFFER_PARAM_SI8_CHAR:
216       {
217         char *x = va_arg(ap, char *);
218         HAS_SPACE(src, 1);
219         if (x)
220           *x = src->data[0];
221         silc_buffer_pull(src, 1);
222         break;
223       }
224     case SILC_BUFFER_PARAM_UI8_CHAR:
225       {
226         unsigned char *x = va_arg(ap, unsigned char *);
227         HAS_SPACE(src, 1);
228         if (x)
229           *x = src->data[0];
230         silc_buffer_pull(src, 1);
231         break;
232       }
233     case SILC_BUFFER_PARAM_SI16_SHORT:
234       {
235         int16 *x = va_arg(ap, int16 *);
236         HAS_SPACE(src, 2);
237         if (x)
238           SILC_GET16_MSB(*x, src->data);
239         silc_buffer_pull(src, 2);
240         break;
241       }
242     case SILC_BUFFER_PARAM_UI16_SHORT:
243       {
244         uint16 *x = va_arg(ap, uint16 *);
245         HAS_SPACE(src, 2);
246         if (x)
247           SILC_GET16_MSB(*x, src->data);
248         silc_buffer_pull(src, 2);
249         break;
250       }
251     case SILC_BUFFER_PARAM_SI32_INT:
252       {
253         int32 *x = va_arg(ap, int32 *);
254         HAS_SPACE(src, 4);
255         if (x)
256           SILC_GET32_MSB(*x, src->data);
257         silc_buffer_pull(src, 4);
258         break;
259       }
260     case SILC_BUFFER_PARAM_UI32_INT:
261       {
262         uint32 *x = va_arg(ap, uint32 *);
263         HAS_SPACE(src, 4);
264         if (x)
265           SILC_GET32_MSB(*x, src->data);
266         silc_buffer_pull(src, 4);
267         break;
268       }
269     case SILC_BUFFER_PARAM_SI64_INT:
270       {
271         int64 *x = va_arg(ap, int64 *);
272         HAS_SPACE(src, 8);
273         if (x)
274           SILC_GET64_MSB(*x, src->data);
275         silc_buffer_pull(src, 8);
276         break;
277       }
278     case SILC_BUFFER_PARAM_UI64_INT:
279       {
280         uint64 *x = va_arg(ap, uint64 *);
281         HAS_SPACE(src, 8);
282         if (x)
283           SILC_GET64_MSB(*x, src->data);
284         silc_buffer_pull(src, 8);
285         break;
286       }
287     case SILC_BUFFER_PARAM_UI16_STRING:
288       {
289         uint16 len2;
290         unsigned char **x = va_arg(ap, unsigned char **);
291         HAS_SPACE(src, 2);
292         SILC_GET16_MSB(len2, src->data);
293         silc_buffer_pull(src, 2);
294         HAS_SPACE(src, len2);
295         if (x)
296           *x = src->data;
297         silc_buffer_pull(src, len2);
298         break;
299       }
300     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
301       {
302         uint16 len2;
303         unsigned char **x = va_arg(ap, unsigned char **);
304         HAS_SPACE(src, 2);
305         SILC_GET16_MSB(len2, src->data);
306         silc_buffer_pull(src, 2);
307         HAS_SPACE(src, len2);
308         if (x && len2) {
309           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
310           memcpy(*x, src->data, len2);
311         }
312         silc_buffer_pull(src, len2);
313         break;
314       }
315     case SILC_BUFFER_PARAM_UI32_STRING:
316       {
317         uint32 len2;
318         unsigned char **x = va_arg(ap, unsigned char **);
319         HAS_SPACE(src, 4);
320         SILC_GET32_MSB(len2, src->data);
321         silc_buffer_pull(src, 4);
322         HAS_SPACE(src, len2);
323         if (x)
324           *x = src->data;
325         silc_buffer_pull(src, len2);
326         break;
327       }
328     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
329       {
330         uint32 len2;
331         unsigned char **x = va_arg(ap, unsigned char **);
332         HAS_SPACE(src, 4);
333         SILC_GET32_MSB(len2, src->data);
334         silc_buffer_pull(src, 4);
335         HAS_SPACE(src, len2);
336         if (x && len2) {
337           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
338           memcpy(*x, src->data, len2);
339         }
340         silc_buffer_pull(src, len2);
341         break;
342       }
343     case SILC_BUFFER_PARAM_UI16_NSTRING:
344       {
345         uint16 len2;
346         unsigned char **x = va_arg(ap, unsigned char **);
347         uint16 *len = va_arg(ap, unsigned short *);
348         HAS_SPACE(src, 2);
349         SILC_GET16_MSB(len2, src->data);
350         silc_buffer_pull(src, 2);
351         HAS_SPACE(src, len2);
352         if (len)
353           *len = len2;
354         if (x)
355           *x = src->data;
356         silc_buffer_pull(src, len2);
357         break;
358       }
359     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
360       {
361         uint16 len2;
362         unsigned char **x = va_arg(ap, unsigned char **);
363         uint16 *len = va_arg(ap, uint16 *);
364         HAS_SPACE(src, 2);
365         SILC_GET16_MSB(len2, src->data);
366         silc_buffer_pull(src, 2);
367         HAS_SPACE(src, len2);
368         if (len)
369           *len = 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_UI32_NSTRING:
378       {
379         uint32 len2;
380         unsigned char **x = va_arg(ap, unsigned char **);
381         uint32 *len = va_arg(ap, uint32 *);
382         HAS_SPACE(src, 4);
383         SILC_GET32_MSB(len2, src->data);
384         silc_buffer_pull(src, 4);
385         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_UI_XNSTRING:
394       {
395         unsigned char **x = va_arg(ap, unsigned char **);
396         uint32 len = va_arg(ap, uint32);
397         HAS_SPACE(src, len);
398         if (len && x)
399           *x = src->data;
400         silc_buffer_pull(src, len);
401         break;
402       }
403     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
404       {
405         unsigned char **x = va_arg(ap, unsigned char **);
406         uint32 len = va_arg(ap, uint32);
407         HAS_SPACE(src, len);
408         if (len && x) {
409           *x = silc_calloc(len + 1, sizeof(unsigned char));
410           memcpy(*x, src->data, len);
411         }
412         silc_buffer_pull(src, len);
413         break;
414       }
415     case SILC_BUFFER_PARAM_END:
416       goto ok;
417       break;
418     default:
419       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
420                       "format the data.", fmt));
421       goto fail;
422       break;
423     }
424   }
425
426  fail:
427   SILC_LOG_DEBUG(("Error occured while unformatting buffer"));
428   return -1;
429
430  ok:
431   /* Push the buffer back to the start. */
432   len = src->data - start_ptr;
433   silc_buffer_push(src, len);
434   return len;
435 }