5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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))) { \
38 silc_set_errno(SILC_ERR_OVERFLOW); \
41 if (silc_unlikely((req + 1) <= 0)) { \
42 silc_set_errno(SILC_ERR_UNDERFLOW); \
48 /******************************* Formatting *********************************/
50 int silc_buffer_format(SilcBuffer dst, ...)
56 ret = silc_buffer_sformat_vp(NULL, dst, ap);
62 int silc_buffer_format_vp(SilcBuffer dst, va_list ap)
64 return silc_buffer_sformat_vp(NULL, dst, ap);
67 int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...)
73 ret = silc_buffer_sformat_vp(stack, dst, ap);
79 int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap)
83 SilcBool advance = FALSE;
85 /* Parse the arguments by formatting type. */
87 fmt = va_arg(ap, SilcParam);
89 SILC_LOG_DEBUG(("Buffer format type %x", fmt));
94 SilcBufferFormatFunc func;
98 func = va_arg(ap, SilcBufferFormatFunc);
99 val = va_arg(ap, void *);
100 context = va_arg(ap, void *);
101 tmp_len = func(stack, dst, val, context);
105 silc_buffer_pull(dst, tmp_len);
110 case SILC_PARAM_UI8_STRING:
111 case SILC_PARAM_UI16_STRING:
112 case SILC_PARAM_UI32_STRING:
113 case SILC_PARAM_UI8_STRING | SILC_PARAM_ALLOC:
114 case SILC_PARAM_UI16_STRING | SILC_PARAM_ALLOC:
115 case SILC_PARAM_UI32_STRING | SILC_PARAM_ALLOC:
117 char *x = va_arg(ap, char *);
118 SilcUInt32 tmp_len = x ? strlen(x) : 0;
120 FORMAT_HAS_SPACE(stack, dst, tmp_len);
121 silc_buffer_put(dst, (unsigned char *)x, tmp_len);
122 silc_buffer_pull(dst, tmp_len);
126 case SILC_PARAM_UI8_NSTRING:
127 case SILC_PARAM_UI16_NSTRING:
128 case SILC_PARAM_UI32_NSTRING:
129 case SILC_PARAM_UICHAR:
130 case SILC_PARAM_UI8_NSTRING | SILC_PARAM_ALLOC:
131 case SILC_PARAM_UI16_NSTRING | SILC_PARAM_ALLOC:
132 case SILC_PARAM_UI32_NSTRING | SILC_PARAM_ALLOC:
133 case SILC_PARAM_UICHAR | SILC_PARAM_ALLOC:
135 unsigned char *x = va_arg(ap, unsigned char *);
136 SilcUInt32 tmp_len = va_arg(ap, SilcUInt32);
138 FORMAT_HAS_SPACE(stack, dst, tmp_len);
139 silc_buffer_put(dst, x, tmp_len);
140 silc_buffer_pull(dst, tmp_len);
144 case SILC_PARAM_UINT8:
146 unsigned char x = (unsigned char)va_arg(ap, int);
147 FORMAT_HAS_SPACE(stack, dst, 1);
148 silc_buffer_put(dst, &x, 1);
149 silc_buffer_pull(dst, 1);
152 case SILC_PARAM_UINT16:
155 SilcUInt16 x = (SilcUInt16)va_arg(ap, int);
156 FORMAT_HAS_SPACE(stack, dst, 2);
157 SILC_PUT16_MSB(x, xf);
158 silc_buffer_put(dst, xf, 2);
159 silc_buffer_pull(dst, 2);
162 case SILC_PARAM_UINT32:
165 SilcUInt32 x = va_arg(ap, SilcUInt32);
166 FORMAT_HAS_SPACE(stack, dst, 4);
167 SILC_PUT32_MSB(x, xf);
168 silc_buffer_put(dst, xf, 4);
169 silc_buffer_pull(dst, 4);
172 case SILC_PARAM_UINT64:
175 SilcUInt64 x = va_arg(ap, SilcUInt64);
176 FORMAT_HAS_SPACE(stack, dst, sizeof(SilcUInt64));
177 SILC_PUT64_MSB(x, xf);
178 silc_buffer_put(dst, xf, sizeof(SilcUInt64));
179 silc_buffer_pull(dst, sizeof(SilcUInt64));
182 case SILC_PARAM_SINT8:
184 char x = (char)va_arg(ap, int);
185 FORMAT_HAS_SPACE(stack, dst, 1);
186 silc_buffer_put(dst, (unsigned char *)&x, 1);
187 silc_buffer_pull(dst, 1);
190 case SILC_PARAM_SINT16:
193 SilcInt16 x = (SilcInt16)va_arg(ap, int);
194 FORMAT_HAS_SPACE(stack, dst, 2);
195 SILC_PUT16_MSB(x, xf);
196 silc_buffer_put(dst, xf, 2);
197 silc_buffer_pull(dst, 2);
200 case SILC_PARAM_SINT32:
203 SilcInt32 x = va_arg(ap, SilcInt32);
204 FORMAT_HAS_SPACE(stack, dst, 4);
205 SILC_PUT32_MSB(x, xf);
206 silc_buffer_put(dst, xf, 4);
207 silc_buffer_pull(dst, 4);
210 case SILC_PARAM_SINT64:
213 SilcInt64 x = va_arg(ap, SilcInt64);
214 FORMAT_HAS_SPACE(stack, dst, sizeof(SilcInt64));
215 SILC_PUT64_MSB(x, xf);
216 silc_buffer_put(dst, xf, sizeof(SilcInt64));
217 silc_buffer_pull(dst, sizeof(SilcInt64));
220 case SILC_PARAM_BUFFER:
221 case SILC_PARAM_BUFFER | SILC_PARAM_ALLOC:
223 SilcBuffer x = va_arg(ap, SilcBuffer);
225 if (x && silc_buffer_len(x)) {
226 FORMAT_HAS_SPACE(stack, dst, silc_buffer_len(x) + 4);
227 SILC_PUT32_MSB(silc_buffer_len(x), xf);
228 silc_buffer_put(dst, xf, 4);
229 silc_buffer_pull(dst, 4);
230 silc_buffer_put(dst, silc_buffer_data(x), silc_buffer_len(x));
231 silc_buffer_pull(dst, silc_buffer_len(x));
235 case SILC_PARAM_OFFSET:
237 int offst = va_arg(ap, int);
241 if (offst > silc_buffer_len(dst)) {
242 silc_set_errno(SILC_ERR_OVERFLOW);
245 silc_buffer_pull(dst, offst);
248 silc_buffer_push(dst, -(offst));
253 case SILC_PARAM_ADVANCE:
260 SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
261 "format the data.", fmt));
262 silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT,
263 "Bad buffer formatting type %d", fmt);
270 SILC_LOG_DEBUG(("Error occured while formatting data"));
272 silc_buffer_push(dst, flen);
276 /* Push the buffer back to where it belongs. */
278 silc_buffer_push(dst, flen);
283 /****************************** Unformatting ********************************/
285 int silc_buffer_unformat(SilcBuffer src, ...)
291 ret = silc_buffer_sunformat_vp(NULL, src, ap);
297 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
299 return silc_buffer_sunformat_vp(NULL, src, ap);
302 int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...)
308 ret = silc_buffer_sunformat_vp(stack, src, ap);
314 int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap)
317 unsigned char *start_ptr = src->data;
319 SilcBool advance = FALSE;
321 /* Parse the arguments by formatting type. */
323 fmt = va_arg(ap, SilcParam);
325 SILC_LOG_DEBUG(("Buffer unformat type %x", fmt));
328 case SILC_PARAM_FUNC:
330 SilcBufferUnformatFunc func;
334 func = va_arg(ap, SilcBufferUnformatFunc);
335 val = va_arg(ap, void **);
336 context = va_arg(ap, void *);
337 tmp_len = func(stack, src, val, context);
341 UNFORMAT_HAS_SPACE(src, tmp_len);
342 silc_buffer_pull(src, tmp_len);
345 case SILC_PARAM_UICHAR:
347 unsigned char **x = va_arg(ap, unsigned char **);
348 SilcUInt32 len2 = va_arg(ap, SilcUInt32);
349 UNFORMAT_HAS_SPACE(src, len2);
350 if (silc_likely(len2 && x))
352 silc_buffer_pull(src, len2);
355 case SILC_PARAM_UICHAR | SILC_PARAM_ALLOC:
357 unsigned char **x = va_arg(ap, unsigned char **);
358 SilcUInt32 len2 = va_arg(ap, SilcUInt32);
359 UNFORMAT_HAS_SPACE(src, len2);
360 if (silc_likely(len2 && x)) {
361 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
362 memcpy(*x, src->data, len2);
364 silc_buffer_pull(src, len2);
367 case SILC_PARAM_UINT8:
369 unsigned char *x = va_arg(ap, unsigned char *);
370 UNFORMAT_HAS_SPACE(src, 1);
373 silc_buffer_pull(src, 1);
376 case SILC_PARAM_UINT16:
378 SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
379 UNFORMAT_HAS_SPACE(src, 2);
381 SILC_GET16_MSB(*x, src->data);
382 silc_buffer_pull(src, 2);
385 case SILC_PARAM_UINT32:
387 SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
388 UNFORMAT_HAS_SPACE(src, 4);
390 SILC_GET32_MSB(*x, src->data);
391 silc_buffer_pull(src, 4);
394 case SILC_PARAM_UINT64:
396 SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
397 UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
399 SILC_GET64_MSB(*x, src->data);
400 silc_buffer_pull(src, sizeof(SilcUInt64));
403 case SILC_PARAM_SINT8:
405 char *x = va_arg(ap, char *);
406 UNFORMAT_HAS_SPACE(src, 1);
409 silc_buffer_pull(src, 1);
412 case SILC_PARAM_SINT16:
414 SilcInt16 *x = va_arg(ap, SilcInt16 *);
415 UNFORMAT_HAS_SPACE(src, 2);
417 SILC_GET16_MSB(*x, src->data);
418 silc_buffer_pull(src, 2);
421 case SILC_PARAM_SINT32:
423 SilcInt32 *x = va_arg(ap, SilcInt32 *);
424 UNFORMAT_HAS_SPACE(src, 4);
426 SILC_GET32_MSB(*x, src->data);
427 silc_buffer_pull(src, 4);
430 case SILC_PARAM_SINT64:
432 SilcInt64 *x = va_arg(ap, SilcInt64 *);
433 UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
435 SILC_GET64_MSB(*x, src->data);
436 silc_buffer_pull(src, sizeof(SilcInt64));
439 case SILC_PARAM_UI8_STRING:
442 unsigned char **x = va_arg(ap, unsigned char **);
443 UNFORMAT_HAS_SPACE(src, 1);
444 len2 = (SilcUInt8)src->data[0];
445 silc_buffer_pull(src, 1);
446 UNFORMAT_HAS_SPACE(src, len2);
449 silc_buffer_pull(src, len2);
452 case SILC_PARAM_UI8_STRING | SILC_PARAM_ALLOC:
455 unsigned char **x = va_arg(ap, unsigned char **);
456 UNFORMAT_HAS_SPACE(src, 1);
457 len2 = (SilcUInt8)src->data[0];
458 silc_buffer_pull(src, 1);
459 UNFORMAT_HAS_SPACE(src, len2);
460 if (silc_likely(x && len2)) {
461 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
462 memcpy(*x, src->data, len2);
464 silc_buffer_pull(src, len2);
467 case SILC_PARAM_UI16_STRING:
470 unsigned char **x = va_arg(ap, unsigned char **);
471 UNFORMAT_HAS_SPACE(src, 2);
472 SILC_GET16_MSB(len2, src->data);
473 silc_buffer_pull(src, 2);
474 UNFORMAT_HAS_SPACE(src, len2);
477 silc_buffer_pull(src, len2);
480 case SILC_PARAM_UI16_STRING | SILC_PARAM_ALLOC:
483 unsigned char **x = va_arg(ap, unsigned char **);
484 UNFORMAT_HAS_SPACE(src, 2);
485 SILC_GET16_MSB(len2, src->data);
486 silc_buffer_pull(src, 2);
487 UNFORMAT_HAS_SPACE(src, len2);
488 if (silc_likely(x && len2)) {
489 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
490 memcpy(*x, src->data, len2);
492 silc_buffer_pull(src, len2);
495 case SILC_PARAM_UI32_STRING:
498 unsigned char **x = va_arg(ap, unsigned char **);
499 UNFORMAT_HAS_SPACE(src, 4);
500 SILC_GET32_MSB(len2, src->data);
501 silc_buffer_pull(src, 4);
502 UNFORMAT_HAS_SPACE(src, len2);
505 silc_buffer_pull(src, len2);
508 case SILC_PARAM_UI32_STRING | SILC_PARAM_ALLOC:
511 unsigned char **x = va_arg(ap, unsigned char **);
512 UNFORMAT_HAS_SPACE(src, 4);
513 SILC_GET32_MSB(len2, src->data);
514 silc_buffer_pull(src, 4);
515 UNFORMAT_HAS_SPACE(src, len2);
516 if (silc_likely(x && len2)) {
517 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
518 memcpy(*x, src->data, len2);
520 silc_buffer_pull(src, len2);
523 case SILC_PARAM_UI8_NSTRING:
526 unsigned char **x = va_arg(ap, unsigned char **);
527 SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
528 UNFORMAT_HAS_SPACE(src, 1);
529 len2 = (SilcUInt8)src->data[0];
530 silc_buffer_pull(src, 1);
531 UNFORMAT_HAS_SPACE(src, len2);
536 silc_buffer_pull(src, len2);
539 case SILC_PARAM_UI8_NSTRING | SILC_PARAM_ALLOC:
542 unsigned char **x = va_arg(ap, unsigned char **);
543 SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
544 UNFORMAT_HAS_SPACE(src, 1);
545 len2 = (SilcUInt8)src->data[0];
546 silc_buffer_pull(src, 1);
547 UNFORMAT_HAS_SPACE(src, len2);
551 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
552 memcpy(*x, src->data, len2);
554 silc_buffer_pull(src, len2);
557 case SILC_PARAM_UI16_NSTRING:
560 unsigned char **x = va_arg(ap, unsigned char **);
561 SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
562 UNFORMAT_HAS_SPACE(src, 2);
563 SILC_GET16_MSB(len2, src->data);
564 silc_buffer_pull(src, 2);
565 UNFORMAT_HAS_SPACE(src, len2);
570 silc_buffer_pull(src, len2);
573 case SILC_PARAM_UI16_NSTRING | SILC_PARAM_ALLOC:
576 unsigned char **x = va_arg(ap, unsigned char **);
577 SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
578 UNFORMAT_HAS_SPACE(src, 2);
579 SILC_GET16_MSB(len2, src->data);
580 silc_buffer_pull(src, 2);
581 UNFORMAT_HAS_SPACE(src, len2);
585 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
586 memcpy(*x, src->data, len2);
588 silc_buffer_pull(src, len2);
591 case SILC_PARAM_UI32_NSTRING:
594 unsigned char **x = va_arg(ap, unsigned char **);
595 SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
596 UNFORMAT_HAS_SPACE(src, 4);
597 SILC_GET32_MSB(len2, src->data);
598 silc_buffer_pull(src, 4);
599 UNFORMAT_HAS_SPACE(src, len2);
604 silc_buffer_pull(src, len2);
607 case SILC_PARAM_UI32_NSTRING | SILC_PARAM_ALLOC:
610 unsigned char **x = va_arg(ap, unsigned char **);
611 SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
612 UNFORMAT_HAS_SPACE(src, 4);
613 SILC_GET32_MSB(len2, src->data);
614 silc_buffer_pull(src, 4);
615 UNFORMAT_HAS_SPACE(src, len2);
618 if (silc_likely(x && len2)) {
619 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
620 memcpy(*x, src->data, len2);
622 silc_buffer_pull(src, len2);
625 case SILC_PARAM_BUFFER:
627 SilcBuffer x = va_arg(ap, SilcBuffer);
629 UNFORMAT_HAS_SPACE(src, 4);
630 SILC_GET32_MSB(len2, src->data);
631 silc_buffer_pull(src, 4);
632 UNFORMAT_HAS_SPACE(src, len2);
633 silc_buffer_set(x, src->data, len2);
634 silc_buffer_pull(src, len2);
637 case SILC_PARAM_BUFFER | SILC_PARAM_ALLOC:
639 SilcBuffer x = va_arg(ap, SilcBuffer);
641 UNFORMAT_HAS_SPACE(src, 4);
642 SILC_GET32_MSB(len2, src->data);
643 silc_buffer_pull(src, 4);
644 UNFORMAT_HAS_SPACE(src, len2);
645 silc_buffer_sformat(stack, x,
646 SILC_STR_DATA(src->data, len2),
648 silc_buffer_pull(src, len2);
651 case SILC_PARAM_OFFSET:
653 int offst = va_arg(ap, int);
657 UNFORMAT_HAS_SPACE(src, offst);
658 silc_buffer_pull(src, offst);
660 silc_buffer_push(src, -(offst));
664 case SILC_PARAM_ADVANCE:
671 SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
672 "format the data.", fmt));
673 silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT,
674 "Bad buffer formatting type %d", fmt);
681 SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
682 len = src->data - start_ptr;
683 silc_buffer_push(src, len);
687 /* Push the buffer back to the start. */
689 len = src->data - start_ptr;
690 silc_buffer_push(src, len);
696 /**************************** Utility functions *****************************/
698 /* Formats strings into a buffer */
700 int silc_buffer_strformat(SilcBuffer dst, ...)
702 int len = silc_buffer_truelen(dst);
703 int hlen = silc_buffer_headlen(dst);
708 /* Parse the arguments by formatting type. */
710 char *string = va_arg(va, char *);
716 if (string == (char *)SILC_PARAM_END)
719 slen = strlen(string);
720 d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
721 if (silc_unlikely(!d))
724 memcpy(dst->head + len, string, slen);
726 dst->head[len] = '\0';
729 SILC_LOG_DEBUG(("Error occured while formatting buffer"));
734 dst->end = dst->head + len;
735 dst->data = dst->head + hlen;
736 dst->tail = dst->end;
742 /* Formats strings into a buffer. Allocates memory from SilcStack. */
744 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
746 int len = silc_buffer_truelen(dst);
747 int hlen = silc_buffer_headlen(dst);
752 /* Parse the arguments by formatting type. */
754 char *string = va_arg(va, char *);
760 if (string == (char *)SILC_PARAM_END)
763 slen = strlen(string);
764 d = silc_srealloc(stack, len + 1, dst->head,
765 sizeof(*dst->head) * (slen + len + 1));
766 if (silc_unlikely(!d))
769 memcpy(dst->head + len, string, slen);
771 dst->head[len] = '\0';
774 SILC_LOG_DEBUG(("Error occured while formatting buffer"));
779 dst->end = dst->head + len;
780 dst->data = dst->head + hlen;
781 dst->tail = dst->end;