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