1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 * octstr.c - implementation of Octet strings
59 *
60 * See octstr.h for explanations of what public functions should do.
61 *
62 * Lars Wirzenius
63 */
64
65
66 #include <ctype.h>
67 #include <limits.h>
68 #include <errno.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <unistd.h>
72 #include <sys/types.h>
73 #include <sys/socket.h>
74 #include <netinet/in.h>
75
76 #include "gwlib.h"
77
78 /*
79 * Unfortunately some platforms base va_list an an array type
80 * which makes passing of the &args a bit tricky
81 */
82 #if (defined(__linux__) && (defined(__powerpc__) || defined(__s390__) || defined(__x86_64))) || \
83 (defined(__FreeBSD__) && defined(__amd64__)) || \
84 (defined(DARWIN) && defined(__x86_64__))
85 #define VARGS(x) (x)
86 #define VALPARM(y) va_list y
87 #define VALST(z) (z)
88 #else
89 #define VARGS(x) (&x)
90 #define VALPARM(y) va_list *y
91 #define VALST(z) (*z)
92 #endif
93
94
95 /***********************************************************************
96 * Definitions of data structures. These are not visible to the external
97 * world -- they may be accessed only via the functions declared in
98 * octstr.h. This ensures they really are abstract.
99 */
100
101 /*
102 * The octet string.
103 *
104 * `data' is a pointer to dynamically allocated memory are where the
105 * octets in the string. It may be bigger than the actual length of the
106 * string.
107 *
108 * `len' is the length of the string.
109 *
110 * `size' is the size of the memory area `data' points at.
111 *
112 * When `size' is greater than zero, it is at least `len+1', and the
113 * character at `len' is '\0'. This is so that octstr_get_cstr will
114 * always work.
115 *
116 * `immutable' defines whether the octet string is immutable or not.
117 */
118 struct Octstr
119 {
120 unsigned char *data;
121 long len;
122 long size;
123 int immutable;
124 };
125
126
127 /**********************************************************************
128 * Hash table of immutable octet strings.
129 */
130
131 #define MAX_IMMUTABLES 1024
132
133 static Octstr *immutables[MAX_IMMUTABLES];
134 static Mutex immutables_mutex;
135 static int immutables_init = 0;
136
137 static char is_safe[UCHAR_MAX + 1];
138
139 /*
140 * Convert a pointer to a C string literal to a long that can be used
141 * for hashing. This is done by converting the pointer into an integer
142 * and discarding the lowest to bits to get rid of typical alignment
143 * bits.
144 */
145 #define CSTR_TO_LONG(ptr) (((unsigned long) ptr) >> 2)
146
147
148 /*
149 * HEX to ASCII preprocessor macro
150 */
151 #define H2B(a) (a >= '0' && a <= '9' ? \
152 a - '0' : (a >= 'a' && a <= 'f' ? \
153 a - 'a' + 10 : (a >= 'A' && a <= 'F' ? a - 'A' + 10 : -1) \
154 ) \
155 )
156
157
158 /***********************************************************************
159 * Declarations of internal functions. These are defined at the end of
160 * the file.
161 */
162
163
164 static void seems_valid_real(const Octstr *ostr, const char *filename, long lineno,
165 const char *function);
166 #ifdef NO_GWASSERT
167 #define seems_valid(ostr)
168 #else
169 #define seems_valid(ostr) \
170 (seems_valid_real(ostr, __FILE__, __LINE__, __func__))
171 #endif
172
173
174 /***********************************************************************
175 * Implementations of the functions declared in octstr.h. See the
176 * header for explanations of what they should do.
177 */
178
179
180 /* Reserve space for at least 'size' octets */
octstr_grow(Octstr * ostr,long size)181 static void octstr_grow(Octstr *ostr, long size)
182 {
183 gw_assert(!ostr->immutable);
184 seems_valid(ostr);
185 gw_assert(size >= 0);
186
187 size++; /* make room for the invisible terminating NUL */
188
189 if (size > ostr->size) {
190 /* always reallocate in 1kB chunks */
191 size += 1024 - (size % 1024);
192 ostr->data = gw_realloc(ostr->data, size);
193 ostr->size = size;
194 }
195 }
196
197
198 /*
199 * Fill is_safe table. is_safe[c] means that c can be left as such when
200 * url-encoded.
201 * RFC 2396 defines the list of characters that need to be encoded.
202 * Space is treated as an exception by the encoding routine;
203 * it's listed as safe here, but is actually changed to '+'.
204 */
urlcode_init(void)205 static void urlcode_init(void)
206 {
207 int i;
208
209 unsigned char *safe = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
210 "abcdefghijklmnopqrstuvwxyz-_.!~*'()";
211 for (i = 0; safe[i] != '\0'; ++i)
212 is_safe[safe[i]] = 1;
213 }
214
215
octstr_init(void)216 void octstr_init(void)
217 {
218 urlcode_init();
219 mutex_init_static(&immutables_mutex);
220 immutables_init = 1;
221 }
222
223
octstr_shutdown(void)224 void octstr_shutdown(void)
225 {
226 long i, n;
227
228 n = 0;
229 for (i = 0; i < MAX_IMMUTABLES; ++i) {
230 if (immutables[i] != NULL) {
231 gw_free(immutables[i]);
232 ++n;
233 }
234 }
235 if(n>0)
236 debug("gwlib.octstr", 0, "Immutable octet strings: %ld.", n);
237 mutex_destroy(&immutables_mutex);
238 }
239
240
octstr_create_real(const char * cstr,const char * file,long line,const char * func)241 Octstr *octstr_create_real(const char *cstr, const char *file, long line,
242 const char *func)
243 {
244 gw_assert(cstr != NULL);
245 return octstr_create_from_data_trace(cstr, strlen(cstr), file, line, func);
246 }
247
octstr_create_from_data_real(const char * data,long len,const char * file,long line,const char * func)248 Octstr *octstr_create_from_data_real(const char *data, long len, const char *file,
249 long line, const char *func)
250 {
251 Octstr *ostr;
252
253 gw_assert(len >= 0);
254 if (data == NULL)
255 gw_assert(len == 0);
256
257 /* if gw_assert is disabled just return NULL
258 * and caller will check for NULL or just crash.
259 */
260 if (len < 0 || (data == NULL && len != 0))
261 return NULL;
262
263 ostr = gw_malloc_trace(sizeof(*ostr), file, line, func);
264 if (len == 0) {
265 ostr->len = 0;
266 ostr->size = 0;
267 ostr->data = NULL;
268 } else {
269 ostr->len = len;
270 ostr->size = len + 1;
271 ostr->data = gw_malloc_trace(ostr->size, file, line, func);
272 memcpy(ostr->data, data, len);
273 ostr->data[len] = '\0';
274 }
275 ostr->immutable = 0;
276 seems_valid(ostr);
277 return ostr;
278 }
279
280
octstr_imm(const char * cstr)281 Octstr *octstr_imm(const char *cstr)
282 {
283 Octstr *os;
284 long i, index;
285 unsigned char *data;
286
287 gw_assert(immutables_init);
288 gw_assert(cstr != NULL);
289
290 index = CSTR_TO_LONG(cstr) % MAX_IMMUTABLES;
291 data = (unsigned char *) cstr;
292
293 mutex_lock(&immutables_mutex);
294 i = index;
295 for (; ; ) {
296 if (immutables[i] == NULL || immutables[i]->data == data)
297 break;
298 i = (i + 1) % MAX_IMMUTABLES;
299 if (i == index)
300 panic(0, "Too many immutable strings.");
301 }
302 os = immutables[i];
303 if (os == NULL) {
304 /*
305 * Can't use octstr_create() because it copies the string,
306 * which would break our hashing.
307 */
308 os = gw_malloc(sizeof(*os));
309 os->data = data;
310 os->len = strlen(data);
311 os->size = os->len + 1;
312 os->immutable = 1;
313 immutables[i] = os;
314 seems_valid(os);
315 }
316 mutex_unlock(&immutables_mutex);
317
318 return os;
319 }
320
321
octstr_destroy(Octstr * ostr)322 void octstr_destroy(Octstr *ostr)
323 {
324 if (ostr != NULL) {
325 seems_valid(ostr);
326 if (!ostr->immutable) {
327 gw_free(ostr->data);
328 gw_free(ostr);
329 }
330 }
331 }
332
333
octstr_destroy_item(void * os)334 void octstr_destroy_item(void *os)
335 {
336 octstr_destroy(os);
337 }
338
339
octstr_len(const Octstr * ostr)340 long octstr_len(const Octstr *ostr)
341 {
342 if (ostr == NULL)
343 return 0;
344 seems_valid(ostr);
345 return ostr->len;
346 }
347
348
octstr_copy_real(const Octstr * ostr,long from,long len,const char * file,long line,const char * func)349 Octstr *octstr_copy_real(const Octstr *ostr, long from, long len, const char *file, long line,
350 const char *func)
351 {
352 if (ostr == NULL)
353 return octstr_create("");
354
355 seems_valid_real(ostr, file, line, func);
356 gw_assert(from >= 0);
357 gw_assert(len >= 0);
358
359 if (from >= ostr->len)
360 return octstr_create("");
361
362 if (len > ostr->len - from)
363 len = ostr->len - from;
364
365 return octstr_create_from_data_trace(ostr->data + from, len, file,
366 line, func);
367 }
368
369
370
octstr_duplicate_real(const Octstr * ostr,const char * file,long line,const char * func)371 Octstr *octstr_duplicate_real(const Octstr *ostr, const char *file, long line,
372 const char *func)
373 {
374 if (ostr == NULL)
375 return NULL;
376 seems_valid_real(ostr, file, line, func);
377 return octstr_create_from_data_trace(ostr->data, ostr->len, file, line, func);
378 }
379
380
octstr_cat(Octstr * ostr1,Octstr * ostr2)381 Octstr *octstr_cat(Octstr *ostr1, Octstr *ostr2)
382 {
383 Octstr *ostr;
384
385 seems_valid(ostr1);
386 seems_valid(ostr2);
387 gw_assert(!ostr1->immutable);
388
389 ostr = octstr_create("");
390 ostr->len = ostr1->len + ostr2->len;
391 ostr->size = ostr->len + 1;
392 ostr->data = gw_malloc(ostr->size);
393
394 if (ostr1->len > 0)
395 memcpy(ostr->data, ostr1->data, ostr1->len);
396 if (ostr2->len > 0)
397 memcpy(ostr->data + ostr1->len, ostr2->data, ostr2->len);
398 ostr->data[ostr->len] = '\0';
399
400 seems_valid(ostr);
401 return ostr;
402 }
403
404
octstr_get_char(const Octstr * ostr,long pos)405 int octstr_get_char(const Octstr *ostr, long pos)
406 {
407 seems_valid(ostr);
408 if (pos >= ostr->len || pos < 0)
409 return -1;
410 return ostr->data[pos];
411 }
412
413
octstr_set_char(Octstr * ostr,long pos,int ch)414 void octstr_set_char(Octstr *ostr, long pos, int ch)
415 {
416 seems_valid(ostr);
417 gw_assert(!ostr->immutable);
418 if (pos < ostr->len)
419 ostr->data[pos] = ch;
420 seems_valid(ostr);
421 }
422
423
octstr_get_many_chars(char * buf,Octstr * ostr,long pos,long len)424 void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len)
425 {
426 gw_assert(buf != NULL);
427 seems_valid(ostr);
428
429 if (pos >= ostr->len)
430 return;
431 if (pos + len > ostr->len)
432 len = ostr->len - pos;
433 if (len > 0)
434 memcpy(buf, ostr->data + pos, len);
435 }
436
437
octstr_get_cstr_real(const Octstr * ostr,const char * file,long line,const char * func)438 char *octstr_get_cstr_real(const Octstr *ostr, const char *file, long line,
439 const char *func)
440 {
441 if (!ostr)
442 return "(null)";
443 seems_valid_real(ostr, file, line, func);
444 if (ostr->len == 0)
445 return "";
446 return ostr->data;
447 }
448
449
octstr_append_from_hex(Octstr * ostr,char * hex)450 void octstr_append_from_hex(Octstr *ostr, char *hex)
451 {
452 Octstr *output;
453
454 seems_valid(ostr);
455 gw_assert(!ostr->immutable);
456
457 output = octstr_create(hex);
458 octstr_hex_to_binary(output);
459 octstr_append(ostr, output);
460 octstr_destroy(output);
461 }
462
463
octstr_binary_to_hex(Octstr * ostr,int uppercase)464 void octstr_binary_to_hex(Octstr *ostr, int uppercase)
465 {
466 unsigned char *hexits;
467 long i, tmp;
468
469 seems_valid(ostr);
470 gw_assert(!ostr->immutable);
471 if (ostr->len == 0)
472 return;
473
474 hexits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
475 octstr_grow(ostr, ostr->len * 2);
476
477 /* In-place modification must be done back-to-front to avoid
478 * overwriting the data while we read it. Even the order of
479 * the two assignments is important, to get i == 0 right. */
480 for (i = ostr->len - 1; i >= 0; i--) {
481 tmp = i << 1; /* tmp = i * 2; */
482 ostr->data[tmp + 1] = hexits[ostr->data[i] & 0xf];
483 ostr->data[tmp] = hexits[ostr->data[i] >> 4];
484 }
485
486 ostr->len = ostr->len * 2;
487 ostr->data[ostr->len] = '\0';
488
489 seems_valid(ostr);
490 }
491
492
octstr_hex_to_binary(Octstr * ostr)493 int octstr_hex_to_binary(Octstr *ostr)
494 {
495 long len, i;
496 unsigned char *p;
497
498 seems_valid(ostr);
499 gw_assert(!ostr->immutable);
500
501 if (ostr->len == 0)
502 return 0;
503
504 /* Check if it's in the right format */
505 if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit))
506 return -1;
507
508 len = ostr->len;
509
510 /* Convert ascii data to binary values */
511 for (i = 0, p = ostr->data; i < len; i++, p++) {
512 if (*p >= '0' && *p <= '9')
513 *p -= '0';
514 else if (*p >= 'a' && *p <= 'f')
515 *p = *p - 'a' + 10;
516 else if (*p >= 'A' && *p <= 'F')
517 *p = *p - 'A' + 10;
518 else {
519 /* isxdigit checked the whole string, so we should
520 * not be able to get here. */
521 gw_assert(0);
522 *p = 0;
523 }
524 }
525
526 /* De-hexing will compress data by factor of 2 */
527 len = ostr->len / 2;
528
529 for (i = 0; i < len; i++) {
530 ostr->data[i] = ostr->data[i * 2] * 16 | ostr->data[i * 2 + 1];
531 }
532
533 ostr->len = len;
534 ostr->data[len] = '\0';
535
536 seems_valid(ostr);
537 return 0;
538 }
539
540
octstr_binary_to_base64(Octstr * ostr)541 void octstr_binary_to_base64(Octstr *ostr)
542 {
543 static const unsigned char base64[64] =
544 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
545 long triplets;
546 long lines;
547 long orig_len;
548 unsigned char *data;
549 long from, to;
550 int left_on_line;
551
552 seems_valid(ostr);
553 gw_assert(!ostr->immutable);
554
555 if (ostr->len == 0) {
556 /* Always terminate with CR LF */
557 octstr_insert(ostr, octstr_imm("\015\012"), 0);
558 return;
559 }
560
561 /* The lines must be 76 characters each (or less), and each
562 * triplet will expand to 4 characters, so we can fit 19
563 * triplets on one line. We need a CR LF after each line,
564 * which will add 2 octets per 19 triplets (rounded up). */
565 triplets = (ostr->len + 2) / 3; /* round up */
566 lines = (triplets + 18) / 19;
567
568 octstr_grow(ostr, triplets * 4 + lines * 2);
569 orig_len = ostr->len;
570 data = ostr->data;
571
572 ostr->len = triplets * 4 + lines * 2;
573 data[ostr->len] = '\0';
574
575 /* This function works back-to-front, so that encoded data will
576 * not overwrite source data.
577 * from points to the start of the last triplet (which may be
578 * an odd-sized one), and to points to the start of where the
579 * last quad should go. */
580 from = (triplets - 1) * 3;
581 to = (triplets - 1) * 4 + (lines - 1) * 2;
582
583 /* First write the CR LF after the last quad */
584 data[to + 5] = 10; /* LF */
585 data[to + 4] = 13; /* CR */
586 left_on_line = triplets - ((lines - 1) * 19);
587
588 /* base64 encoding is in 3-octet units. To handle leftover
589 * octets, conceptually we have to zero-pad up to the next
590 * 6-bit unit, and pad with '=' characters for missing 6-bit
591 * units.
592 * We do it by first completing the first triplet with
593 * zero-octets, and after the loop replacing some of the
594 * result characters with '=' characters.
595 * There is enough room for this, because even with a 1 or 2
596 * octet source string, space for four octets of output
597 * will be reserved.
598 */
599 switch (orig_len % 3) {
600 case 0:
601 break;
602 case 1:
603 data[orig_len] = 0;
604 data[orig_len + 1] = 0;
605 break;
606 case 2:
607 data[orig_len + 1] = 0;
608 break;
609 }
610
611 /* Now we only have perfect triplets. */
612 while (from >= 0) {
613 long whole_triplet;
614
615 /* Add a newline, if necessary */
616 if (left_on_line == 0) {
617 to -= 2;
618 data[to + 5] = 10; /* LF */
619 data[to + 4] = 13; /* CR */
620 left_on_line = 19;
621 }
622
623 whole_triplet = (data[from] << 16) |
624 (data[from + 1] << 8) |
625 data[from + 2];
626 data[to + 3] = base64[whole_triplet % 64];
627 data[to + 2] = base64[(whole_triplet >> 6) % 64];
628 data[to + 1] = base64[(whole_triplet >> 12) % 64];
629 data[to] = base64[(whole_triplet >> 18) % 64];
630
631 to -= 4;
632 from -= 3;
633 left_on_line--;
634 }
635
636 gw_assert(left_on_line == 0);
637 gw_assert(from == -3);
638 gw_assert(to == -4);
639
640 /* Insert padding characters in the last quad. Remember that
641 * there is a CR LF between the last quad and the end of the
642 * string. */
643 switch (orig_len % 3) {
644 case 0:
645 break;
646 case 1:
647 gw_assert(data[ostr->len - 3] == 'A');
648 gw_assert(data[ostr->len - 4] == 'A');
649 data[ostr->len - 3] = '=';
650 data[ostr->len - 4] = '=';
651 break;
652 case 2:
653 gw_assert(data[ostr->len - 3] == 'A');
654 data[ostr->len - 3] = '=';
655 break;
656 }
657
658 seems_valid(ostr);
659 }
660
661
octstr_base64_to_binary(Octstr * ostr)662 void octstr_base64_to_binary(Octstr *ostr)
663 {
664 long triplet;
665 long pos, len;
666 long to;
667 int quadpos = 0;
668 int warned = 0;
669 unsigned char *data;
670
671 seems_valid(ostr);
672 gw_assert(!ostr->immutable);
673
674 len = ostr->len;
675 data = ostr->data;
676
677 if (len == 0)
678 return;
679
680 to = 0;
681 triplet = 0;
682 quadpos = 0;
683 for (pos = 0; pos < len; pos++) {
684 int c = data[pos];
685 int sixbits;
686
687 if (c >= 'A' && c <= 'Z') {
688 sixbits = c - 'A';
689 } else if (c >= 'a' && c <= 'z') {
690 sixbits = 26 + c - 'a';
691 } else if (c >= '0' && c <= '9') {
692 sixbits = 52 + c - '0';
693 } else if (c == '+') {
694 sixbits = 62;
695 } else if (c == '/') {
696 sixbits = 63;
697 } else if (c == '=') {
698 /* These can only occur at the end of encoded
699 * text. RFC 2045 says we can assume it really
700 * is the end. */
701 break;
702 } else if (isspace(c)) {
703 /* skip whitespace */
704 continue;
705 } else {
706 if (!warned) {
707 warning(0, "Unusual characters in base64 "
708 "encoded text.");
709 warned = 1;
710 }
711 continue;
712 }
713
714 triplet = (triplet << 6) | sixbits;
715 quadpos++;
716
717 if (quadpos == 4) {
718 data[to++] = (triplet >> 16) & 0xff;
719 data[to++] = (triplet >> 8) & 0xff;
720 data[to++] = triplet & 0xff;
721 quadpos = 0;
722 }
723 }
724
725 /* Deal with leftover octets */
726 switch (quadpos) {
727 case 0:
728 break;
729 case 3: /* triplet has 18 bits, we want the first 16 */
730 data[to++] = (triplet >> 10) & 0xff;
731 data[to++] = (triplet >> 2) & 0xff;
732 break;
733 case 2: /* triplet has 12 bits, we want the first 8 */
734 data[to++] = (triplet >> 4) & 0xff;
735 break;
736 case 1:
737 warning(0, "Bad padding in base64 encoded text.");
738 break;
739 }
740
741 ostr->len = to;
742 data[to] = '\0';
743
744 seems_valid(ostr);
745 }
746
747
octstr_parse_long(long * nump,Octstr * ostr,long pos,int base)748 long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
749 {
750 /* strtol wants a char *, and we have to compare the result to
751 * an unsigned char *. The easiest way to avoid warnings without
752 * introducing typecasts is to use two variables. */
753 char *endptr;
754 unsigned char *endpos;
755 long number;
756
757 seems_valid(ostr);
758 gw_assert(nump != NULL);
759 gw_assert(base == 0 || (base >= 2 && base <= 36));
760
761 if (pos >= ostr->len) {
762 errno = EINVAL;
763 return -1;
764 }
765
766 errno = 0;
767 number = strtol(ostr->data + pos, &endptr, base);
768 endpos = endptr;
769 if (errno == ERANGE)
770 return -1;
771 if (endpos == ostr->data + pos) {
772 errno = EINVAL;
773 return -1;
774 }
775
776 *nump = number;
777 return endpos - ostr->data;
778 }
779
780
octstr_parse_double(double * nump,Octstr * ostr,long pos)781 long octstr_parse_double(double *nump, Octstr *ostr, long pos)
782 {
783 /* strtod wants a char *, and we have to compare the result to
784 * an unsigned char *. The easiest way to avoid warnings without
785 * introducing typecasts is to use two variables. */
786 char *endptr;
787 unsigned char *endpos;
788 double number;
789
790 seems_valid(ostr);
791 gw_assert(nump != NULL);
792
793 if (pos >= ostr->len) {
794 errno = EINVAL;
795 return -1;
796 }
797
798 errno = 0;
799 number = strtod(ostr->data + pos, &endptr);
800 endpos = endptr;
801 if (errno == ERANGE)
802 return -1;
803 if (endpos == ostr->data + pos) {
804 errno = EINVAL;
805 return -1;
806 }
807
808 *nump = number;
809 return endpos - ostr->data;
810 }
811
812
octstr_check_range(Octstr * ostr,long pos,long len,octstr_func_t filter)813 int octstr_check_range(Octstr *ostr, long pos, long len,
814 octstr_func_t filter)
815 {
816 long end = pos + len;
817
818 seems_valid(ostr);
819 gw_assert(len >= 0);
820
821 if (pos >= ostr->len)
822 return 1;
823 if (end > ostr->len)
824 end = ostr->len;
825
826 for ( ; pos < end; pos++) {
827 if (!filter(ostr->data[pos]))
828 return 0;
829 }
830
831 return 1;
832 }
833
834
octstr_convert_range(Octstr * ostr,long pos,long len,octstr_func_t map)835 void octstr_convert_range(Octstr *ostr, long pos, long len,
836 octstr_func_t map)
837 {
838 long end = pos + len;
839
840 seems_valid(ostr);
841 gw_assert(!ostr->immutable);
842 gw_assert(len >= 0);
843
844 if (pos >= ostr->len)
845 return;
846 if (end > ostr->len)
847 end = ostr->len;
848
849 for ( ; pos < end; pos++) {
850 ostr->data[pos] = map(ostr->data[pos]);
851 }
852
853 seems_valid(ostr);
854 }
855
856
make_printable(int c)857 static int inline make_printable(int c)
858 {
859 return isprint(c) ? c : '.';
860 }
861
862
octstr_convert_printable(Octstr * ostr)863 void octstr_convert_printable(Octstr *ostr)
864 {
865 octstr_convert_range(ostr, 0, ostr->len, make_printable);
866 }
867
868
869
octstr_compare(const Octstr * ostr1,const Octstr * ostr2)870 int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
871 {
872 int ret;
873 long len;
874
875 seems_valid(ostr1);
876 seems_valid(ostr2);
877
878 if (ostr1->len < ostr2->len)
879 len = ostr1->len;
880 else
881 len = ostr2->len;
882
883 if (len == 0) {
884 if (ostr1->len == 0 && ostr2->len > 0)
885 return -1;
886 if (ostr1->len > 0 && ostr2->len == 0)
887 return 1;
888 return 0;
889 }
890
891 ret = memcmp(ostr1->data, ostr2->data, len);
892 if (ret == 0) {
893 if (ostr1->len < ostr2->len)
894 ret = -1;
895 else if (ostr1->len > ostr2->len)
896 ret = 1;
897 }
898 return ret;
899 }
900
901
octstr_case_compare(const Octstr * os1,const Octstr * os2)902 int octstr_case_compare(const Octstr *os1, const Octstr *os2)
903 {
904 int c1, c2;
905 long i, len;
906
907 seems_valid(os1);
908 seems_valid(os2);
909
910 if (os1->len < os2->len)
911 len = os1->len;
912 else
913 len = os2->len;
914
915 if (len == 0) {
916 if (os1->len == 0 && os2->len > 0)
917 return -1;
918 if (os1->len > 0 && os2->len == 0)
919 return 1;
920 return 0;
921 }
922
923 c1 = c2 = 0;
924 for (i = 0; i < len; ++i) {
925 c1 = toupper(os1->data[i]);
926 c2 = toupper(os2->data[i]);
927 if (c1 != c2)
928 break;
929 }
930
931 if (i == len) {
932 if (i == os1->len && i == os2->len)
933 return 0;
934 if (i == os1->len)
935 return -1;
936 return 1;
937 } else {
938 /*
939 c1 = toupper(os1->data[i]);
940 c2 = toupper(os2->data[i]);
941 */
942 if (c1 < c2)
943 return -1;
944 if (c1 == c2)
945 return 0;
946 return 1;
947 }
948 }
949
950
octstr_ncompare(const Octstr * ostr1,const Octstr * ostr2,long n)951 int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
952 {
953 long len;
954
955 seems_valid(ostr1);
956 seems_valid(ostr2);
957
958 if ((ostr1->len < ostr2->len) && (ostr1->len < n))
959 len = ostr1->len;
960 else if ((ostr2->len < ostr1->len) && (ostr2->len < n))
961 len = ostr2->len;
962 else
963 len = n;
964
965 if (len == 0)
966 return 0;
967
968 return memcmp(ostr1->data, ostr2->data, len);
969 }
970
971
octstr_str_compare(const Octstr * ostr,const char * str)972 int octstr_str_compare(const Octstr *ostr, const char *str)
973 {
974 seems_valid(ostr);
975
976 if (str == NULL)
977 return -1;
978 if (ostr->data == NULL)
979 return strcmp("", str);
980
981 return strcmp(ostr->data, str);
982 }
983
984
octstr_str_case_compare(const Octstr * ostr,const char * str)985 int octstr_str_case_compare(const Octstr *ostr, const char *str)
986 {
987 seems_valid(ostr);
988
989 if (str == NULL)
990 return -1;
991 if (ostr->data == NULL)
992 return strcasecmp("", str);
993
994 return strcasecmp(ostr->data, str);
995 }
996
997
octstr_str_ncompare(const Octstr * ostr,const char * str,long n)998 int octstr_str_ncompare(const Octstr *ostr, const char *str, long n)
999 {
1000 seems_valid(ostr);
1001
1002 if (str == NULL)
1003 return -1;
1004 if (ostr->data == NULL)
1005 return 1; /* str grater */
1006
1007 return strncmp(ostr->data, str, n);
1008 }
1009
1010
octstr_search_char(const Octstr * ostr,int ch,long pos)1011 long octstr_search_char(const Octstr *ostr, int ch, long pos)
1012 {
1013 unsigned char *p;
1014
1015 seems_valid(ostr);
1016 gw_assert(ch >= 0);
1017 gw_assert(ch <= UCHAR_MAX);
1018 gw_assert(pos >= 0);
1019
1020 if (pos >= ostr->len)
1021 return -1;
1022
1023 p = memchr(ostr->data + pos, ch, ostr->len - pos);
1024 if (!p)
1025 return -1;
1026 return p - ostr->data;
1027 }
1028
1029
octstr_rsearch_char(const Octstr * ostr,int ch,long pos)1030 long octstr_rsearch_char(const Octstr *ostr, int ch, long pos)
1031 {
1032 long i;
1033
1034 seems_valid(ostr);
1035 gw_assert(ch >= 0);
1036 gw_assert(ch <= UCHAR_MAX);
1037 gw_assert(pos >= 0);
1038
1039 if (pos >= ostr->len)
1040 return -1;
1041
1042 for (i = pos; i >= 0; i--) {
1043 if (ostr->data[i] == ch)
1044 return i;
1045 }
1046
1047 return -1;
1048 }
1049
1050
octstr_search_chars(const Octstr * ostr,const Octstr * chars,long pos)1051 long octstr_search_chars(const Octstr *ostr, const Octstr *chars, long pos)
1052 {
1053 long i, j;
1054
1055 seems_valid(ostr);
1056 seems_valid(chars);
1057 gw_assert(pos >= 0);
1058
1059 for (i = 0; i < octstr_len(chars); i++) {
1060 j = octstr_search_char(ostr, octstr_get_char(chars, i), pos);
1061 if (j != -1)
1062 return j;
1063 }
1064
1065 return -1;
1066 }
1067
1068
octstr_search(const Octstr * haystack,const Octstr * needle,long pos)1069 long octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
1070 {
1071 int first;
1072
1073 seems_valid(haystack);
1074 seems_valid(needle);
1075 gw_assert(pos >= 0);
1076
1077 /* Always "find" an empty string */
1078 if (needle->len == 0)
1079 return 0;
1080
1081 if (needle->len == 1)
1082 return octstr_search_char(haystack, needle->data[0], pos);
1083
1084 /* For each occurrence of needle's first character in ostr,
1085 * check if the rest of needle follows. Stop if there are no
1086 * more occurrences, or if the rest of needle can't possibly
1087 * fit in the haystack. */
1088 first = needle->data[0];
1089 pos = octstr_search_char(haystack, first, pos);
1090 while (pos >= 0 && haystack->len - pos >= needle->len) {
1091 if (memcmp(haystack->data + pos,
1092 needle->data, needle->len) == 0)
1093 return pos;
1094 pos = octstr_search_char(haystack, first, pos + 1);
1095 }
1096
1097 return -1;
1098 }
1099
1100
octstr_case_search(const Octstr * haystack,const Octstr * needle,long pos)1101 long octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos)
1102 {
1103 long i, j;
1104 int c1, c2;
1105
1106 seems_valid(haystack);
1107 seems_valid(needle);
1108 gw_assert(pos >= 0);
1109
1110 /* Always "find" an empty string */
1111 if (needle->len == 0)
1112 return 0;
1113
1114 for (i = pos; i <= haystack->len - needle->len; ++i) {
1115 for (j = 0; j < needle->len; ++j) {
1116 c1 = toupper(haystack->data[i + j]);
1117 c2 = toupper(needle->data[j]);
1118 if (c1 != c2)
1119 break;
1120 }
1121 if (j == needle->len)
1122 return i;
1123 }
1124
1125 return -1;
1126 }
1127
octstr_case_nsearch(const Octstr * haystack,const Octstr * needle,long pos,long n)1128 long octstr_case_nsearch(const Octstr *haystack, const Octstr *needle, long pos, long n)
1129 {
1130 long i, j;
1131 int c1, c2;
1132
1133 seems_valid(haystack);
1134 seems_valid(needle);
1135 gw_assert(pos >= 0);
1136
1137 /* Always "find" an empty string */
1138 if (needle->len == 0)
1139 return 0;
1140
1141 for (i = pos; i <= haystack->len - needle->len && i < n; ++i) {
1142 for (j = 0; j < needle->len && j < n; ++j) {
1143 c1 = toupper(haystack->data[i + j]);
1144 c2 = toupper(needle->data[j]);
1145 if (c1 != c2)
1146 break;
1147 }
1148 if (j == needle->len)
1149 return i;
1150 }
1151
1152 return -1;
1153 }
1154
1155
octstr_str_search(const Octstr * haystack,const char * needle,long pos)1156 long octstr_str_search(const Octstr *haystack, const char *needle, long pos)
1157 {
1158 int first;
1159 int needle_len;
1160
1161 seems_valid(haystack);
1162 gw_assert(pos >= 0);
1163
1164 /* Always "find" an empty string */
1165 if (needle == NULL || needle[0] == '\0')
1166 return 0;
1167
1168 needle_len = strlen(needle);
1169
1170 if (needle_len == 1)
1171 return octstr_search_char(haystack, needle[0], pos);
1172
1173 /* For each occurrence of needle's first character in ostr,
1174 * check if the rest of needle follows. Stop if there are no
1175 * more occurrences, or if the rest of needle can't possibly
1176 * fit in the haystack. */
1177 first = needle[0];
1178 pos = octstr_search_char(haystack, first, pos);
1179 while (pos >= 0 && haystack->len - pos >= needle_len) {
1180 if (memcmp(haystack->data + pos,
1181 needle, needle_len) == 0)
1182 return pos;
1183 pos = octstr_search_char(haystack, first, pos + 1);
1184 }
1185
1186 return -1;
1187 }
1188
1189
octstr_print(FILE * f,Octstr * ostr)1190 int octstr_print(FILE *f, Octstr *ostr)
1191 {
1192 gw_assert(f != NULL);
1193 seems_valid(ostr);
1194
1195 if (ostr->len == 0)
1196 return 0;
1197 if (fwrite(ostr->data, ostr->len, 1, f) != 1) {
1198 error(errno, "Couldn't write all of octet string to file.");
1199 return -1;
1200 }
1201 return 0;
1202 }
1203
1204
octstr_pretty_print(FILE * f,Octstr * ostr)1205 int octstr_pretty_print(FILE *f, Octstr *ostr)
1206 {
1207 unsigned char *p;
1208 long i;
1209
1210 gw_assert(f != NULL);
1211 seems_valid(ostr);
1212
1213 p = ostr->data;
1214 for (i = 0; i < ostr->len; ++i, ++p) {
1215 if (isprint(*p))
1216 fprintf(f, "%c", *p);
1217 else
1218 fprintf(f, "\\x%02x", *p);
1219 }
1220 if (ferror(f))
1221 return -1;
1222 return 0;
1223 }
1224
1225
octstr_write_to_socket(int socket,Octstr * ostr)1226 int octstr_write_to_socket(int socket, Octstr *ostr)
1227 {
1228 long len;
1229 unsigned char *data;
1230 int ret;
1231
1232 gw_assert(socket >= 0);
1233 seems_valid(ostr);
1234
1235 data = ostr->data;
1236 len = ostr->len;
1237 while (len > 0) {
1238 ret = write(socket, data, len);
1239 if (ret == -1) {
1240 if (errno != EINTR) {
1241 error(errno, "Writing to socket failed");
1242 return -1;
1243 }
1244 } else {
1245 /* ret may be less than len */
1246 len -= ret;
1247 data += ret;
1248 }
1249 }
1250 return 0;
1251 }
1252
1253
octstr_write_data(Octstr * ostr,int fd,long from)1254 long octstr_write_data(Octstr *ostr, int fd, long from)
1255 {
1256 long ret;
1257
1258 gw_assert(fd >= 0);
1259 gw_assert(from >= 0);
1260 seems_valid(ostr);
1261
1262 if (from >= ostr->len)
1263 return 0;
1264
1265 ret = write(fd, ostr->data + from, ostr->len - from);
1266
1267 if (ret < 0) {
1268 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
1269 return 0;
1270 error(errno, "Error writing %ld octets to fd %d:",
1271 ostr->len - from, fd);
1272 return -1;
1273 }
1274
1275 return ret;
1276 }
1277
1278
octstr_append_from_socket(Octstr * ostr,int socket)1279 int octstr_append_from_socket(Octstr *ostr, int socket)
1280 {
1281 unsigned char buf[4096];
1282 int len;
1283
1284 seems_valid(ostr);
1285 gw_assert(!ostr->immutable);
1286
1287 again:
1288 len = recv(socket, buf, sizeof(buf), 0);
1289 if (len < 0 && errno == EINTR)
1290 goto again;
1291
1292 if (len < 0) {
1293 error(errno, "Could not read from socket %d", socket);
1294 return -1;
1295 }
1296
1297 octstr_append_data(ostr, buf, len);
1298 return len;
1299 }
1300
1301
octstr_insert(Octstr * ostr1,const Octstr * ostr2,long pos)1302 void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
1303 {
1304 if (ostr2 == NULL)
1305 return;
1306
1307 seems_valid(ostr1);
1308 seems_valid(ostr2);
1309 gw_assert(pos <= ostr1->len);
1310 gw_assert(!ostr1->immutable);
1311
1312 if (ostr2->len == 0)
1313 return;
1314
1315 octstr_grow(ostr1, ostr1->len + ostr2->len);
1316 memmove(ostr1->data + pos + ostr2->len, ostr1->data + pos,
1317 ostr1->len - pos);
1318 memcpy(ostr1->data + pos, ostr2->data, ostr2->len);
1319 ostr1->len += ostr2->len;
1320 ostr1->data[ostr1->len] = '\0';
1321
1322 seems_valid(ostr1);
1323 }
1324
1325
octstr_truncate(Octstr * ostr,int new_len)1326 void octstr_truncate(Octstr *ostr, int new_len)
1327 {
1328 if (ostr == NULL)
1329 return;
1330
1331 seems_valid(ostr);
1332 gw_assert(!ostr->immutable);
1333 gw_assert(new_len >= 0);
1334
1335 if (new_len >= ostr->len)
1336 return;
1337
1338 ostr->len = new_len;
1339 ostr->data[new_len] = '\0';
1340
1341 seems_valid(ostr);
1342 }
1343
1344
octstr_strip_blanks(Octstr * text)1345 void octstr_strip_blanks(Octstr *text)
1346 {
1347 int start = 0, end, len = 0;
1348
1349 seems_valid(text);
1350 gw_assert(!text->immutable);
1351
1352 /* Remove white space from the beginning of the text */
1353 while (isspace(octstr_get_char(text, start)) &&
1354 start <= octstr_len(text))
1355 start ++;
1356
1357 if (start > 0)
1358 octstr_delete(text, 0, start);
1359
1360 /* and from the end. */
1361
1362 if ((len = octstr_len(text)) > 0) {
1363 end = len = len - 1;
1364 while (isspace(octstr_get_char(text, end)) && end >= 0)
1365 end--;
1366 octstr_delete(text, end + 1, len - end);
1367 }
1368
1369 seems_valid(text);
1370 }
1371
iscrlf(unsigned char c)1372 static int iscrlf(unsigned char c)
1373 {
1374 return c == '\n' || c == '\r';
1375 }
1376
octstr_strip_crlfs(Octstr * text)1377 void octstr_strip_crlfs(Octstr *text)
1378 {
1379 int start = 0, end, len = 0;
1380
1381 seems_valid(text);
1382 gw_assert(!text->immutable);
1383
1384 /* Remove white space from the beginning of the text */
1385 while (iscrlf(octstr_get_char(text, start)) &&
1386 start <= octstr_len(text))
1387 start ++;
1388
1389 if (start > 0)
1390 octstr_delete(text, 0, start);
1391
1392 /* and from the end. */
1393
1394 if ((len = octstr_len(text)) > 0) {
1395 end = len = len - 1;
1396 while (iscrlf(octstr_get_char(text, end)) && end >= 0)
1397 end--;
1398 octstr_delete(text, end + 1, len - end);
1399 }
1400
1401 seems_valid(text);
1402 }
1403
octstr_strip_nonalphanums(Octstr * text)1404 void octstr_strip_nonalphanums(Octstr *text)
1405 {
1406 int start = 0, end, len = 0;
1407
1408 seems_valid(text);
1409 gw_assert(!text->immutable);
1410
1411 /* Remove white space from the beginning of the text */
1412 while (!isalnum(octstr_get_char(text, start)) &&
1413 start <= octstr_len(text))
1414 start ++;
1415
1416 if (start > 0)
1417 octstr_delete(text, 0, start);
1418
1419 /* and from the end. */
1420
1421 if ((len = octstr_len(text)) > 0) {
1422 end = len = len - 1;
1423 while (!isalnum(octstr_get_char(text, end)) && end >= 0)
1424 end--;
1425 octstr_delete(text, end + 1, len - end);
1426 }
1427
1428 seems_valid(text);
1429 }
1430
1431
octstr_shrink_blanks(Octstr * text)1432 void octstr_shrink_blanks(Octstr *text)
1433 {
1434 int i, j, end;
1435
1436 seems_valid(text);
1437 gw_assert(!text->immutable);
1438
1439 end = octstr_len(text);
1440
1441 /* Shrink white spaces to one */
1442 for (i = 0; i < end; i++) {
1443 if (isspace(octstr_get_char(text, i))) {
1444 /* Change the remaining space into single space. */
1445 if (octstr_get_char(text, i) != ' ')
1446 octstr_set_char(text, i, ' ');
1447
1448 j = i = i + 1;
1449 while (isspace(octstr_get_char(text, j)))
1450 j ++;
1451 if (j - i > 1)
1452 octstr_delete(text, i, j - i);
1453 }
1454 }
1455
1456 seems_valid(text);
1457 }
1458
1459
octstr_insert_data(Octstr * ostr,long pos,const char * data,long len)1460 void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
1461 {
1462 seems_valid(ostr);
1463 gw_assert(!ostr->immutable);
1464 gw_assert(pos <= ostr->len);
1465
1466 if (len == 0)
1467 return;
1468
1469 octstr_grow(ostr, ostr->len + len);
1470 if (ostr->len > pos) { /* only if neccessary*/
1471 memmove(ostr->data + pos + len, ostr->data + pos, ostr->len - pos);
1472 }
1473 memcpy(ostr->data + pos, data, len);
1474 ostr->len += len;
1475 ostr->data[ostr->len] = '\0';
1476
1477 seems_valid(ostr);
1478 }
1479
octstr_insert_char(Octstr * ostr,long pos,const char c)1480 void octstr_insert_char(Octstr *ostr, long pos, const char c)
1481 {
1482 seems_valid(ostr);
1483 gw_assert(!ostr->immutable);
1484 gw_assert(pos <= ostr->len);
1485
1486 octstr_grow(ostr, ostr->len + 1);
1487 if (ostr->len > pos)
1488 memmove(ostr->data + pos + 1, ostr->data + pos, ostr->len - pos);
1489 memcpy(ostr->data + pos, &c, 1);
1490 ostr->len += 1;
1491 ostr->data[ostr->len] = '\0';
1492
1493 seems_valid(ostr);
1494 }
1495
octstr_append_data(Octstr * ostr,const char * data,long len)1496 void octstr_append_data(Octstr *ostr, const char *data, long len)
1497 {
1498 gw_assert(ostr != NULL);
1499 octstr_insert_data(ostr, ostr->len, data, len);
1500 }
1501
1502
octstr_append(Octstr * ostr1,const Octstr * ostr2)1503 void octstr_append(Octstr *ostr1, const Octstr *ostr2)
1504 {
1505 gw_assert(ostr1 != NULL);
1506 octstr_insert(ostr1, ostr2, ostr1->len);
1507 }
1508
1509
octstr_append_cstr(Octstr * ostr,const char * cstr)1510 void octstr_append_cstr(Octstr *ostr, const char *cstr)
1511 {
1512 octstr_insert_data(ostr, ostr->len, cstr, strlen(cstr));
1513 }
1514
1515
octstr_append_char(Octstr * ostr,int ch)1516 void octstr_append_char(Octstr *ostr, int ch)
1517 {
1518 unsigned char c = ch;
1519
1520 gw_assert(ch >= 0);
1521 gw_assert(ch <= UCHAR_MAX);
1522 octstr_insert_data(ostr, ostr->len, &c, 1);
1523 }
1524
1525
octstr_delete(Octstr * ostr1,long pos,long len)1526 void octstr_delete(Octstr *ostr1, long pos, long len)
1527 {
1528 seems_valid(ostr1);
1529 gw_assert(!ostr1->immutable);
1530
1531 if (pos > ostr1->len)
1532 pos = ostr1->len;
1533 if (pos + len > ostr1->len)
1534 len = ostr1->len - pos;
1535 if (len > 0) {
1536 memmove(ostr1->data + pos, ostr1->data + pos + len,
1537 ostr1->len - pos - len);
1538 ostr1->len -= len;
1539 ostr1->data[ostr1->len] = '\0';
1540 }
1541
1542 seems_valid(ostr1);
1543 }
1544
1545
1546
octstr_read_file(const char * filename)1547 Octstr *octstr_read_file(const char *filename)
1548 {
1549 FILE *f;
1550 Octstr *os;
1551 char buf[4096];
1552 long n;
1553
1554 gw_assert(filename != NULL);
1555
1556 f = fopen(filename, "r");
1557 if (f == NULL) {
1558 error(errno, "fopen failed: couldn't open `%s'", filename);
1559 return NULL;
1560 }
1561
1562 os = octstr_create("");
1563 if (os == NULL)
1564 goto error;
1565
1566 while ((n = fread(buf, 1, sizeof(buf), f)) > 0)
1567 octstr_insert_data(os, octstr_len(os), buf, n);
1568
1569 (void) fclose(f);
1570 return os;
1571
1572 error:
1573 (void) fclose(f);
1574 octstr_destroy(os);
1575 return NULL;
1576 }
1577
1578
octstr_read_pipe(FILE * f)1579 Octstr *octstr_read_pipe(FILE *f)
1580 {
1581 Octstr *os;
1582 char buf[4096];
1583
1584 gw_assert(f != NULL);
1585
1586 os = octstr_create("");
1587 if (os == NULL)
1588 goto error;
1589
1590 while (fgets(buf, sizeof(buf), f) != NULL)
1591 octstr_append_data(os, buf, strlen(buf));
1592
1593 return os;
1594
1595 error:
1596 octstr_destroy(os);
1597 return NULL;
1598 }
1599
1600
octstr_split_words(const Octstr * ostr)1601 List *octstr_split_words(const Octstr *ostr)
1602 {
1603 unsigned char *p;
1604 List *list;
1605 Octstr *word;
1606 long i, start, end;
1607
1608 seems_valid(ostr);
1609
1610 list = gwlist_create();
1611
1612 p = ostr->data;
1613 i = 0;
1614 for (; ; ) {
1615 while (i < ostr->len && isspace(*p)) {
1616 ++p;
1617 ++i;
1618 }
1619 start = i;
1620
1621 while (i < ostr->len && !isspace(*p)) {
1622 ++p;
1623 ++i;
1624 }
1625 end = i;
1626
1627 if (start == end)
1628 break;
1629
1630 word = octstr_create_from_data(ostr->data + start,
1631 end - start);
1632 gwlist_append(list, word);
1633 }
1634
1635 return list;
1636 }
1637
1638
octstr_split(const Octstr * os,const Octstr * sep)1639 List *octstr_split(const Octstr *os, const Octstr *sep)
1640 {
1641 List *list;
1642 long next, pos, seplen;
1643
1644 list = gwlist_create();
1645 pos = 0;
1646 seplen = octstr_len(sep);
1647
1648 while ((next = octstr_search(os, sep, pos)) >= 0) {
1649 gwlist_append(list, octstr_copy(os, pos, next - pos));
1650 pos = next + seplen;
1651 }
1652
1653 if (pos < octstr_len(os))
1654 gwlist_append(list, octstr_copy(os, pos, octstr_len(os)));
1655
1656 return list;
1657 }
1658
1659
octstr_item_match(void * item,void * pattern)1660 int octstr_item_match(void *item, void *pattern)
1661 {
1662 return octstr_compare(item, pattern) == 0;
1663 }
1664
1665
octstr_item_case_match(void * item,void * pattern)1666 int octstr_item_case_match(void *item, void *pattern)
1667 {
1668 return octstr_case_compare(item, pattern) == 0;
1669 }
1670
1671
octstr_url_encode(Octstr * ostr)1672 void octstr_url_encode(Octstr *ostr)
1673 {
1674 long i, n, len = 0;
1675 int all_safe;
1676 unsigned char c, *str, *str2, *res, *hexits;
1677
1678 if (ostr == NULL)
1679 return;
1680
1681 seems_valid(ostr);
1682 gw_assert(!ostr->immutable);
1683
1684 if (ostr->len == 0)
1685 return;
1686
1687 /* calculate new length */
1688 for (i = n = 0, str = ostr->data, all_safe = 1; i < ostr->len; i++) {
1689 c = *str++;
1690
1691 if (c == ' ') {
1692 all_safe = 0;
1693 continue;
1694 }
1695
1696 if (!is_safe[c]) {
1697 n++;
1698 all_safe = 0;
1699 }
1700 }
1701
1702 if (all_safe) /* we are done, all chars are safe */
1703 return;
1704
1705 hexits = "0123456789ABCDEF";
1706
1707 /*
1708 * no need to reallocate if n == 0, so we make replace in place.
1709 * NOTE: we don't do if (xxx) ... else ... because conditional jump
1710 * is not so fast as just compare (alex).
1711 */
1712 res = str2 = (n ? gw_malloc((len = ostr->len + 2 * n + 1)) : ostr->data);
1713
1714 for (i = 0, str = ostr->data; i < ostr->len; i++) {
1715 c = *str++;
1716
1717 if (c == ' ') {
1718 *str2++ = '+';
1719 continue;
1720 }
1721
1722 if (!is_safe[c]) {
1723 *str2++ = '%';
1724 *str2++ = hexits[c >> 4 & 0xf];
1725 *str2++ = hexits[c & 0xf];
1726 continue;
1727 }
1728
1729 *str2++ = c;
1730 }
1731 *str2 = 0;
1732
1733 /* we made replace in place */
1734 if (n) {
1735 gw_free(ostr->data);
1736 ostr->data = res;
1737 ostr->size = len;
1738 ostr->len = len - 1;
1739 }
1740
1741 seems_valid(ostr);
1742 }
1743
1744
octstr_url_decode(Octstr * ostr)1745 int octstr_url_decode(Octstr *ostr)
1746 {
1747 unsigned char *string;
1748 unsigned char *dptr;
1749 int code, code2, ret = 0;
1750
1751 if (ostr == NULL)
1752 return 0;
1753
1754 seems_valid(ostr);
1755 gw_assert(!ostr->immutable);
1756
1757 if (ostr->len == 0)
1758 return 0;
1759
1760 string = ostr->data;
1761 dptr = ostr->data;
1762
1763 do {
1764 if (*string == '%') {
1765 if (*(string + 1) == '\0' || *(string + 2) == '\0') {
1766 warning(0, "octstr_url_decode: corrupted end-of-string <%s>", string);
1767 ret = -1;
1768 break;
1769 }
1770
1771 code = H2B(*(string + 1));
1772 code2 = H2B(*(string + 2));
1773
1774 if (code == -1 || code2 == -1) {
1775 warning(0, "octstr_url_decode: garbage detected (%c%c%c) skipping.",
1776 *string, *(string + 1), *(string + 2));
1777 *dptr++ = *string++;
1778 *dptr++ = *string++;
1779 *dptr++ = *string++;
1780 ret = -1;
1781 continue;
1782 }
1783
1784 *dptr++ = code << 4 | code2;
1785 string += 3;
1786 }
1787 else if (*string == '+') {
1788 *dptr++ = ' ';
1789 string++;
1790 } else
1791 *dptr++ = *string++;
1792 } while (*string); /* we stop here because it terimates encoded string */
1793
1794 *dptr = '\0';
1795 ostr->len = (dptr - ostr->data);
1796
1797 seems_valid(ostr);
1798 return ret;
1799 }
1800
1801
octstr_get_bits(Octstr * ostr,long bitpos,int numbits)1802 long octstr_get_bits(Octstr *ostr, long bitpos, int numbits)
1803 {
1804 long pos;
1805 long result;
1806 int mask;
1807 int shiftwidth;
1808
1809 seems_valid(ostr);
1810 gw_assert(bitpos >= 0);
1811 gw_assert(numbits <= 32);
1812 gw_assert(numbits >= 0);
1813
1814 pos = bitpos / 8;
1815 bitpos = bitpos % 8;
1816
1817 /* This also takes care of the len == 0 case */
1818 if (pos >= ostr->len)
1819 return 0;
1820
1821 mask = (1 << numbits) - 1;
1822
1823 /* It's easy if the range fits in one octet */
1824 if (bitpos + numbits <= 8) {
1825 /* shiftwidth is the number of bits to ignore on the right.
1826 * bitpos 0 is the leftmost bit. */
1827 shiftwidth = 8 - (bitpos + numbits);
1828 return (ostr->data[pos] >> shiftwidth) & mask;
1829 }
1830
1831 /* Otherwise... */
1832 result = 0;
1833 while (bitpos + numbits > 8) {
1834 result = (result << 8) | ostr->data[pos];
1835 numbits -= (8 - bitpos);
1836 bitpos = 0;
1837 pos++;
1838 if (pos >= ostr->len)
1839 return (result << numbits) & mask;
1840 }
1841
1842 gw_assert(bitpos == 0);
1843 result <<= numbits;
1844 result |= ostr->data[pos] >> (8 - numbits);
1845 return result & mask;
1846 }
1847
octstr_set_bits(Octstr * ostr,long bitpos,int numbits,unsigned long value)1848 void octstr_set_bits(Octstr *ostr, long bitpos, int numbits,
1849 unsigned long value)
1850 {
1851 long pos;
1852 unsigned long mask;
1853 int shiftwidth;
1854 int bits;
1855 int maxlen;
1856 int c;
1857
1858 seems_valid(ostr);
1859 gw_assert(!ostr->immutable);
1860 gw_assert(bitpos >= 0);
1861 gw_assert(numbits <= 32);
1862 gw_assert(numbits >= 0);
1863
1864 maxlen = (bitpos + numbits + 7) / 8;
1865 if (maxlen > ostr->len) {
1866 octstr_grow(ostr, maxlen);
1867 /* Make sure the new octets start out with value 0 */
1868 for (pos = ostr->len; pos < maxlen; pos++) {
1869 ostr->data[pos] = 0;
1870 }
1871 ostr->len = maxlen;
1872 ostr->data[maxlen] = 0;
1873 }
1874
1875 mask = (1 << numbits) - 1;
1876 /* mask is also the largest value that fits */
1877 gw_assert(value <= mask);
1878
1879 pos = bitpos / 8;
1880 bitpos = bitpos % 8;
1881
1882 /* Does the range fit in one octet? */
1883 if (bitpos + numbits <= 8) {
1884 /* shiftwidth is the number of bits to ignore on the right.
1885 * bitpos 0 is the leftmost bit. */
1886 shiftwidth = 8 - (bitpos + numbits);
1887 /* Extract the bits we don't want to affect */
1888 c = ostr->data[pos] & ~(mask << shiftwidth);
1889 c |= value << shiftwidth;
1890 gw_assert(pos < ostr->len);
1891 ostr->data[pos] = c;
1892 return;
1893 }
1894
1895 /* Otherwise... */
1896 /* If speed is a problem here, we could have separate cases for
1897 * the first octet (which may have bitpos > 0), and the rest,
1898 * which don't. */
1899 while (bitpos + numbits > 8) {
1900 /* We want this many bits from the value */
1901 bits = 8 - bitpos;
1902 /* There are this many bits to their right in the value */
1903 shiftwidth = numbits - bits;
1904 /* Construct a mask for "bits" bits on the far right */
1905 mask = (1 << bits) - 1;
1906 /* Get the bits we want */
1907 c = (value >> shiftwidth) & mask;
1908 /* Merge them with the bits that are already there */
1909 gw_assert(pos < ostr->len);
1910 ostr->data[pos] = (ostr->data[pos] & ~mask) | c;
1911 numbits -= (8 - bitpos);
1912 bitpos = 0;
1913 pos++;
1914 }
1915
1916 gw_assert(bitpos == 0);
1917 gw_assert(pos < ostr->len);
1918 /* Set remaining bits. This is just like the single-octet case
1919 * before the loop, except that we know bitpos is 0. */
1920 mask = (1 << numbits) - 1;
1921 shiftwidth = 8 - numbits;
1922 c = ostr->data[pos] & ~(mask << shiftwidth);
1923 c |= value << shiftwidth;
1924 ostr->data[pos] = c;
1925
1926 seems_valid(ostr);
1927 }
1928
1929
octstr_append_uintvar(Octstr * ostr,unsigned long value)1930 void octstr_append_uintvar(Octstr *ostr, unsigned long value)
1931 {
1932 /* A uintvar is defined to be up to 32 bits large, so it will
1933 * fit in 5 octets. */
1934 unsigned char octets[5];
1935 int i;
1936 int start;
1937
1938 /* Handle last byte separately; it has no continuation bit,
1939 * and must be encoded even if value is 0. */
1940 octets[4] = value & 0x7f;
1941 value >>= 7;
1942
1943 for (i = 3; value > 0 && i >= 0; i--) {
1944 octets[i] = 0x80 | (value & 0x7f);
1945 value >>= 7;
1946 }
1947 start = i + 1;
1948
1949 octstr_append_data(ostr, octets + start, 5 - start);
1950 }
1951
1952
octstr_extract_uintvar(Octstr * ostr,unsigned long * value,long pos)1953 long octstr_extract_uintvar(Octstr *ostr, unsigned long *value, long pos)
1954 {
1955 int c;
1956 int count;
1957 unsigned long ui;
1958
1959 ui = 0;
1960 for (count = 0; count < 5; count++) {
1961 c = octstr_get_char(ostr, pos + count);
1962 if (c < 0)
1963 return -1;
1964 ui = (ui << 7) | (c & 0x7f);
1965 if (!(c & 0x80)) {
1966 *value = ui;
1967 return pos + count + 1;
1968 }
1969 }
1970
1971 return -1;
1972 }
1973
1974
octstr_append_decimal(Octstr * ostr,long value)1975 void octstr_append_decimal(Octstr *ostr, long value)
1976 {
1977 char tmp[128];
1978
1979 sprintf(tmp, "%ld", value);
1980 octstr_append_cstr(ostr, tmp);
1981 }
1982
1983
1984
1985 /**********************************************************************
1986 * octstr_dump... and related private functions
1987 */
1988
octstr_dump_debug(const Octstr * ostr,int level)1989 static void octstr_dump_debug(const Octstr *ostr, int level)
1990 {
1991 unsigned char *p, *d, buf[1024], charbuf[256];
1992 long pos;
1993 const int octets_per_line = 16;
1994 int c, this_line_begins_at;
1995
1996 if (ostr == NULL)
1997 return;
1998
1999 seems_valid(ostr);
2000
2001 debug("gwlib.octstr", 0, "%*sOctet string at %p:", level, "",
2002 (void *) ostr);
2003 debug("gwlib.octstr", 0, "%*s len: %lu", level, "",
2004 (unsigned long) ostr->len);
2005 debug("gwlib.octstr", 0, "%*s size: %lu", level, "",
2006 (unsigned long) ostr->size);
2007 debug("gwlib.octstr", 0, "%*s immutable: %d", level, "",
2008 ostr->immutable);
2009
2010 buf[0] = '\0';
2011 p = buf;
2012 d = charbuf;
2013 this_line_begins_at = 0;
2014 for (pos = 0; pos < octstr_len(ostr); ) {
2015 c = octstr_get_char(ostr, pos);
2016 sprintf(p, "%02x ", c);
2017 p = strchr(p, '\0');
2018 if (isprint(c))
2019 *d++ = c;
2020 else
2021 *d++ = '.';
2022 ++pos;
2023 if (pos - this_line_begins_at == octets_per_line) {
2024 *d = '\0';
2025 debug("gwlib.octstr", 0, "%*s data: %s %s", level, "",
2026 buf, charbuf);
2027 buf[0] = '\0';
2028 charbuf[0] = '\0';
2029 p = buf;
2030 d = charbuf;
2031 this_line_begins_at = pos;
2032 }
2033 }
2034 if (pos - this_line_begins_at > 0) {
2035 *d = '\0';
2036 debug("gwlib.octstr", 0, "%*s data: %-*.*s %s", level, "",
2037 octets_per_line*3,
2038 octets_per_line*3, buf, charbuf);
2039 }
2040
2041 debug("gwlib.octstr", 0, "%*sOctet string dump ends.", level, "");
2042 }
2043
2044
2045 /*
2046 * We do some pre-processor mangling here in order to reduce code for
2047 * the 3 log levels info(), warning() and error() that have the same
2048 * argument list.
2049 * We need to map the function calls via ## concatenation and revert
2050 * to the original function call by a define.
2051 * The do-while loop emulates a function call.
2052 */
2053
2054 #define LLinfo info
2055 #define LLwarning warning
2056 #define LLerror error
2057
2058 #define octstr_dump_LOGLEVEL(loglevel, ostr, level) \
2059 do { \
2060 unsigned char *p, *d, buf[1024], charbuf[256]; \
2061 long pos; \
2062 const int octets_per_line = 16; \
2063 int c, this_line_begins_at; \
2064 \
2065 if (ostr == NULL) \
2066 return; \
2067 \
2068 seems_valid(ostr); \
2069 \
2070 LL##loglevel(0, "%*sOctet string at %p:", level, "", \
2071 (void *) ostr); \
2072 LL##loglevel(0, "%*s len: %lu", level, "", \
2073 (unsigned long) ostr->len); \
2074 LL##loglevel(0, "%*s size: %lu", level, "", \
2075 (unsigned long) ostr->size); \
2076 LL##loglevel(0, "%*s immutable: %d", level, "", \
2077 ostr->immutable); \
2078 \
2079 buf[0] = '\0'; \
2080 p = buf; \
2081 d = charbuf; \
2082 this_line_begins_at = 0; \
2083 for (pos = 0; pos < octstr_len(ostr); ) { \
2084 c = octstr_get_char(ostr, pos); \
2085 sprintf(p, "%02x ", c); \
2086 p = strchr(p, '\0'); \
2087 if (isprint(c)) \
2088 *d++ = c; \
2089 else \
2090 *d++ = '.'; \
2091 ++pos; \
2092 if (pos - this_line_begins_at == octets_per_line) { \
2093 *d = '\0'; \
2094 LL##loglevel(0, "%*s data: %s %s", level, "", \
2095 buf, charbuf); \
2096 buf[0] = '\0'; \
2097 charbuf[0] = '\0'; \
2098 p = buf; \
2099 d = charbuf; \
2100 this_line_begins_at = pos; \
2101 } \
2102 } \
2103 if (pos - this_line_begins_at > 0) { \
2104 *d = '\0'; \
2105 LL##loglevel(0, "%*s data: %-*.*s %s", level, "", \
2106 octets_per_line*3, \
2107 octets_per_line*3, buf, charbuf); \
2108 } \
2109 \
2110 LL##loglevel(0, "%*sOctet string dump ends.", level, ""); \
2111 } while (0)
2112
2113
octstr_dump_real(const Octstr * ostr,int level,...)2114 void octstr_dump_real(const Octstr *ostr, int level, ...)
2115 {
2116 va_list p;
2117 unsigned int loglevel;
2118
2119 va_start(p, level);
2120 loglevel = va_arg(p, unsigned int);
2121 va_end(p);
2122
2123 switch (loglevel) {
2124 case GW_DEBUG:
2125 octstr_dump_debug(ostr, level);
2126 break;
2127 case GW_INFO:
2128 octstr_dump_LOGLEVEL(info, ostr, level);
2129 break;
2130 case GW_WARNING:
2131 octstr_dump_LOGLEVEL(warning, ostr, level);
2132 break;
2133 case GW_ERROR:
2134 octstr_dump_LOGLEVEL(error, ostr, level);
2135 break;
2136 default:
2137 octstr_dump_debug(ostr, level);
2138 break;
2139 }
2140 }
2141
2142
octstr_dump_short(Octstr * ostr,int level,const char * name)2143 void octstr_dump_short(Octstr *ostr, int level, const char *name)
2144 {
2145 char buf[100];
2146 char *p;
2147 long i;
2148 int c;
2149
2150 if (ostr == NULL) {
2151 debug("gwlib.octstr", 0, "%*s%s: NULL", level, "", name);
2152 return;
2153 }
2154
2155 seems_valid(ostr);
2156
2157 if (ostr->len < 20) {
2158 p = buf;
2159 for (i = 0; i < ostr->len; i++) {
2160 c = ostr->data[i];
2161 if (c == '\n') {
2162 *p++ = '\\';
2163 *p++ = 'n';
2164 } else if (!isprint(c)) {
2165 break;
2166 } else if (c == '"') {
2167 *p++ = '\\';
2168 *p++ = '"';
2169 } else if (c == '\\') {
2170 *p++ = '\\';
2171 *p++ = '\\';
2172 } else {
2173 *p++ = c;
2174 }
2175 }
2176 if (i == ostr->len) {
2177 *p++ = 0;
2178 /* We got through the loop without hitting nonprintable
2179 * characters. */
2180 debug("gwlib.octstr", 0, "%*s%s: \"%s\"", level, "", name, buf);
2181 return;
2182 }
2183 }
2184
2185 debug("gwlib.octstr", 0, "%*s%s:", level, "", name);
2186 octstr_dump(ostr, level + 1);
2187 }
2188
2189
2190 /**********************************************************************
2191 * octstr_format and related private functions
2192 */
2193
2194
2195 /*
2196 * A parsed form of the format string. This struct has been carefully
2197 * defined so that it can be initialized with {0} and it will have
2198 * the correct defaults.
2199 */
2200 struct format
2201 {
2202 int minus;
2203 int zero;
2204
2205 long min_width;
2206
2207 int has_prec;
2208 long prec;
2209
2210 long type;
2211 };
2212
2213
format_flags(struct format * format,const char ** fmt)2214 static void format_flags(struct format *format, const char **fmt)
2215 {
2216 int done;
2217
2218 done = 0;
2219 do
2220 {
2221 switch (**fmt) {
2222 case '-':
2223 format->minus = 1;
2224 break;
2225
2226 case '0':
2227 format->zero = 1;
2228 break;
2229
2230 default:
2231 done = 1;
2232 }
2233
2234 if (!done)
2235 ++(*fmt);
2236 } while (!done);
2237 }
2238
2239
format_width(struct format * format,const char ** fmt,VALPARM (args))2240 static void format_width(struct format *format, const char **fmt,
2241 VALPARM(args))
2242 {
2243 char *end;
2244
2245 if (**fmt == '*')
2246 {
2247 format->min_width = va_arg(VALST(args), int);
2248 ++(*fmt);
2249 } else if (isdigit(**(const unsigned char **) fmt))
2250 {
2251 format->min_width = strtol(*fmt, &end, 10);
2252 *fmt = end;
2253 /* XXX error checking is missing from here */
2254 }
2255 }
2256
2257
format_prec(struct format * format,const char ** fmt,VALPARM (args))2258 static void format_prec(struct format *format, const char **fmt,
2259 VALPARM(args))
2260 {
2261 char *end;
2262
2263 if (**fmt != '.')
2264 return;
2265 ++(*fmt);
2266 if (**fmt == '*')
2267 {
2268 format->has_prec = 1;
2269 format->prec = va_arg(VALST(args), int);
2270 ++(*fmt);
2271 } else if (isdigit(**(const unsigned char **) fmt))
2272 {
2273 format->has_prec = 1;
2274 format->prec = strtol(*fmt, &end, 10);
2275 *fmt = end;
2276 /* XXX error checking is missing from here */
2277 }
2278 }
2279
2280
format_type(struct format * format,const char ** fmt)2281 static void format_type(struct format *format, const char **fmt)
2282 {
2283 switch (**fmt) {
2284 case 'h':
2285 format->type = **fmt;
2286 ++(*fmt);
2287 break;
2288 case 'l':
2289 if (*(*fmt + 1) == 'l'){
2290 format->type = 'L';
2291 ++(*fmt);
2292 } else format->type = **fmt;
2293 ++(*fmt);
2294 break;
2295 }
2296 }
2297
2298
convert(Octstr * os,struct format * format,const char ** fmt,VALPARM (args))2299 static void convert(Octstr *os, struct format *format, const char **fmt,
2300 VALPARM(args))
2301 {
2302 Octstr *new;
2303 char *s, *pad;
2304 long long n;
2305 unsigned long long u;
2306 char tmpfmt[1024];
2307 char tmpbuf[1024];
2308 char c;
2309 void *p;
2310
2311 new = NULL;
2312
2313 switch (**fmt)
2314 {
2315 case 'c':
2316 c = va_arg(VALST(args), int);
2317 new = octstr_create_from_data(&c, 1);
2318 break;
2319
2320 case 'd':
2321 case 'i':
2322 switch (format->type) {
2323 case 'L':
2324 n = va_arg(VALST(args), long long);
2325 break;
2326 case 'l':
2327 n = va_arg(VALST(args), long);
2328 break;
2329 case 'h':
2330 n = (short) va_arg(VALST(args), int);
2331 break;
2332 default:
2333 n = va_arg(VALST(args), int);
2334 break;
2335 }
2336 new = octstr_create("");
2337 octstr_append_decimal(new, n);
2338 break;
2339
2340 case 'o':
2341 case 'u':
2342 case 'x':
2343 case 'X':
2344 switch (format->type) {
2345 case 'l':
2346 u = va_arg(VALST(args), unsigned long);
2347 break;
2348 case 'L':
2349 u = va_arg(VALST(args), unsigned long long);
2350 break;
2351 case 'h':
2352 u = (unsigned short) va_arg(VALST(args), unsigned int);
2353 break;
2354 default:
2355 u = va_arg(VALST(args), unsigned int);
2356 break;
2357 }
2358 tmpfmt[0] = '%';
2359 tmpfmt[1] = 'l';
2360 tmpfmt[2] = **fmt;
2361 tmpfmt[3] = '\0';
2362 sprintf(tmpbuf, tmpfmt, u);
2363 new = octstr_create(tmpbuf);
2364 break;
2365
2366 case 'e':
2367 case 'f':
2368 case 'g':
2369 sprintf(tmpfmt, "%%");
2370 if (format->minus)
2371 strcat(tmpfmt, "-");
2372 if (format->zero)
2373 strcat(tmpfmt, "0");
2374 if (format->min_width > 0)
2375 sprintf(strchr(tmpfmt, '\0'),
2376 "%ld", format->min_width);
2377 if (format->has_prec)
2378 sprintf(strchr(tmpfmt, '\0'),
2379 ".%ld", format->prec);
2380 if (format->type != '\0')
2381 sprintf(strchr(tmpfmt, '\0'),
2382 "%c", (int) format->type);
2383 sprintf(strchr(tmpfmt, '\0'), "%c", **fmt);
2384 snprintf(tmpbuf, sizeof(tmpbuf),
2385 tmpfmt, va_arg(VALST(args), double));
2386 new = octstr_create(tmpbuf);
2387 break;
2388
2389 case 's':
2390 s = va_arg(VALST(args), char *);
2391 if (format->has_prec && format->prec < (long) strlen(s))
2392 n = format->prec;
2393 else
2394 n = (long) strlen(s);
2395 new = octstr_create_from_data(s, n);
2396 break;
2397
2398 case 'p':
2399 p = va_arg(VALST(args), void *);
2400 sprintf(tmpfmt, "%p", p);
2401 new = octstr_create(tmpfmt);
2402 break;
2403
2404 case 'S':
2405 new = octstr_duplicate(va_arg(VALST(args), Octstr *));
2406 if (!new)
2407 new = octstr_create("(null)");
2408 if (format->has_prec)
2409 octstr_truncate(new, format->prec);
2410 break;
2411
2412 case 'E':
2413 new = octstr_duplicate(va_arg(VALST(args), Octstr *));
2414 if (!new)
2415 new = octstr_create("(null)");
2416 octstr_url_encode(new);
2417 /*
2418 * note: we use blind truncate - encoded character can get cut half-way.
2419 */
2420 if (format->has_prec)
2421 octstr_truncate(new, format->prec);
2422 break;
2423
2424 case 'H':
2425 new = octstr_duplicate(va_arg(VALST(args), Octstr *));
2426 if (!new)
2427 new = octstr_create("(null)");
2428 /* upper case */
2429 octstr_binary_to_hex(new, 1);
2430 if (format->has_prec)
2431 octstr_truncate(new, (format->prec % 2 ? format->prec - 1 : format->prec));
2432 break;
2433
2434 case '%':
2435 new = octstr_create("%");
2436 break;
2437
2438 default:
2439 panic(0, "octstr_format format string syntax error.");
2440 }
2441
2442 if (format->zero)
2443 pad = "0";
2444 else
2445 pad = " ";
2446
2447 if (format->minus) {
2448 while (format->min_width > octstr_len(new))
2449 octstr_append_data(new, pad, 1);
2450 } else {
2451 while (format->min_width > octstr_len(new))
2452 octstr_insert_data(new, 0, pad, 1);
2453 }
2454
2455 octstr_append(os, new);
2456 octstr_destroy(new);
2457
2458 if (**fmt != '\0')
2459 ++(*fmt);
2460 }
2461
2462
octstr_format(const char * fmt,...)2463 Octstr *octstr_format(const char *fmt, ...)
2464 {
2465 Octstr *os;
2466 va_list args;
2467
2468 va_start(args, fmt);
2469 os = octstr_format_valist(fmt, args);
2470 va_end(args);
2471 return os;
2472 }
2473
2474
octstr_format_valist_real(const char * fmt,va_list args)2475 Octstr *octstr_format_valist_real(const char *fmt, va_list args)
2476 {
2477 Octstr *os;
2478 size_t n;
2479
2480 os = octstr_create("");
2481
2482 while (*fmt != '\0') {
2483 struct format format = { 0, };
2484
2485 n = strcspn(fmt, "%");
2486 octstr_append_data(os, fmt, n);
2487 fmt += n;
2488
2489 gw_assert(*fmt == '%' || *fmt == '\0');
2490 if (*fmt == '\0')
2491 continue;
2492
2493 ++fmt;
2494 format_flags(&format, &fmt);
2495 format_width(&format, &fmt, VARGS(args));
2496 format_prec(&format, &fmt, VARGS(args));
2497 format_type(&format, &fmt);
2498 convert(os, &format, &fmt, VARGS(args));
2499 }
2500
2501 seems_valid(os);
2502 return os;
2503 }
2504
2505
octstr_format_append(Octstr * os,const char * fmt,...)2506 void octstr_format_append(Octstr *os, const char *fmt, ...)
2507 {
2508 Octstr *temp;
2509 va_list args;
2510
2511 va_start(args, fmt);
2512 temp = octstr_format_valist(fmt, args);
2513 va_end(args);
2514 octstr_append(os, temp);
2515 octstr_destroy(temp);
2516 }
2517
2518
2519 /*
2520 * Hash implementation ala Robert Sedgewick.
2521 */
octstr_hash_key(Octstr * ostr)2522 unsigned long octstr_hash_key(Octstr *ostr)
2523 {
2524 unsigned long b = 378551;
2525 unsigned long a = 63689;
2526 unsigned long hash = 0;
2527 unsigned long i = 0;
2528 unsigned long len = octstr_len(ostr);
2529 const char *str = octstr_get_cstr(ostr);
2530
2531 for(i = 0; i < len; str++, i++) {
2532 hash = hash*a+(*str);
2533 a = a*b;
2534 }
2535
2536 return (hash & 0x7FFFFFFF);
2537 }
2538
2539
2540 /**********************************************************************
2541 * Local functions.
2542 */
2543
seems_valid_real(const Octstr * ostr,const char * filename,long lineno,const char * function)2544 static void seems_valid_real(const Octstr *ostr, const char *filename, long lineno,
2545 const char *function)
2546 {
2547 gw_assert(immutables_init);
2548 gw_assert_place(ostr != NULL,
2549 filename, lineno, function);
2550 gw_assert_allocated(ostr,
2551 filename, lineno, function);
2552 gw_assert_place(ostr->len >= 0,
2553 filename, lineno, function);
2554 gw_assert_place(ostr->size >= 0,
2555 filename, lineno, function);
2556 if (ostr->size == 0) {
2557 gw_assert_place(ostr->len == 0,
2558 filename, lineno, function);
2559 gw_assert_place(ostr->data == NULL,
2560 filename, lineno, function);
2561 } else {
2562 gw_assert_place(ostr->len + 1 <= ostr->size,
2563 filename, lineno, function);
2564 gw_assert_place(ostr->data != NULL,
2565 filename, lineno, function);
2566 if (!ostr->immutable)
2567 gw_assert_allocated(ostr->data,
2568 filename, lineno, function);
2569 gw_assert_place(ostr->data[ostr->len] == '\0',
2570 filename, lineno, function);
2571 }
2572 }
2573
2574 int
octstr_recode(Octstr * tocode,Octstr * fromcode,Octstr * orig)2575 octstr_recode (Octstr *tocode, Octstr *fromcode, Octstr *orig)
2576 {
2577 Octstr *octstr_utf8 = NULL;
2578 Octstr *octstr_final = NULL;
2579 int resultcode = 0;
2580
2581 if (octstr_case_compare(tocode, fromcode) == 0) {
2582 goto cleanup_and_exit;
2583 }
2584
2585 if ((octstr_case_compare(fromcode, octstr_imm ("UTF-8")) != 0) &&
2586 (octstr_case_compare(fromcode, octstr_imm ("UTF8")) != 0)) {
2587 if (charset_to_utf8(orig, &octstr_utf8, fromcode) < 0) {
2588 resultcode = -1;
2589 goto cleanup_and_exit;
2590 }
2591 } else {
2592 octstr_utf8 = octstr_duplicate(orig);
2593 }
2594
2595 if ((octstr_case_compare(tocode, octstr_imm ("UTF-8")) != 0) &&
2596 (octstr_case_compare(tocode, octstr_imm ("UTF8")) != 0)) {
2597 if (charset_from_utf8(octstr_utf8, &octstr_final, tocode) < 0) {
2598 resultcode = -1;
2599 goto cleanup_and_exit;
2600 }
2601 } else {
2602 octstr_final = octstr_duplicate(octstr_utf8);
2603 }
2604
2605 octstr_truncate(orig, 0);
2606 octstr_append(orig, octstr_final);
2607
2608 cleanup_and_exit:
2609 octstr_destroy (octstr_utf8);
2610 octstr_destroy (octstr_final);
2611
2612 return resultcode;
2613 }
2614
octstr_strip_char(Octstr * text,char ch)2615 void octstr_strip_char(Octstr *text, char ch)
2616 {
2617 int start = 0;
2618
2619 seems_valid(text);
2620 gw_assert(!text->immutable);
2621
2622 /* Remove char from the beginning of the text */
2623 while ((ch == octstr_get_char(text, start)) &&
2624 start <= octstr_len(text))
2625 start ++;
2626
2627 if (start > 0)
2628 octstr_delete(text, 0, start);
2629
2630 seems_valid(text);
2631 }
2632
octstr_isnum(Octstr * ostr1)2633 int octstr_isnum(Octstr *ostr1)
2634 {
2635 int start = 0;
2636 char c;
2637
2638 seems_valid(ostr1);
2639 while (start < octstr_len(ostr1)) {
2640 c = octstr_get_char(ostr1, start);
2641 if (!isdigit(c) && (c!='+'))
2642 return 0;
2643 start++;
2644 }
2645 return 1;
2646 }
2647
octstr_replace(Octstr * haystack,Octstr * needle,Octstr * repl)2648 void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl)
2649 {
2650 int p = 0;
2651 long len, repl_len;
2652
2653 len = octstr_len(needle);
2654 repl_len = octstr_len(repl);
2655
2656 while ((p = octstr_search(haystack, needle, p)) != -1) {
2657 octstr_delete(haystack, p, len);
2658 octstr_insert(haystack, repl, p);
2659 p += repl_len;
2660 }
2661 }
2662
octstr_replace_first(Octstr * haystack,Octstr * needle,Octstr * repl)2663 void octstr_replace_first(Octstr *haystack, Octstr *needle, Octstr *repl)
2664 {
2665 int p = 0;
2666 long len, repl_len;
2667
2668 len = octstr_len(needle);
2669 repl_len = octstr_len(repl);
2670
2671 p = octstr_search(haystack, needle, p);
2672 if (p != -1) {
2673 octstr_delete(haystack, p, len);
2674 octstr_insert(haystack, repl, p);
2675 }
2676 }
2677
octstr_symbolize(Octstr * ostr)2678 int octstr_symbolize(Octstr *ostr)
2679 {
2680 long len, i;
2681
2682 seems_valid(ostr);
2683 gw_assert(!ostr->immutable);
2684
2685 if (ostr->len == 0)
2686 return 0;
2687
2688 /* Check if it's in the right format */
2689 if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit))
2690 return -1;
2691
2692 len = ostr->len + (ostr->len/2);
2693 octstr_grow(ostr, ostr->len * 2);
2694
2695 for (i = 0; i < len; i += 3)
2696 octstr_insert_data(ostr, i, "%", 1);
2697
2698 return 1;
2699 }
2700
octstr_delete_matching(Octstr * haystack,Octstr * needle)2701 void octstr_delete_matching(Octstr *haystack, Octstr *needle)
2702 {
2703 int p = 0;
2704 long len;
2705
2706 seems_valid(haystack);
2707 seems_valid(needle);
2708 gw_assert(!haystack->immutable);
2709 len = octstr_len(needle);
2710
2711 while ((p = octstr_search(haystack, needle, p)) != -1) {
2712 octstr_delete(haystack, p, len);
2713 }
2714 }
2715
octstr_is_all_hex(Octstr * os)2716 int octstr_is_all_hex(Octstr *os)
2717 {
2718 long len, i;
2719 int ch;
2720
2721 seems_valid(os);
2722 len = octstr_len(os);
2723 for (i = 0; i < len; ++i) {
2724 ch = octstr_get_char(os, i);
2725 if (!gw_isxdigit(ch))
2726 return 0;
2727 }
2728
2729 return 1;
2730 }
2731
2732 /*
2733 * function octstr_convert_to_html_entities()
2734 * make data HTML safe by converting appropriate characters to HTML entities
2735 * Input: data to be inserted in HTML
2736 **/
octstr_convert_to_html_entities(Octstr * input)2737 void octstr_convert_to_html_entities(Octstr* input)
2738 {
2739 int i;
2740
2741 for (i = 0; i < octstr_len(input); ++i) {
2742 switch (octstr_get_char(input, i)) {
2743 #define ENTITY(a,b) \
2744 case a: \
2745 octstr_delete(input, i, 1); \
2746 octstr_insert(input, octstr_imm("&" b ";"), i); \
2747 i += sizeof(b); break;
2748 #include "gwlib/html-entities.def"
2749 #undef ENTITY
2750 }
2751 }
2752 }
2753
2754 /*
2755 * This function is meant to find html entities in an octstr.
2756 * The html-entities.def file must be sorted alphabetically for
2757 * this function to work (according to current Locale in use).
2758 */
octstr_find_entity(Octstr * input,int startfind,int endfind)2759 static int octstr_find_entity(Octstr* input, int startfind, int endfind)
2760 {
2761 #define ENTITY(a,b) { a, b },
2762 struct entity_struct {
2763 int entity;
2764 char *entity_str;
2765 };
2766 const struct entity_struct entities[] = {
2767 #include "html-entities.def"
2768 { -1, "" } /* pivot */
2769 };
2770 #undef ENTITY
2771 int center; /* position in table that we are about to compare */
2772 int matchresult; /* result of match agains found entity name. indicates less, equal or greater */
2773
2774 if (endfind == 0) {
2775 /* when calling this function we do not (nor even want to) know the
2776 * sizeof(entities). Hence this check. */
2777 endfind = (sizeof(entities) / sizeof(struct entity_struct)) - 1;
2778 }
2779 center = startfind + ((endfind - startfind) / 2);
2780 matchresult = octstr_str_compare(input, entities[center].entity_str);
2781 if (matchresult == 0) {
2782 return entities[center].entity;
2783 }
2784 if (endfind - startfind <= 1) {
2785 /* we are at the end of our results */
2786 return -1;
2787 }
2788 if (matchresult < 0) {
2789 /* keep searching in first part of the table */
2790 return octstr_find_entity(input, startfind, center);
2791 } else {
2792 /* keep searching in last part of the table */
2793 return octstr_find_entity(input, center, endfind);
2794 }
2795 }
2796
2797 /*
2798 * function octstr_convert_from_html_entities()
2799 * convert HTML safe data back to binary data by replacing HTML entities with their
2800 * respective character values
2801 * Input: data to be inserted in HTML
2802 **/
octstr_convert_from_html_entities(Octstr * input)2803 void octstr_convert_from_html_entities(Octstr* input)
2804 {
2805 int startpos = 0, endpos;
2806 int entity;
2807 Octstr *match;
2808
2809 while ((startpos = octstr_search_char(input, '&', startpos)) != -1) {
2810 endpos = octstr_search_char(input, ';', startpos + 1);
2811 if (endpos >= 0) {
2812 match = octstr_copy(input, startpos + 1, endpos - startpos - 1);
2813 entity = octstr_find_entity(match, 0, 0);
2814 if (entity >= 0) {
2815 octstr_delete(input, startpos, endpos - startpos + 1);
2816 octstr_insert_char(input, startpos, entity);
2817 }
2818 octstr_destroy(match);
2819 }
2820 startpos++;
2821 }
2822 }
2823