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   SilcBufferParamType fmt;
44   unsigned char *start_ptr = dst->data;
45
46   va_start(ap, dst);
47
48   /* Parse the arguments by formatting type. */
49   while(1) {
50     fmt = va_arg(ap, SilcBufferParamType);
51
52     switch(fmt) {
53     case SILC_BUFFER_PARAM_SI8_CHAR:
54       {
55         char x = (char)va_arg(ap, int);
56         HAS_SPACE(dst, 1);
57         silc_buffer_put(dst, &x, 1);
58         silc_buffer_pull(dst, 1);
59         break;
60       }
61     case SILC_BUFFER_PARAM_UI8_CHAR:
62       {
63         unsigned char x = (unsigned char)va_arg(ap, int);
64         HAS_SPACE(dst, 1);
65         silc_buffer_put(dst, &x, 1);
66         silc_buffer_pull(dst, 1);
67         break;
68       }
69     case SILC_BUFFER_PARAM_SI16_SHORT:
70       {
71         unsigned char xf[2];
72         short x = (short)va_arg(ap, int);
73         HAS_SPACE(dst, 2);
74         SILC_PUT16_MSB(x, xf);
75         silc_buffer_put(dst, xf, 2);
76         silc_buffer_pull(dst, 2);
77         break;
78       }
79     case SILC_BUFFER_PARAM_UI16_SHORT:
80       {
81         unsigned char xf[2];
82         unsigned short x = (unsigned short)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_SI32_INT:
90       {
91         unsigned char xf[4];
92         int x = va_arg(ap, int);
93         HAS_SPACE(dst, 4);
94         SILC_PUT32_MSB(x, xf);
95         silc_buffer_put(dst, xf, 4);
96         silc_buffer_pull(dst, 4);
97         break;
98       }
99     case SILC_BUFFER_PARAM_UI32_INT:
100       {
101         unsigned char xf[4];
102         unsigned int x = va_arg(ap, unsigned int);
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_UI16_STRING:
110     case SILC_BUFFER_PARAM_UI32_STRING:
111     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
112     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
113       {
114         unsigned char *x = va_arg(ap, unsigned char *);
115         int tmp_len = strlen(x);
116         HAS_SPACE(dst, tmp_len);
117         silc_buffer_put(dst, x, tmp_len);
118         silc_buffer_pull(dst, tmp_len);
119         break;
120       }
121     case SILC_BUFFER_PARAM_UI16_NSTRING:
122     case SILC_BUFFER_PARAM_UI32_NSTRING:
123     case SILC_BUFFER_PARAM_UI_XNSTRING:
124     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
125     case SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC:
126     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
127       {
128         unsigned char *x = va_arg(ap, unsigned char *);
129         unsigned int len = va_arg(ap, unsigned int);
130         HAS_SPACE(dst, len);
131         silc_buffer_put(dst, x, len);
132         silc_buffer_pull(dst, len);
133         break;
134       }
135     case SILC_BUFFER_PARAM_END:
136       goto ok;
137       break;
138     default:
139       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
140                       "format the data.", fmt));
141       goto fail;
142       break;
143     }
144   }
145
146  fail:
147   SILC_LOG_DEBUG(("Error occured while formatting data"));
148 #ifdef SILC_DEBUG
149   assert(FALSE);
150 #endif
151   return -1;
152
153  ok:
154   /* Push the buffer back to where it belongs. */
155   silc_buffer_push(dst, dst->data - start_ptr);
156   return dst->len;
157 }
158
159 /* Unformats the buffer sent as argument. The unformatted data is returned
160    to the variable argument list of pointers. The buffer must point to the
161    start of the data area to be unformatted. Buffer maybe be safely free'd
162    after this returns succesfully. */
163
164 int silc_buffer_unformat(SilcBuffer src, ...)
165 {
166   va_list ap;
167   SilcBufferParamType fmt;
168   unsigned char *start_ptr = src->data;
169   int len = 0;
170
171   va_start(ap, src);
172
173   /* Parse the arguments by formatting type. */
174   while(1) {
175     fmt = va_arg(ap, SilcBufferParamType);
176
177     switch(fmt) {
178     case SILC_BUFFER_PARAM_SI8_CHAR:
179       {
180         char *x = va_arg(ap, char *);
181         HAS_SPACE(src, 1);
182         if (x)
183           *x = src->data[0];
184         silc_buffer_pull(src, 1);
185         break;
186       }
187     case SILC_BUFFER_PARAM_UI8_CHAR:
188       {
189         unsigned char *x = va_arg(ap, unsigned char *);
190         HAS_SPACE(src, 1);
191         if (x)
192           *x = src->data[0];
193         silc_buffer_pull(src, 1);
194         break;
195       }
196     case SILC_BUFFER_PARAM_SI16_SHORT:
197       {
198         short *x = va_arg(ap, short *);
199         HAS_SPACE(src, 2);
200         if (x)
201           SILC_GET16_MSB(*x, src->data);
202         silc_buffer_pull(src, 2);
203         break;
204       }
205     case SILC_BUFFER_PARAM_UI16_SHORT:
206       {
207         unsigned short *x = va_arg(ap, unsigned short *);
208         HAS_SPACE(src, 2);
209         if (x)
210           SILC_GET16_MSB(*x, src->data);
211         silc_buffer_pull(src, 2);
212         break;
213       }
214     case SILC_BUFFER_PARAM_SI32_INT:
215       {
216         int *x = va_arg(ap, int *);
217         HAS_SPACE(src, 4);
218         if (x)
219           SILC_GET32_MSB(*x, src->data);
220         silc_buffer_pull(src, 4);
221         break;
222       }
223     case SILC_BUFFER_PARAM_UI32_INT:
224       {
225         unsigned int *x = va_arg(ap, unsigned int *);
226         HAS_SPACE(src, 4);
227         if (x)
228           SILC_GET32_MSB(*x, src->data);
229         silc_buffer_pull(src, 4);
230         break;
231       }
232     case SILC_BUFFER_PARAM_UI16_STRING:
233       {
234         unsigned short len2;
235         unsigned char **x = va_arg(ap, unsigned char **);
236         HAS_SPACE(src, 2);
237         SILC_GET16_MSB(len2, src->data);
238         silc_buffer_pull(src, 2);
239         HAS_SPACE(src, len2);
240         if (x)
241           *x = src->data;
242         silc_buffer_pull(src, len2);
243         break;
244       }
245     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
246       {
247         unsigned short len2;
248         unsigned char **x = va_arg(ap, unsigned char **);
249         HAS_SPACE(src, 2);
250         SILC_GET16_MSB(len2, src->data);
251         silc_buffer_pull(src, 2);
252         HAS_SPACE(src, len2);
253         if (x) {
254           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
255           memcpy(*x, src->data, len2);
256         }
257         silc_buffer_pull(src, len2);
258         break;
259       }
260     case SILC_BUFFER_PARAM_UI32_STRING:
261       {
262         unsigned int len2;
263         unsigned char **x = va_arg(ap, unsigned char **);
264         HAS_SPACE(src, 4);
265         SILC_GET32_MSB(len2, src->data);
266         silc_buffer_pull(src, 4);
267         HAS_SPACE(src, len2);
268         if (x)
269           *x = src->data;
270         silc_buffer_pull(src, len2);
271         break;
272       }
273     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
274       {
275         unsigned int len2;
276         unsigned char **x = va_arg(ap, unsigned char **);
277         HAS_SPACE(src, 4);
278         SILC_GET32_MSB(len2, src->data);
279         silc_buffer_pull(src, 4);
280         HAS_SPACE(src, len2);
281         if (x) {
282           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
283           memcpy(*x, src->data, len2);
284         }
285         silc_buffer_pull(src, len2);
286         break;
287       }
288     case SILC_BUFFER_PARAM_UI16_NSTRING:
289       {
290         unsigned short len2;
291         unsigned char **x = va_arg(ap, unsigned char **);
292         unsigned short *len = va_arg(ap, unsigned short *);
293         HAS_SPACE(src, 2);
294         SILC_GET16_MSB(len2, src->data);
295         silc_buffer_pull(src, 2);
296         HAS_SPACE(src, len2);
297         if (len)
298           *len = len2;
299         if (x)
300           *x = src->data;
301         silc_buffer_pull(src, len2);
302         break;
303       }
304     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
305       {
306         unsigned short len2;
307         unsigned char **x = va_arg(ap, unsigned char **);
308         unsigned short *len = va_arg(ap, unsigned short *);
309         HAS_SPACE(src, 2);
310         SILC_GET16_MSB(len2, src->data);
311         silc_buffer_pull(src, 2);
312         HAS_SPACE(src, len2);
313         if (len)
314           *len = len2;
315         if (x) {
316           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
317           memcpy(*x, src->data, len2);
318         }
319         silc_buffer_pull(src, len2);
320         break;
321       }
322     case SILC_BUFFER_PARAM_UI32_NSTRING:
323       {
324         unsigned int len2;
325         unsigned char **x = va_arg(ap, unsigned char **);
326         unsigned int *len = va_arg(ap, unsigned int *);
327         HAS_SPACE(src, 4);
328         SILC_GET32_MSB(len2, src->data);
329         silc_buffer_pull(src, 4);
330         HAS_SPACE(src, len2);
331         if (len)
332           *len = len2;
333         if (x)
334           *x = src->data;
335         silc_buffer_pull(src, len2);
336         break;
337       }
338     case SILC_BUFFER_PARAM_UI_XNSTRING:
339       {
340         unsigned char **x = va_arg(ap, unsigned char **);
341         unsigned int len = va_arg(ap, unsigned int);
342         HAS_SPACE(src, len);
343         if (len && x)
344           *x = src->data;
345         silc_buffer_pull(src, len);
346         break;
347       }
348     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
349       {
350         unsigned char **x = va_arg(ap, unsigned char **);
351         unsigned int len = va_arg(ap, unsigned int);
352         HAS_SPACE(src, len);
353         if (len && x) {
354           *x = silc_calloc(len + 1, sizeof(unsigned char));
355           memcpy(*x, src->data, len);
356         }
357         silc_buffer_pull(src, len);
358         break;
359       }
360     case SILC_BUFFER_PARAM_END:
361       goto ok;
362       break;
363     default:
364       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
365                       "format the data.", fmt));
366       goto fail;
367       break;
368     }
369   }
370
371  fail:
372   SILC_LOG_DEBUG(("Error occured while unformatting buffer"));
373 #ifdef SILC_DEBUG
374   assert(FALSE);
375 #endif
376   return -1;
377
378  ok:
379   /* Push the buffer back to the start. */
380   len = src->data - start_ptr;
381   silc_buffer_push(src, len);
382   return len;
383 }