af317cfbd7fa0699ad7663d7db766216b4bd5158
[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         int16 x = (int16)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         uint16 x = (uint16)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         int32 x = va_arg(ap, int32);
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         uint32 x = va_arg(ap, uint32);
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         uint32 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         uint32 len = va_arg(ap, uint32);
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   return -1;
149
150  ok:
151   /* Push the buffer back to where it belongs. */
152   silc_buffer_push(dst, dst->data - start_ptr);
153   return dst->len;
154 }
155
156 /* Unformats the buffer sent as argument. The unformatted data is returned
157    to the variable argument list of pointers. The buffer must point to the
158    start of the data area to be unformatted. Buffer maybe be safely free'd
159    after this returns succesfully. */
160
161 int silc_buffer_unformat(SilcBuffer src, ...)
162 {
163   va_list ap;
164   SilcBufferParamType fmt;
165   unsigned char *start_ptr = src->data;
166   int len = 0;
167
168   va_start(ap, src);
169
170   /* Parse the arguments by formatting type. */
171   while(1) {
172     fmt = va_arg(ap, SilcBufferParamType);
173
174     switch(fmt) {
175     case SILC_BUFFER_PARAM_SI8_CHAR:
176       {
177         char *x = va_arg(ap, char *);
178         HAS_SPACE(src, 1);
179         if (x)
180           *x = src->data[0];
181         silc_buffer_pull(src, 1);
182         break;
183       }
184     case SILC_BUFFER_PARAM_UI8_CHAR:
185       {
186         unsigned char *x = va_arg(ap, unsigned char *);
187         HAS_SPACE(src, 1);
188         if (x)
189           *x = src->data[0];
190         silc_buffer_pull(src, 1);
191         break;
192       }
193     case SILC_BUFFER_PARAM_SI16_SHORT:
194       {
195         int16 *x = va_arg(ap, int16 *);
196         HAS_SPACE(src, 2);
197         if (x)
198           SILC_GET16_MSB(*x, src->data);
199         silc_buffer_pull(src, 2);
200         break;
201       }
202     case SILC_BUFFER_PARAM_UI16_SHORT:
203       {
204         uint16 *x = va_arg(ap, uint16 *);
205         HAS_SPACE(src, 2);
206         if (x)
207           SILC_GET16_MSB(*x, src->data);
208         silc_buffer_pull(src, 2);
209         break;
210       }
211     case SILC_BUFFER_PARAM_SI32_INT:
212       {
213         int32 *x = va_arg(ap, int32 *);
214         HAS_SPACE(src, 4);
215         if (x)
216           SILC_GET32_MSB(*x, src->data);
217         silc_buffer_pull(src, 4);
218         break;
219       }
220     case SILC_BUFFER_PARAM_UI32_INT:
221       {
222         uint32 *x = va_arg(ap, uint32 *);
223         HAS_SPACE(src, 4);
224         if (x)
225           SILC_GET32_MSB(*x, src->data);
226         silc_buffer_pull(src, 4);
227         break;
228       }
229     case SILC_BUFFER_PARAM_UI16_STRING:
230       {
231         uint16 len2;
232         unsigned char **x = va_arg(ap, unsigned char **);
233         HAS_SPACE(src, 2);
234         SILC_GET16_MSB(len2, src->data);
235         silc_buffer_pull(src, 2);
236         HAS_SPACE(src, len2);
237         if (x)
238           *x = src->data;
239         silc_buffer_pull(src, len2);
240         break;
241       }
242     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
243       {
244         uint16 len2;
245         unsigned char **x = va_arg(ap, unsigned char **);
246         HAS_SPACE(src, 2);
247         SILC_GET16_MSB(len2, src->data);
248         silc_buffer_pull(src, 2);
249         HAS_SPACE(src, len2);
250         if (x && len2) {
251           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
252           memcpy(*x, src->data, len2);
253         }
254         silc_buffer_pull(src, len2);
255         break;
256       }
257     case SILC_BUFFER_PARAM_UI32_STRING:
258       {
259         uint32 len2;
260         unsigned char **x = va_arg(ap, unsigned char **);
261         HAS_SPACE(src, 4);
262         SILC_GET32_MSB(len2, src->data);
263         silc_buffer_pull(src, 4);
264         HAS_SPACE(src, len2);
265         if (x)
266           *x = src->data;
267         silc_buffer_pull(src, len2);
268         break;
269       }
270     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
271       {
272         uint32 len2;
273         unsigned char **x = va_arg(ap, unsigned char **);
274         HAS_SPACE(src, 4);
275         SILC_GET32_MSB(len2, src->data);
276         silc_buffer_pull(src, 4);
277         HAS_SPACE(src, len2);
278         if (x && len2) {
279           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
280           memcpy(*x, src->data, len2);
281         }
282         silc_buffer_pull(src, len2);
283         break;
284       }
285     case SILC_BUFFER_PARAM_UI16_NSTRING:
286       {
287         uint16 len2;
288         unsigned char **x = va_arg(ap, unsigned char **);
289         uint16 *len = va_arg(ap, unsigned short *);
290         HAS_SPACE(src, 2);
291         SILC_GET16_MSB(len2, src->data);
292         silc_buffer_pull(src, 2);
293         HAS_SPACE(src, len2);
294         if (len)
295           *len = len2;
296         if (x)
297           *x = src->data;
298         silc_buffer_pull(src, len2);
299         break;
300       }
301     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
302       {
303         uint16 len2;
304         unsigned char **x = va_arg(ap, unsigned char **);
305         uint16 *len = va_arg(ap, uint16 *);
306         HAS_SPACE(src, 2);
307         SILC_GET16_MSB(len2, src->data);
308         silc_buffer_pull(src, 2);
309         HAS_SPACE(src, len2);
310         if (len)
311           *len = len2;
312         if (x && len2) {
313           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
314           memcpy(*x, src->data, len2);
315         }
316         silc_buffer_pull(src, len2);
317         break;
318       }
319     case SILC_BUFFER_PARAM_UI32_NSTRING:
320       {
321         uint32 len2;
322         unsigned char **x = va_arg(ap, unsigned char **);
323         uint32 *len = va_arg(ap, uint32 *);
324         HAS_SPACE(src, 4);
325         SILC_GET32_MSB(len2, src->data);
326         silc_buffer_pull(src, 4);
327         HAS_SPACE(src, len2);
328         if (len)
329           *len = len2;
330         if (x)
331           *x = src->data;
332         silc_buffer_pull(src, len2);
333         break;
334       }
335     case SILC_BUFFER_PARAM_UI_XNSTRING:
336       {
337         unsigned char **x = va_arg(ap, unsigned char **);
338         uint32 len = va_arg(ap, uint32);
339         HAS_SPACE(src, len);
340         if (len && x)
341           *x = src->data;
342         silc_buffer_pull(src, len);
343         break;
344       }
345     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
346       {
347         unsigned char **x = va_arg(ap, unsigned char **);
348         uint32 len = va_arg(ap, uint32);
349         HAS_SPACE(src, len);
350         if (len && x) {
351           *x = silc_calloc(len + 1, sizeof(unsigned char));
352           memcpy(*x, src->data, len);
353         }
354         silc_buffer_pull(src, len);
355         break;
356       }
357     case SILC_BUFFER_PARAM_END:
358       goto ok;
359       break;
360     default:
361       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
362                       "format the data.", fmt));
363       goto fail;
364       break;
365     }
366   }
367
368  fail:
369   SILC_LOG_DEBUG(("Error occured while unformatting buffer"));
370   return -1;
371
372  ok:
373   /* Push the buffer back to the start. */
374   len = src->data - start_ptr;
375   silc_buffer_push(src, len);
376   return len;
377 }