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