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)
81 SilcBufferParamType fmt;
83 SilcBool advance = FALSE;
85 /* Parse the arguments by formatting type. */
87 fmt = va_arg(ap, SilcBufferParamType);
92 SilcBufferFormatFunc func;
96 func = va_arg(ap, SilcBufferFormatFunc);
97 val = va_arg(ap, void *);
98 context = va_arg(ap, void *);
99 tmp_len = func(stack, dst, val, context);
103 silc_buffer_pull(dst, tmp_len);
108 case SILC_PARAM_UI8_STRING:
109 case SILC_PARAM_UI16_STRING:
110 case SILC_PARAM_UI32_STRING:
111 case SILC_PARAM_UI8_STRING_ALLOC:
112 case SILC_PARAM_UI16_STRING_ALLOC:
113 case SILC_PARAM_UI32_STRING_ALLOC:
115 char *x = va_arg(ap, char *);
116 SilcUInt32 tmp_len = x ? strlen(x) : 0;
118 FORMAT_HAS_SPACE(stack, dst, tmp_len);
119 silc_buffer_put(dst, (unsigned char *)x, tmp_len);
120 silc_buffer_pull(dst, tmp_len);
124 case SILC_PARAM_UI8_NSTRING:
125 case SILC_PARAM_UI16_NSTRING:
126 case SILC_PARAM_UI32_NSTRING:
127 case SILC_PARAM_UI_XNSTRING:
128 case SILC_PARAM_DATA:
129 case SILC_PARAM_UI8_NSTRING_ALLOC:
130 case SILC_PARAM_UI16_NSTRING_ALLOC:
131 case SILC_PARAM_UI32_NSTRING_ALLOC:
132 case SILC_PARAM_UI_XNSTRING_ALLOC:
133 case SILC_PARAM_DATA_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_UI8_CHAR:
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_UI16_SHORT:
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_UI32_INT:
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_UI64_INT:
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_SI8_CHAR:
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_SI16_SHORT:
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_SI32_INT:
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_SI64_INT:
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_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)
316 SilcBufferParamType fmt;
317 unsigned char *start_ptr = src->data;
319 SilcBool advance = FALSE;
321 /* Parse the arguments by formatting type. */
323 fmt = va_arg(ap, SilcBufferParamType);
326 case SILC_PARAM_FUNC:
328 SilcBufferUnformatFunc func;
332 func = va_arg(ap, SilcBufferUnformatFunc);
333 val = va_arg(ap, void **);
334 context = va_arg(ap, void *);
335 tmp_len = func(stack, src, val, context);
339 UNFORMAT_HAS_SPACE(src, tmp_len);
340 silc_buffer_pull(src, tmp_len);
343 case SILC_PARAM_UI_XNSTRING:
344 case SILC_PARAM_DATA:
346 unsigned char **x = va_arg(ap, unsigned char **);
347 SilcUInt32 len2 = va_arg(ap, SilcUInt32);
348 UNFORMAT_HAS_SPACE(src, len2);
349 if (silc_likely(len2 && x))
351 silc_buffer_pull(src, len2);
354 case SILC_PARAM_UI_XNSTRING_ALLOC:
355 case SILC_PARAM_DATA_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_UI8_CHAR:
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_UI16_SHORT:
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_UI32_INT:
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_UI64_INT:
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_SI8_CHAR:
405 char *x = va_arg(ap, char *);
406 UNFORMAT_HAS_SPACE(src, 1);
409 silc_buffer_pull(src, 1);
412 case SILC_PARAM_SI16_SHORT:
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_SI32_INT:
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_SI64_INT:
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_UI16_STRING:
455 unsigned char **x = va_arg(ap, unsigned char **);
456 UNFORMAT_HAS_SPACE(src, 2);
457 SILC_GET16_MSB(len2, src->data);
458 silc_buffer_pull(src, 2);
459 UNFORMAT_HAS_SPACE(src, len2);
462 silc_buffer_pull(src, len2);
465 case SILC_PARAM_UI8_STRING_ALLOC:
468 unsigned char **x = va_arg(ap, unsigned char **);
469 UNFORMAT_HAS_SPACE(src, 1);
470 len2 = (SilcUInt8)src->data[0];
471 silc_buffer_pull(src, 1);
472 UNFORMAT_HAS_SPACE(src, len2);
473 if (silc_likely(x && len2)) {
474 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
475 memcpy(*x, src->data, len2);
477 silc_buffer_pull(src, len2);
480 case SILC_PARAM_UI16_STRING_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_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_UI16_NSTRING:
542 unsigned char **x = va_arg(ap, unsigned char **);
543 SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
544 UNFORMAT_HAS_SPACE(src, 2);
545 SILC_GET16_MSB(len2, src->data);
546 silc_buffer_pull(src, 2);
547 UNFORMAT_HAS_SPACE(src, len2);
552 silc_buffer_pull(src, len2);
555 case SILC_PARAM_UI8_NSTRING_ALLOC:
558 unsigned char **x = va_arg(ap, unsigned char **);
559 SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
560 UNFORMAT_HAS_SPACE(src, 1);
561 len2 = (SilcUInt8)src->data[0];
562 silc_buffer_pull(src, 1);
563 UNFORMAT_HAS_SPACE(src, len2);
567 *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
568 memcpy(*x, src->data, len2);
570 silc_buffer_pull(src, len2);
573 case SILC_PARAM_UI16_NSTRING_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_BUFFER:
609 SilcBuffer x = va_arg(ap, SilcBuffer);
611 UNFORMAT_HAS_SPACE(src, 4);
612 SILC_GET32_MSB(len2, src->data);
613 silc_buffer_pull(src, 4);
614 UNFORMAT_HAS_SPACE(src, len2);
615 silc_buffer_set(x, src->data, len2);
616 silc_buffer_pull(src, len2);
619 case SILC_PARAM_BUFFER_ALLOC:
621 SilcBuffer x = va_arg(ap, SilcBuffer);
623 UNFORMAT_HAS_SPACE(src, 4);
624 SILC_GET32_MSB(len2, src->data);
625 silc_buffer_pull(src, 4);
626 UNFORMAT_HAS_SPACE(src, len2);
627 silc_buffer_sformat(stack, x,
628 SILC_STR_DATA(src->data, len2),
630 silc_buffer_pull(src, len2);
633 case SILC_PARAM_OFFSET:
635 int offst = va_arg(ap, int);
639 UNFORMAT_HAS_SPACE(src, offst);
640 silc_buffer_pull(src, offst);
642 silc_buffer_push(src, -(offst));
646 case SILC_PARAM_ADVANCE:
653 SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
654 "format the data.", fmt));
655 silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT,
656 "Bad buffer formatting type %d", fmt);
663 SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
664 len = src->data - start_ptr;
665 silc_buffer_push(src, len);
669 /* Push the buffer back to the start. */
671 len = src->data - start_ptr;
672 silc_buffer_push(src, len);
678 /**************************** Utility functions *****************************/
680 /* Formats strings into a buffer */
682 int silc_buffer_strformat(SilcBuffer dst, ...)
684 int len = silc_buffer_truelen(dst);
685 int hlen = silc_buffer_headlen(dst);
690 /* Parse the arguments by formatting type. */
692 char *string = va_arg(va, char *);
698 if (string == (char *)SILC_PARAM_END)
701 slen = strlen(string);
702 d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
703 if (silc_unlikely(!d))
706 memcpy(dst->head + len, string, slen);
708 dst->head[len] = '\0';
711 SILC_LOG_DEBUG(("Error occured while formatting buffer"));
716 dst->end = dst->head + len;
717 dst->data = dst->head + hlen;
718 dst->tail = dst->end;
724 /* Formats strings into a buffer. Allocates memory from SilcStack. */
726 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
728 int len = silc_buffer_truelen(dst);
729 int hlen = silc_buffer_headlen(dst);
734 /* Parse the arguments by formatting type. */
736 char *string = va_arg(va, char *);
742 if (string == (char *)SILC_PARAM_END)
745 slen = strlen(string);
746 d = silc_srealloc(stack, len + 1, dst->head,
747 sizeof(*dst->head) * (slen + len + 1));
748 if (silc_unlikely(!d))
751 memcpy(dst->head + len, string, slen);
753 dst->head[len] = '\0';
756 SILC_LOG_DEBUG(("Error occured while formatting buffer"));
761 dst->end = dst->head + len;
762 dst->data = dst->head + hlen;
763 dst->tail = dst->end;