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