1 /*
2 
3   silcbuffmt.c
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 1997 - 2014 Pekka Riikonen
8 
9   The contents of this file are subject to one of the Licenses specified
10   in the COPYING file;  You may not use this file except in compliance
11   with the License.
12 
13   The software distributed under the License is distributed on an "AS IS"
14   basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15   KIND, either expressed or implied.  See the COPYING file for more
16   information.
17 
18 */
19 /* $Id$ */
20 
21 #include "silc.h"
22 
23 /************************** Types and definitions ***************************/
24 
25 /* Check that buffer has enough room to format data in it, if not
26    allocate more. */
27 #define FORMAT_HAS_SPACE(s, b, req)			\
28 do {							\
29   if (silc_unlikely(!silc_buffer_senlarge(s, b, req)))	\
30     goto fail;						\
31   flen += req;						\
32 } while(0)
33 
34 /* Check that there is data to be unformatted */
35 #define UNFORMAT_HAS_SPACE(b, req)		\
36 do {						\
37   if (silc_unlikely(req > silc_buffer_len(b)))	\
38     goto fail;					\
39   if (silc_unlikely((req + 1) <= 0))		\
40     goto fail;					\
41 } while(0)
42 
43 
44 /******************************* Formatting *********************************/
45 
silc_buffer_format(SilcBuffer dst,...)46 int silc_buffer_format(SilcBuffer dst, ...)
47 {
48   va_list ap;
49   int ret;
50 
51   va_start(ap, dst);
52   ret = silc_buffer_sformat_vp(NULL, dst, ap);
53   va_end(ap);
54 
55   return ret;
56 }
57 
silc_buffer_format_vp(SilcBuffer dst,va_list ap)58 int silc_buffer_format_vp(SilcBuffer dst, va_list ap)
59 {
60   return silc_buffer_sformat_vp(NULL, dst, ap);
61 }
62 
silc_buffer_sformat(SilcStack stack,SilcBuffer dst,...)63 int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...)
64 {
65   va_list ap;
66   int ret;
67 
68   va_start(ap, dst);
69   ret = silc_buffer_sformat_vp(stack, dst, ap);
70   va_end(ap);
71 
72   return ret;
73 }
74 
silc_buffer_sformat_vp(SilcStack stack,SilcBuffer dst,va_list ap)75 int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap)
76 {
77   SilcBufferParamType fmt;
78   int flen = 0;
79   SilcBool advance = FALSE;
80 
81   /* Parse the arguments by formatting type. */
82   while (1) {
83     fmt = va_arg(ap, SilcBufferParamType);
84 
85     switch(fmt) {
86     case SILC_PARAM_FUNC:
87       {
88 	SilcBufferFormatFunc func = NULL;
89 	SilcBufferSFormatFunc funcs = NULL;
90 	void *val;
91 	void *context;
92 	int tmp_len;
93 	if (!stack)
94 	  func = va_arg(ap, SilcBufferFormatFunc);
95 	else
96 	  funcs = va_arg(ap, SilcBufferSFormatFunc);
97 	val = va_arg(ap, void *);
98 	context = va_arg(ap, void *);
99 	if (!stack)
100 	  tmp_len = func(dst, val, context);
101 	else
102 	  tmp_len = funcs(stack, dst, val, context);
103 	if (tmp_len < 0)
104 	  goto fail;
105 	if (tmp_len) {
106 	  silc_buffer_pull(dst, tmp_len);
107 	  flen += tmp_len;
108 	}
109       }
110       break;
111     case SILC_PARAM_UI8_STRING:
112     case SILC_PARAM_UI16_STRING:
113     case SILC_PARAM_UI32_STRING:
114     case SILC_PARAM_UI8_STRING_ALLOC:
115     case SILC_PARAM_UI16_STRING_ALLOC:
116     case SILC_PARAM_UI32_STRING_ALLOC:
117       {
118 	unsigned char *x = va_arg(ap, unsigned char *);
119 	SilcUInt32 tmp_len = x ? strlen(x) : 0;
120 	if (x && tmp_len) {
121 	  FORMAT_HAS_SPACE(stack, dst, tmp_len);
122 	  silc_buffer_put(dst, x, tmp_len);
123 	  silc_buffer_pull(dst, tmp_len);
124 	}
125 	break;
126       }
127     case SILC_PARAM_UI8_NSTRING:
128     case SILC_PARAM_UI16_NSTRING:
129     case SILC_PARAM_UI32_NSTRING:
130     case SILC_PARAM_UI_XNSTRING:
131     case SILC_PARAM_DATA:
132     case SILC_PARAM_UI8_NSTRING_ALLOC:
133     case SILC_PARAM_UI16_NSTRING_ALLOC:
134     case SILC_PARAM_UI32_NSTRING_ALLOC:
135     case SILC_PARAM_UI_XNSTRING_ALLOC:
136     case SILC_PARAM_DATA_ALLOC:
137       {
138 	unsigned char *x = va_arg(ap, unsigned char *);
139 	SilcUInt32 tmp_len = va_arg(ap, SilcUInt32);
140 	if (x && tmp_len) {
141 	  FORMAT_HAS_SPACE(stack, dst, tmp_len);
142 	  silc_buffer_put(dst, x, tmp_len);
143 	  silc_buffer_pull(dst, tmp_len);
144 	}
145 	break;
146       }
147     case SILC_PARAM_UI8_CHAR:
148       {
149 	unsigned char x = (unsigned char)va_arg(ap, int);
150 	FORMAT_HAS_SPACE(stack, dst, 1);
151 	silc_buffer_put(dst, &x, 1);
152 	silc_buffer_pull(dst, 1);
153 	break;
154       }
155     case SILC_PARAM_UI16_SHORT:
156       {
157 	unsigned char xf[2];
158 	SilcUInt16 x = (SilcUInt16)va_arg(ap, int);
159 	FORMAT_HAS_SPACE(stack, dst, 2);
160 	SILC_PUT16_MSB(x, xf);
161 	silc_buffer_put(dst, xf, 2);
162 	silc_buffer_pull(dst, 2);
163 	break;
164       }
165     case SILC_PARAM_UI32_INT:
166       {
167 	unsigned char xf[4];
168 	SilcUInt32 x = va_arg(ap, SilcUInt32);
169 	FORMAT_HAS_SPACE(stack, dst, 4);
170 	SILC_PUT32_MSB(x, xf);
171 	silc_buffer_put(dst, xf, 4);
172 	silc_buffer_pull(dst, 4);
173 	break;
174       }
175     case SILC_PARAM_UI64_INT:
176       {
177 	unsigned char xf[8];
178 	SilcUInt64 x = va_arg(ap, SilcUInt64);
179 	FORMAT_HAS_SPACE(stack, dst, sizeof(SilcUInt64));
180 	SILC_PUT64_MSB(x, xf);
181 	silc_buffer_put(dst, xf, sizeof(SilcUInt64));
182 	silc_buffer_pull(dst, sizeof(SilcUInt64));
183 	break;
184       }
185     case SILC_PARAM_SI8_CHAR:
186       {
187 	char x = (char)va_arg(ap, int);
188 	FORMAT_HAS_SPACE(stack, dst, 1);
189 	silc_buffer_put(dst, &x, 1);
190 	silc_buffer_pull(dst, 1);
191 	break;
192       }
193     case SILC_PARAM_SI16_SHORT:
194       {
195 	unsigned char xf[2];
196 	SilcInt16 x = (SilcInt16)va_arg(ap, int);
197 	FORMAT_HAS_SPACE(stack, dst, 2);
198 	SILC_PUT16_MSB(x, xf);
199 	silc_buffer_put(dst, xf, 2);
200 	silc_buffer_pull(dst, 2);
201 	break;
202       }
203     case SILC_PARAM_SI32_INT:
204       {
205 	unsigned char xf[4];
206 	SilcInt32 x = va_arg(ap, SilcInt32);
207 	FORMAT_HAS_SPACE(stack, dst, 4);
208 	SILC_PUT32_MSB(x, xf);
209 	silc_buffer_put(dst, xf, 4);
210 	silc_buffer_pull(dst, 4);
211 	break;
212       }
213     case SILC_PARAM_SI64_INT:
214       {
215 	unsigned char xf[8];
216 	SilcInt64 x = va_arg(ap, SilcInt64);
217 	FORMAT_HAS_SPACE(stack, dst, sizeof(SilcInt64));
218 	SILC_PUT64_MSB(x, xf);
219 	silc_buffer_put(dst, xf, sizeof(SilcInt64));
220 	silc_buffer_pull(dst, sizeof(SilcInt64));
221 	break;
222       }
223     case SILC_PARAM_BUFFER:
224     case SILC_PARAM_BUFFER_ALLOC:
225       {
226 	SilcBuffer x = va_arg(ap, SilcBuffer);
227 	unsigned char xf[4];
228 	if (x && silc_buffer_len(x)) {
229 	  FORMAT_HAS_SPACE(stack, dst, silc_buffer_len(x) + 4);
230 	  SILC_PUT32_MSB(silc_buffer_len(x), xf);
231 	  silc_buffer_put(dst, xf, 4);
232 	  silc_buffer_pull(dst, 4);
233 	  silc_buffer_put(dst, silc_buffer_data(x), silc_buffer_len(x));
234 	  silc_buffer_pull(dst, silc_buffer_len(x));
235 	}
236       }
237       break;
238     case SILC_PARAM_OFFSET:
239       {
240 	int offst = va_arg(ap, int);
241 	if (!offst)
242 	  break;
243 	if (offst > 1) {
244 	  if (offst > silc_buffer_len(dst))
245 	    goto fail;
246 	  silc_buffer_pull(dst, offst);
247 	  flen += offst;
248 	} else {
249 	  if (-(offst) > (int)silc_buffer_headlen(dst))
250 	    goto fail;
251 	  silc_buffer_push(dst, -(offst));
252 	  flen += -(offst);
253 	}
254 	break;
255       }
256     case SILC_PARAM_ADVANCE:
257       advance = TRUE;
258       break;
259     case SILC_PARAM_END:
260       goto ok;
261       break;
262     default:
263       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
264 		      "format the data.", fmt));
265       goto fail;
266       break;
267     }
268   }
269 
270  fail:
271   SILC_LOG_DEBUG(("Error occured while formatting data"));
272   if (!advance)
273     silc_buffer_push(dst, flen);
274   return -1;
275 
276  ok:
277   /* Push the buffer back to where it belongs. */
278   if (!advance)
279     silc_buffer_push(dst, flen);
280   return flen;
281 }
282 
283 
284 /****************************** Unformatting ********************************/
285 
silc_buffer_unformat(SilcBuffer src,...)286 int silc_buffer_unformat(SilcBuffer src, ...)
287 {
288   va_list ap;
289   int ret;
290 
291   va_start(ap, src);
292   ret = silc_buffer_sunformat_vp(NULL, src, ap);
293   va_end(ap);
294 
295   return ret;
296 }
297 
silc_buffer_unformat_vp(SilcBuffer src,va_list ap)298 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
299 {
300   return silc_buffer_sunformat_vp(NULL, src, ap);
301 }
302 
silc_buffer_sunformat(SilcStack stack,SilcBuffer src,...)303 int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...)
304 {
305   va_list ap;
306   int ret;
307 
308   va_start(ap, src);
309   ret = silc_buffer_sunformat_vp(stack, src, ap);
310   va_end(ap);
311 
312   return ret;
313 }
314 
silc_buffer_sunformat_vp(SilcStack stack,SilcBuffer src,va_list ap)315 int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap)
316 {
317   SilcBufferParamType fmt;
318   unsigned char *start_ptr = src->data;
319   int len = 0;
320   SilcBool advance = FALSE;
321 
322   /* Parse the arguments by formatting type. */
323   while(1) {
324     fmt = va_arg(ap, SilcBufferParamType);
325 
326     switch(fmt) {
327     case SILC_PARAM_FUNC:
328       {
329 	SilcBufferUnformatFunc func = NULL;
330 	SilcBufferSUnformatFunc funcs = NULL;
331 	void **val;
332 	void *context;
333 	int tmp_len;
334 	if (!stack)
335 	  func = va_arg(ap, SilcBufferUnformatFunc);
336 	else
337 	  funcs = va_arg(ap, SilcBufferSUnformatFunc);
338 	val = va_arg(ap, void **);
339 	context = va_arg(ap, void *);
340 	if (!stack)
341 	  tmp_len = func(src, val, context);
342 	else
343 	  tmp_len = funcs(stack, src, val, context);
344 	if (tmp_len < 0)
345 	  goto fail;
346 	if (tmp_len) {
347 	  UNFORMAT_HAS_SPACE(src, tmp_len);
348 	  silc_buffer_pull(src, tmp_len);
349 	}
350       }
351     case SILC_PARAM_UI_XNSTRING:
352     case SILC_PARAM_DATA:
353       {
354 	unsigned char **x = va_arg(ap, unsigned char **);
355 	SilcUInt32 len2 = va_arg(ap, SilcUInt32);
356 	UNFORMAT_HAS_SPACE(src, len2);
357 	if (silc_likely(len2 && x))
358 	  *x = src->data;
359 	silc_buffer_pull(src, len2);
360 	break;
361       }
362     case SILC_PARAM_UI_XNSTRING_ALLOC:
363     case SILC_PARAM_DATA_ALLOC:
364       {
365 	unsigned char **x = va_arg(ap, unsigned char **);
366 	SilcUInt32 len2 = va_arg(ap, SilcUInt32);
367 	UNFORMAT_HAS_SPACE(src, len2);
368 	if (silc_likely(len2 && x)) {
369 	  *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
370 	  if (*x)
371 	    memcpy(*x, src->data, len2);
372 	}
373 	silc_buffer_pull(src, len2);
374 	break;
375       }
376     case SILC_PARAM_UI8_CHAR:
377       {
378 	unsigned char *x = va_arg(ap, unsigned char *);
379 	UNFORMAT_HAS_SPACE(src, 1);
380 	if (silc_likely(x))
381 	  *x = src->data[0];
382 	silc_buffer_pull(src, 1);
383 	break;
384       }
385     case SILC_PARAM_UI16_SHORT:
386       {
387 	SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
388 	UNFORMAT_HAS_SPACE(src, 2);
389 	if (silc_likely(x))
390 	  SILC_GET16_MSB(*x, src->data);
391 	silc_buffer_pull(src, 2);
392 	break;
393       }
394     case SILC_PARAM_UI32_INT:
395       {
396 	SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
397 	UNFORMAT_HAS_SPACE(src, 4);
398 	if (silc_likely(x))
399 	  SILC_GET32_MSB(*x, src->data);
400 	silc_buffer_pull(src, 4);
401 	break;
402       }
403     case SILC_PARAM_UI64_INT:
404       {
405 	SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
406 	UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
407 	if (silc_likely(x))
408 	  SILC_GET64_MSB(*x, src->data);
409 	silc_buffer_pull(src, sizeof(SilcUInt64));
410 	break;
411       }
412     case SILC_PARAM_SI8_CHAR:
413       {
414 	char *x = va_arg(ap, char *);
415 	UNFORMAT_HAS_SPACE(src, 1);
416 	if (silc_likely(x))
417 	  *x = src->data[0];
418 	silc_buffer_pull(src, 1);
419 	break;
420       }
421     case SILC_PARAM_SI16_SHORT:
422       {
423 	SilcInt16 *x = va_arg(ap, SilcInt16 *);
424 	UNFORMAT_HAS_SPACE(src, 2);
425 	if (silc_likely(x))
426 	  SILC_GET16_MSB(*x, src->data);
427 	silc_buffer_pull(src, 2);
428 	break;
429       }
430     case SILC_PARAM_SI32_INT:
431       {
432 	SilcInt32 *x = va_arg(ap, SilcInt32 *);
433 	UNFORMAT_HAS_SPACE(src, 4);
434 	if (silc_likely(x))
435 	  SILC_GET32_MSB(*x, src->data);
436 	silc_buffer_pull(src, 4);
437 	break;
438       }
439     case SILC_PARAM_SI64_INT:
440       {
441 	SilcInt64 *x = va_arg(ap, SilcInt64 *);
442 	UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
443 	if (silc_likely(x))
444 	  SILC_GET64_MSB(*x, src->data);
445 	silc_buffer_pull(src, sizeof(SilcInt64));
446 	break;
447       }
448     case SILC_PARAM_UI8_STRING:
449       {
450 	SilcUInt8 len2;
451 	unsigned char **x = va_arg(ap, unsigned char **);
452 	UNFORMAT_HAS_SPACE(src, 1);
453 	len2 = (SilcUInt8)src->data[0];
454 	silc_buffer_pull(src, 1);
455 	UNFORMAT_HAS_SPACE(src, len2);
456 	if (silc_likely(x))
457 	  *x = src->data;
458 	silc_buffer_pull(src, len2);
459 	break;
460       }
461     case SILC_PARAM_UI16_STRING:
462       {
463 	SilcUInt16 len2;
464 	unsigned char **x = va_arg(ap, unsigned char **);
465 	UNFORMAT_HAS_SPACE(src, 2);
466 	SILC_GET16_MSB(len2, src->data);
467 	silc_buffer_pull(src, 2);
468 	UNFORMAT_HAS_SPACE(src, len2);
469 	if (silc_likely(x))
470 	  *x = src->data;
471 	silc_buffer_pull(src, len2);
472 	break;
473       }
474     case SILC_PARAM_UI8_STRING_ALLOC:
475       {
476 	SilcUInt8 len2;
477 	unsigned char **x = va_arg(ap, unsigned char **);
478 	UNFORMAT_HAS_SPACE(src, 1);
479 	len2 = (SilcUInt8)src->data[0];
480 	silc_buffer_pull(src, 1);
481 	UNFORMAT_HAS_SPACE(src, len2);
482 	if (silc_likely(x && len2)) {
483 	  *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
484 	  if (*x)
485 	    memcpy(*x, src->data, len2);
486 	}
487 	silc_buffer_pull(src, len2);
488 	break;
489       }
490     case SILC_PARAM_UI16_STRING_ALLOC:
491       {
492 	SilcUInt16 len2;
493 	unsigned char **x = va_arg(ap, unsigned char **);
494 	UNFORMAT_HAS_SPACE(src, 2);
495 	SILC_GET16_MSB(len2, src->data);
496 	silc_buffer_pull(src, 2);
497 	UNFORMAT_HAS_SPACE(src, len2);
498 	if (silc_likely(x && len2)) {
499 	  *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
500 	  if (*x)
501 	    memcpy(*x, src->data, len2);
502 	}
503 	silc_buffer_pull(src, len2);
504 	break;
505       }
506     case SILC_PARAM_UI32_STRING:
507       {
508 	SilcUInt32 len2;
509 	unsigned char **x = va_arg(ap, unsigned char **);
510 	UNFORMAT_HAS_SPACE(src, 4);
511 	SILC_GET32_MSB(len2, src->data);
512 	silc_buffer_pull(src, 4);
513 	UNFORMAT_HAS_SPACE(src, len2);
514 	if (silc_likely(x))
515 	  *x = src->data;
516 	silc_buffer_pull(src, len2);
517 	break;
518       }
519     case SILC_PARAM_UI32_STRING_ALLOC:
520       {
521 	SilcUInt32 len2;
522 	unsigned char **x = va_arg(ap, unsigned char **);
523 	UNFORMAT_HAS_SPACE(src, 4);
524 	SILC_GET32_MSB(len2, src->data);
525 	silc_buffer_pull(src, 4);
526 	UNFORMAT_HAS_SPACE(src, len2);
527 	if (silc_likely(x && len2)) {
528 	  *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
529 	  if (*x)
530 	    memcpy(*x, src->data, len2);
531 	}
532 	silc_buffer_pull(src, len2);
533 	break;
534       }
535     case SILC_PARAM_UI8_NSTRING:
536       {
537 	SilcUInt8 len2;
538 	unsigned char **x = va_arg(ap, unsigned char **);
539 	SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
540 	UNFORMAT_HAS_SPACE(src, 1);
541 	len2 = (SilcUInt8)src->data[0];
542 	silc_buffer_pull(src, 1);
543 	UNFORMAT_HAS_SPACE(src, len2);
544 	if (len3)
545 	  *len3 = len2;
546 	if (x)
547 	  *x = src->data;
548 	silc_buffer_pull(src, len2);
549 	break;
550       }
551     case SILC_PARAM_UI16_NSTRING:
552       {
553 	SilcUInt16 len2;
554 	unsigned char **x = va_arg(ap, unsigned char **);
555 	SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
556 	UNFORMAT_HAS_SPACE(src, 2);
557 	SILC_GET16_MSB(len2, src->data);
558 	silc_buffer_pull(src, 2);
559 	UNFORMAT_HAS_SPACE(src, len2);
560 	if (len3)
561 	  *len3 = len2;
562 	if (x)
563 	  *x = src->data;
564 	silc_buffer_pull(src, len2);
565 	break;
566       }
567     case SILC_PARAM_UI8_NSTRING_ALLOC:
568       {
569 	SilcUInt8 len2;
570 	unsigned char **x = va_arg(ap, unsigned char **);
571 	SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
572 	UNFORMAT_HAS_SPACE(src, 1);
573 	len2 = (SilcUInt8)src->data[0];
574 	silc_buffer_pull(src, 1);
575 	UNFORMAT_HAS_SPACE(src, len2);
576 	if (len3)
577 	  *len3 = len2;
578 	if (x && len2) {
579 	  *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
580 	  if (*x)
581 	    memcpy(*x, src->data, len2);
582 	}
583 	silc_buffer_pull(src, len2);
584 	break;
585       }
586     case SILC_PARAM_UI16_NSTRING_ALLOC:
587       {
588 	SilcUInt16 len2;
589 	unsigned char **x = va_arg(ap, unsigned char **);
590 	SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
591 	UNFORMAT_HAS_SPACE(src, 2);
592 	SILC_GET16_MSB(len2, src->data);
593 	silc_buffer_pull(src, 2);
594 	UNFORMAT_HAS_SPACE(src, len2);
595 	if (len3)
596 	  *len3 = len2;
597 	if (x && len2) {
598 	  *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
599 	  if (*x)
600 	    memcpy(*x, src->data, len2);
601 	}
602 	silc_buffer_pull(src, len2);
603 	break;
604       }
605     case SILC_PARAM_UI32_NSTRING:
606       {
607 	SilcUInt32 len2;
608 	unsigned char **x = va_arg(ap, unsigned char **);
609 	SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
610 	UNFORMAT_HAS_SPACE(src, 4);
611 	SILC_GET32_MSB(len2, src->data);
612 	silc_buffer_pull(src, 4);
613 	UNFORMAT_HAS_SPACE(src, len2);
614 	if (len3)
615 	  *len3 = len2;
616 	if (x)
617 	  *x = src->data;
618 	silc_buffer_pull(src, len2);
619 	break;
620       }
621     case SILC_PARAM_BUFFER:
622       {
623 	SilcBuffer x = va_arg(ap, SilcBuffer);
624 	SilcUInt32 len2;
625 	UNFORMAT_HAS_SPACE(src, 4);
626 	SILC_GET32_MSB(len2, src->data);
627 	silc_buffer_pull(src, 4);
628 	UNFORMAT_HAS_SPACE(src, len2);
629 	silc_buffer_set(x, src->data, len2);
630 	silc_buffer_pull(src, len2);
631       }
632       break;
633     case SILC_PARAM_BUFFER_ALLOC:
634       {
635 	SilcBuffer x = va_arg(ap, SilcBuffer);
636 	SilcUInt32 len2;
637 	UNFORMAT_HAS_SPACE(src, 4);
638 	SILC_GET32_MSB(len2, src->data);
639 	silc_buffer_pull(src, 4);
640 	UNFORMAT_HAS_SPACE(src, len2);
641 	if (silc_buffer_sformat(stack, x,
642 				SILC_STR_DATA(src->data, len2),
643 				SILC_STR_END) < 0)
644 	  goto fail;
645 	silc_buffer_pull(src, len2);
646       }
647       break;
648     case SILC_PARAM_OFFSET:
649       {
650 	int offst = va_arg(ap, int);
651 	if (!offst)
652 	  break;
653 	if (offst > 1) {
654 	  UNFORMAT_HAS_SPACE(src, offst);
655 	  silc_buffer_pull(src, offst);
656 	} else {
657 	  silc_buffer_push(src, -(offst));
658 	}
659 	break;
660       }
661     case SILC_PARAM_ADVANCE:
662       advance = TRUE;
663       break;
664     case SILC_PARAM_END:
665       goto ok;
666       break;
667     default:
668       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
669 		      "format the data.", fmt));
670       goto fail;
671       break;
672     }
673   }
674 
675  fail:
676   SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
677   len = src->data - start_ptr;
678   silc_buffer_push(src, len);
679   return -1;
680 
681  ok:
682   /* Push the buffer back to the start. */
683   if (!advance) {
684     len = src->data - start_ptr;
685     silc_buffer_push(src, len);
686   }
687   return len;
688 }
689 
690 
691 /**************************** Utility functions *****************************/
692 
693 /* Formats strings into a buffer */
694 
silc_buffer_strformat(SilcBuffer dst,...)695 int silc_buffer_strformat(SilcBuffer dst, ...)
696 {
697   int len = silc_buffer_truelen(dst);
698   int hlen = silc_buffer_headlen(dst);
699   va_list va;
700 
701   va_start(va, dst);
702 
703   /* Parse the arguments by formatting type. */
704   while(1) {
705     char *string = va_arg(va, char *);
706     unsigned char *d;
707     SilcInt32 slen;
708 
709     if (!string)
710       continue;
711     if (string == (char *)SILC_PARAM_END)
712       goto ok;
713 
714     slen = strlen(string);
715     d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
716     if (silc_unlikely(!d))
717       return -1;
718     dst->head = d;
719     memcpy(dst->head + len, string, slen);
720     len += slen;
721     dst->head[len] = '\0';
722   }
723 
724   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
725   va_end(va);
726   return -1;
727 
728  ok:
729   dst->end = dst->head + len;
730   dst->data = dst->head + hlen;
731   dst->tail = dst->end;
732 
733   va_end(va);
734   return len;
735 }
736 
737 /* Formats strings into a buffer.  Allocates memory from SilcStack. */
738 
silc_buffer_sstrformat(SilcStack stack,SilcBuffer dst,...)739 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
740 {
741   int len = silc_buffer_truelen(dst);
742   int hlen = silc_buffer_headlen(dst);
743   va_list va;
744 
745   va_start(va, dst);
746 
747   /* Parse the arguments by formatting type. */
748   while(1) {
749     char *string = va_arg(va, char *);
750     unsigned char *d;
751     SilcInt32 slen;
752 
753     if (!string)
754       continue;
755     if (string == (char *)SILC_PARAM_END)
756       goto ok;
757 
758     slen = strlen(string);
759     d = silc_srealloc(stack, len + 1, dst->head,
760 		      sizeof(*dst->head) * (slen + len + 1));
761     if (silc_unlikely(!d))
762       return -1;
763     dst->head = d;
764     memcpy(dst->head + len, string, slen);
765     len += slen;
766     dst->head[len] = '\0';
767   }
768 
769   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
770   va_end(va);
771   return -1;
772 
773  ok:
774   dst->end = dst->head + len;
775   dst->data = dst->head + hlen;
776   dst->tail = dst->end;
777 
778   va_end(va);
779   return len;
780 }
781