A LOT updates. Cannot separate. :)
[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 /* XXX: These routines needs to be made more stable as these can crash
21    if the data (for unformatting for example) is malformed or the buffer
22    is too short. Must be fixed. There are some other obvious bugs as
23    well. */
24 /*
25  * $Id$ */
26
27 #include "silcincludes.h"
28
29 /* Formats the arguments sent and puts them into the buffer sent as
30    argument. The buffer must be initialized beforehand and it must have
31    enough free space to include the formatted data. If this function
32    fails caller should not trust the buffer anymore and should free it. 
33    This function is used, for example, to create packets to send over
34    network. */
35
36 int silc_buffer_format(SilcBuffer dst, ...)
37 {
38   va_list ap;
39   SilcBufferParamType fmt;
40   unsigned char *start_ptr = dst->data;
41
42   va_start(ap, dst);
43
44   /* Parse the arguments by formatting type. */
45   while(1) {
46     fmt = va_arg(ap, SilcBufferParamType);
47
48     switch(fmt) {
49     case SILC_BUFFER_PARAM_SI8_CHAR:
50       {
51         char x = (char)va_arg(ap, int);
52         silc_buffer_put(dst, &x, 1);
53         silc_buffer_pull(dst, 1);
54         break;
55       }
56     case SILC_BUFFER_PARAM_UI8_CHAR:
57       {
58         unsigned char x = (unsigned char)va_arg(ap, int);
59         silc_buffer_put(dst, &x, 1);
60         silc_buffer_pull(dst, 1);
61         break;
62       }
63     case SILC_BUFFER_PARAM_SI16_SHORT:
64       {
65         unsigned char xf[2];
66         short x = (short)va_arg(ap, int);
67         SILC_PUT16_MSB(x, xf);
68         silc_buffer_put(dst, xf, 2);
69         silc_buffer_pull(dst, 2);
70         break;
71       }
72     case SILC_BUFFER_PARAM_UI16_SHORT:
73       {
74         unsigned char xf[2];
75         unsigned short x = (unsigned short)va_arg(ap, int);
76         SILC_PUT16_MSB(x, xf);
77         silc_buffer_put(dst, xf, 2);
78         silc_buffer_pull(dst, 2);
79         break;
80       }
81     case SILC_BUFFER_PARAM_SI32_INT:
82       {
83         unsigned char xf[4];
84         int x = va_arg(ap, int);
85         SILC_PUT32_MSB(x, xf);
86         silc_buffer_put(dst, xf, 4);
87         silc_buffer_pull(dst, 4);
88         break;
89       }
90     case SILC_BUFFER_PARAM_UI32_INT:
91       {
92         unsigned char xf[4];
93         unsigned int x = va_arg(ap, unsigned int);
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_UI16_STRING:
100     case SILC_BUFFER_PARAM_UI32_STRING:
101     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
102     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
103       {
104         unsigned char *x = va_arg(ap, unsigned char *);
105         silc_buffer_put(dst, x, strlen(x));
106         silc_buffer_pull(dst, strlen(x));
107         break;
108       }
109     case SILC_BUFFER_PARAM_UI16_NSTRING:
110     case SILC_BUFFER_PARAM_UI32_NSTRING:
111     case SILC_BUFFER_PARAM_UI_XNSTRING:
112     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
113     case SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC:
114     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
115       {
116         unsigned char *x = va_arg(ap, unsigned char *);
117         unsigned int len = va_arg(ap, unsigned int);
118         silc_buffer_put(dst, x, len);
119         silc_buffer_pull(dst, len);
120         break;
121       }
122     case SILC_BUFFER_PARAM_END:
123       goto ok;
124       break;
125     default:
126       SILC_LOG_ERROR(("Bad buffer formatting type `%d'. Could not "
127                       "format the data.", fmt));
128       goto fail;
129       break;
130     }
131   }
132
133  fail:
134   SILC_LOG_ERROR(("Error occured while formatting data"));
135   return FALSE;
136
137  ok:
138   /* Push the buffer back to where it belongs. */
139   silc_buffer_push(dst, dst->data - start_ptr);
140   return dst->len;
141 }
142
143 /* Unformats the buffer sent as argument. The unformatted data is returned
144    to the variable argument list of pointers. The buffer must point to the
145    start of the data area to be unformatted. Buffer maybe be safely free'd
146    after this returns succesfully. */
147
148 int silc_buffer_unformat(SilcBuffer src, ...)
149 {
150   va_list ap;
151   SilcBufferParamType fmt;
152   unsigned char *start_ptr = src->data;
153   int len = 0;
154
155   va_start(ap, src);
156
157   /* Parse the arguments by formatting type. */
158   while(1) {
159     fmt = va_arg(ap, SilcBufferParamType);
160
161     switch(fmt) {
162     case SILC_BUFFER_PARAM_SI8_CHAR:
163       {
164         char *x = va_arg(ap, char *);
165         if (x)
166           *x = src->data[0];
167         silc_buffer_pull(src, 1);
168         break;
169       }
170     case SILC_BUFFER_PARAM_UI8_CHAR:
171       {
172         unsigned char *x = va_arg(ap, unsigned char *);
173         if (x)
174           *x = src->data[0];
175         silc_buffer_pull(src, 1);
176         break;
177       }
178     case SILC_BUFFER_PARAM_SI16_SHORT:
179       {
180         short *x = va_arg(ap, short *);
181         if (x)
182           SILC_GET16_MSB(*x, src->data);
183         silc_buffer_pull(src, 2);
184         break;
185       }
186     case SILC_BUFFER_PARAM_UI16_SHORT:
187       {
188         unsigned short *x = va_arg(ap, unsigned short *);
189         if (x)
190           SILC_GET16_MSB(*x, src->data);
191         silc_buffer_pull(src, 2);
192         break;
193       }
194     case SILC_BUFFER_PARAM_SI32_INT:
195       {
196         int *x = va_arg(ap, int *);
197         if (x)
198           SILC_GET32_MSB(*x, src->data);
199         silc_buffer_pull(src, 4);
200         break;
201       }
202     case SILC_BUFFER_PARAM_UI32_INT:
203       {
204         unsigned int *x = va_arg(ap, unsigned int *);
205         if (x)
206           SILC_GET32_MSB(*x, src->data);
207         silc_buffer_pull(src, 4);
208         break;
209       }
210     case SILC_BUFFER_PARAM_UI16_STRING:
211       {
212         unsigned short len2;
213         unsigned char **x = va_arg(ap, unsigned char **);
214         SILC_GET16_MSB(len2, src->data);
215         silc_buffer_pull(src, 2);
216         if ((len2 > src->len))
217           goto fail;
218         if (len2 < 1)
219           break;
220         if (x)
221           memcpy(x, src->data, len2);
222         silc_buffer_pull(src, len2);
223         break;
224       }
225     case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
226       {
227         unsigned short len2;
228         unsigned char **x = va_arg(ap, unsigned char **);
229         SILC_GET16_MSB(len2, src->data);
230         silc_buffer_pull(src, 2);
231         if ((len2 > src->len))
232           goto fail;
233         if (len2 < 1)
234           break;
235         if (x) {
236           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
237           memcpy(*x, src->data, len2);
238         }
239         silc_buffer_pull(src, len2);
240         break;
241       }
242     case SILC_BUFFER_PARAM_UI32_STRING:
243       {
244         unsigned int len2;
245         unsigned char **x = va_arg(ap, unsigned char **);
246         SILC_GET32_MSB(len2, src->data);
247         silc_buffer_pull(src, 4);
248         if ((len2 > src->len))
249           goto fail;
250         if (len2 < 1)
251           break;
252         if (x)
253           memcpy(x, src->data, len2);
254         silc_buffer_pull(src, len2);
255         break;
256       }
257     case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
258       {
259         unsigned int len2;
260         unsigned char **x = va_arg(ap, unsigned char **);
261         SILC_GET32_MSB(len2, src->data);
262         silc_buffer_pull(src, 4);
263         if ((len2 > src->len))
264           goto fail;
265         if (len2 < 1)
266           break;
267         if (x) {
268           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
269           memcpy(*x, src->data, len2);
270         }
271         silc_buffer_pull(src, len2);
272         break;
273       }
274     case SILC_BUFFER_PARAM_UI16_NSTRING:
275       {
276         unsigned short len2;
277         unsigned char **x = va_arg(ap, unsigned char **);
278         unsigned short *len = va_arg(ap, unsigned short *);
279         SILC_GET16_MSB(len2, src->data);
280         silc_buffer_pull(src, 2);
281         if ((len2 > src->len))
282           break;
283         if (len2 < 1)
284           break;
285         if (len)
286           *len = len2;
287         if (x)
288           memcpy(x, src->data, len2);
289         silc_buffer_pull(src, len2);
290         break;
291       }
292     case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
293       {
294         unsigned short len2;
295         unsigned char **x = va_arg(ap, unsigned char **);
296         unsigned short *len = va_arg(ap, unsigned short *);
297         SILC_GET16_MSB(len2, src->data);
298         silc_buffer_pull(src, 2);
299         if ((len2 > src->len))
300           break;
301         if (len2 < 1)
302           break;
303         if (len)
304           *len = len2;
305         if (x) {
306           *x = silc_calloc(len2 + 1, sizeof(unsigned char));
307           memcpy(*x, src->data, len2);
308         }
309         silc_buffer_pull(src, len2);
310         break;
311       }
312     case SILC_BUFFER_PARAM_UI32_NSTRING:
313       {
314         unsigned int len2;
315         unsigned char **x = va_arg(ap, unsigned char **);
316         unsigned int *len = va_arg(ap, unsigned int *);
317         SILC_GET32_MSB(len2, src->data);
318         silc_buffer_pull(src, 4);
319         if ((len2 > src->len))
320           goto fail;
321         if (len2 < 1)
322           break;
323         if (len)
324           *len = len2;
325         if (x)
326           memcpy(x, src->data, len2);
327         silc_buffer_pull(src, len2);
328         break;
329       }
330     case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
331       {
332         unsigned char **x = va_arg(ap, unsigned char **);
333         unsigned int len = va_arg(ap, unsigned int);
334         if (len && x) {
335           *x = silc_calloc(len + 1, sizeof(unsigned char));
336           memcpy(*x, src->data, len);
337         }
338         silc_buffer_pull(src, len);
339         break;
340       }
341     case SILC_BUFFER_PARAM_UI_XNSTRING:
342       {
343         unsigned char **x = va_arg(ap, unsigned char **);
344         unsigned int len = va_arg(ap, unsigned int);
345         if (len && x)
346           memcpy(x, src->data, len);
347         silc_buffer_pull(src, len);
348         break;
349       }
350     case SILC_BUFFER_PARAM_END:
351       goto ok;
352       break;
353     default:
354       SILC_LOG_ERROR(("Bad buffer formatting type `%d'. Could not "
355                       "format the data.", fmt));
356       goto fail;
357       break;
358     }
359   }
360
361  fail:
362   SILC_LOG_ERROR(("Error occured while unformatting buffer"));
363   return FALSE;
364
365  ok:
366   /* Push the buffer back to the start. */
367   len = src->data - start_ptr;
368   silc_buffer_push(src, len);
369   return len;
370 }