5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2014 Pekka Riikonen
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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
23 /************************** Types and definitions ***************************/
25 /* Check that buffer has enough room to format data in it, if not
27 #define FORMAT_HAS_SPACE(s, b, req) \
29 if (silc_unlikely(!silc_buffer_senlarge(s, b, req))) \
34 /* Check that there is data to be unformatted */
35 #define UNFORMAT_HAS_SPACE(b, req) \
37 if (silc_unlikely(req > silc_buffer_len(b))) \
39 if (silc_unlikely((req + 1) <= 0)) \
44 /******************************* Formatting *********************************/
46 int silc_buffer_format(SilcBuffer dst, ...)
52 ret = silc_buffer_sformat_vp(NULL, dst, ap);
58 int silc_buffer_format_vp(SilcBuffer dst, va_list ap)
60 return silc_buffer_sformat_vp(NULL, dst, ap);
63 int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...)
69 ret = silc_buffer_sformat_vp(stack, dst, ap);
75 int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap)
77 SilcBufferParamType fmt;
79 SilcBool advance = FALSE;
81 /* Parse the arguments by formatting type. */
83 fmt = va_arg(ap, SilcBufferParamType);
88 SilcBufferFormatFunc func = NULL;
89 SilcBufferSFormatFunc funcs = NULL;
94 func = va_arg(ap, SilcBufferFormatFunc);
96 funcs = va_arg(ap, SilcBufferSFormatFunc);
97 val = va_arg(ap, void *);
98 context = va_arg(ap, void *);
100 tmp_len = func(dst, val, context);
102 tmp_len = funcs(stack, dst, val, context);
106 silc_buffer_pull(dst, tmp_len);
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:
118 unsigned char *x = va_arg(ap, unsigned char *);
119 SilcUInt32 tmp_len = x ? strlen(x) : 0;
121 FORMAT_HAS_SPACE(stack, dst, tmp_len);
122 silc_buffer_put(dst, x, tmp_len);
123 silc_buffer_pull(dst, tmp_len);
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:
138 unsigned char *x = va_arg(ap, unsigned char *);
139 SilcUInt32 tmp_len = va_arg(ap, SilcUInt32);
141 FORMAT_HAS_SPACE(stack, dst, tmp_len);
142 silc_buffer_put(dst, x, tmp_len);
143 silc_buffer_pull(dst, tmp_len);
147 case SILC_PARAM_UI8_CHAR:
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);
155 case SILC_PARAM_UI16_SHORT:
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);
165 case SILC_PARAM_UI32_INT:
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);
175 case SILC_PARAM_UI64_INT:
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));
185 case SILC_PARAM_SI8_CHAR:
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);
193 case SILC_PARAM_SI16_SHORT:
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);
203 case SILC_PARAM_SI32_INT:
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);
213 case SILC_PARAM_SI64_INT:
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));
223 case SILC_PARAM_BUFFER:
224 case SILC_PARAM_BUFFER_ALLOC:
226 SilcBuffer x = va_arg(ap, SilcBuffer);
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));
238 case SILC_PARAM_OFFSET:
240 int offst = va_arg(ap, int);
244 if (offst > silc_buffer_len(dst))
246 silc_buffer_pull(dst, offst);
249 if (-(offst) > (int)silc_buffer_headlen(dst))
251 silc_buffer_push(dst, -(offst));
256 case SILC_PARAM_ADVANCE:
263 SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
264 "format the data.", fmt));
271 SILC_LOG_DEBUG(("Error occured while formatting data"));
273 silc_buffer_push(dst, flen);
277 /* Push the buffer back to where it belongs. */
279 silc_buffer_push(dst, flen);
284 /****************************** Unformatting ********************************/
286 int silc_buffer_unformat(SilcBuffer src, ...)
292 ret = silc_buffer_sunformat_vp(NULL, src, ap);
298 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
300 return silc_buffer_sunformat_vp(NULL, src, ap);
303 int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...)
309 ret = silc_buffer_sunformat_vp(stack, src, ap);
315 int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap)
317 SilcBufferParamType fmt;
318 unsigned char *start_ptr = src->data;
320 SilcBool advance = FALSE;
322 /* Parse the arguments by formatting type. */
324 fmt = va_arg(ap, SilcBufferParamType);
327 case SILC_PARAM_FUNC:
329 SilcBufferUnformatFunc func = NULL;
330 SilcBufferSUnformatFunc funcs = NULL;
335 func = va_arg(ap, SilcBufferUnformatFunc);
337 funcs = va_arg(ap, SilcBufferSUnformatFunc);
338 val = va_arg(ap, void **);
339 context = va_arg(ap, void *);
341 tmp_len = func(src, val, context);
343 tmp_len = funcs(stack, src, val, context);
347 UNFORMAT_HAS_SPACE(src, tmp_len);
348 silc_buffer_pull(src, tmp_len);
351 case SILC_PARAM_UI_XNSTRING:
352 case SILC_PARAM_DATA:
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))
359 silc_buffer_pull(src, len2);
362 case SILC_PARAM_UI_XNSTRING_ALLOC:
363 case SILC_PARAM_DATA_ALLOC:
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));
371 memcpy(*x, src->data, len2);
373 silc_buffer_pull(src, len2);
376 case SILC_PARAM_UI8_CHAR:
378 unsigned char *x = va_arg(ap, unsigned char *);
379 UNFORMAT_HAS_SPACE(src, 1);
382 silc_buffer_pull(src, 1);
385 case SILC_PARAM_UI16_SHORT:
387 SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
388 UNFORMAT_HAS_SPACE(src, 2);
390 SILC_GET16_MSB(*x, src->data);
391 silc_buffer_pull(src, 2);
394 case SILC_PARAM_UI32_INT:
396 SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
397 UNFORMAT_HAS_SPACE(src, 4);
399 SILC_GET32_MSB(*x, src->data);
400 silc_buffer_pull(src, 4);
403 case SILC_PARAM_UI64_INT:
405 SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
406 UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
408 SILC_GET64_MSB(*x, src->data);
409 silc_buffer_pull(src, sizeof(SilcUInt64));
412 case SILC_PARAM_SI8_CHAR:
414 char *x = va_arg(ap, char *);
415 UNFORMAT_HAS_SPACE(src, 1);
418 silc_buffer_pull(src, 1);
421 case SILC_PARAM_SI16_SHORT:
423 SilcInt16 *x = va_arg(ap, SilcInt16 *);
424 UNFORMAT_HAS_SPACE(src, 2);
426 SILC_GET16_MSB(*x, src->data);
427 silc_buffer_pull(src, 2);
430 case SILC_PARAM_SI32_INT:
432 SilcInt32 *x = va_arg(ap, SilcInt32 *);
433 UNFORMAT_HAS_SPACE(src, 4);
435 SILC_GET32_MSB(*x, src->data);
436 silc_buffer_pull(src, 4);
439 case SILC_PARAM_SI64_INT:
441 SilcInt64 *x = va_arg(ap, SilcInt64 *);
442 UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
444 SILC_GET64_MSB(*x, src->data);
445 silc_buffer_pull(src, sizeof(SilcInt64));
448 case SILC_PARAM_UI8_STRING:
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);
458 silc_buffer_pull(src, len2);
461 case SILC_PARAM_UI16_STRING:
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);
471 silc_buffer_pull(src, len2);
474 case SILC_PARAM_UI8_STRING_ALLOC:
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));
485 memcpy(*x, src->data, len2);
487 silc_buffer_pull(src, len2);
490 case SILC_PARAM_UI16_STRING_ALLOC:
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));
501 memcpy(*x, src->data, len2);
503 silc_buffer_pull(src, len2);
506 case SILC_PARAM_UI32_STRING:
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);
516 silc_buffer_pull(src, len2);
519 case SILC_PARAM_UI32_STRING_ALLOC:
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));
530 memcpy(*x, src->data, len2);
532 silc_buffer_pull(src, len2);
535 case SILC_PARAM_UI8_NSTRING:
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);
548 silc_buffer_pull(src, len2);
551 case SILC_PARAM_UI16_NSTRING:
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);
564 silc_buffer_pull(src, len2);
567 case SILC_PARAM_UI8_NSTRING_ALLOC:
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);
579 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
581 memcpy(*x, src->data, len2);
583 silc_buffer_pull(src, len2);
586 case SILC_PARAM_UI16_NSTRING_ALLOC:
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);
598 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
600 memcpy(*x, src->data, len2);
602 silc_buffer_pull(src, len2);
605 case SILC_PARAM_UI32_NSTRING:
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);
618 silc_buffer_pull(src, len2);
621 case SILC_PARAM_BUFFER:
623 SilcBuffer x = va_arg(ap, SilcBuffer);
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);
633 case SILC_PARAM_BUFFER_ALLOC:
635 SilcBuffer x = va_arg(ap, SilcBuffer);
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),
645 silc_buffer_pull(src, len2);
648 case SILC_PARAM_OFFSET:
650 int offst = va_arg(ap, int);
654 UNFORMAT_HAS_SPACE(src, offst);
655 silc_buffer_pull(src, offst);
657 silc_buffer_push(src, -(offst));
661 case SILC_PARAM_ADVANCE:
668 SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
669 "format the data.", fmt));
676 SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
677 len = src->data - start_ptr;
678 silc_buffer_push(src, len);
682 /* Push the buffer back to the start. */
684 len = src->data - start_ptr;
685 silc_buffer_push(src, len);
691 /**************************** Utility functions *****************************/
693 /* Formats strings into a buffer */
695 int silc_buffer_strformat(SilcBuffer dst, ...)
697 int len = silc_buffer_truelen(dst);
698 int hlen = silc_buffer_headlen(dst);
703 /* Parse the arguments by formatting type. */
705 char *string = va_arg(va, char *);
711 if (string == (char *)SILC_PARAM_END)
714 slen = strlen(string);
715 d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
716 if (silc_unlikely(!d))
719 memcpy(dst->head + len, string, slen);
721 dst->head[len] = '\0';
724 SILC_LOG_DEBUG(("Error occured while formatting buffer"));
729 dst->end = dst->head + len;
730 dst->data = dst->head + hlen;
731 dst->tail = dst->end;
737 /* Formats strings into a buffer. Allocates memory from SilcStack. */
739 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
741 int len = silc_buffer_truelen(dst);
742 int hlen = silc_buffer_headlen(dst);
747 /* Parse the arguments by formatting type. */
749 char *string = va_arg(va, char *);
755 if (string == (char *)SILC_PARAM_END)
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))
764 memcpy(dst->head + len, string, slen);
766 dst->head[len] = '\0';
769 SILC_LOG_DEBUG(("Error occured while formatting buffer"));
774 dst->end = dst->head + len;
775 dst->data = dst->head + hlen;
776 dst->tail = dst->end;