00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #include <ctype.h>
00067 #include <limits.h>
00068 #include <errno.h>
00069 #include <stdlib.h>
00070 #include <string.h>
00071 #include <unistd.h>
00072 #include <sys/types.h>
00073 #include <sys/socket.h>
00074 #include <netinet/in.h>
00075
00076 #include "gwlib.h"
00077
00078
00079
00080
00081
00082 #if (defined(__linux__) && (defined(__powerpc__) || defined(__s390__) || defined(__x86_64))) || \
00083 (defined(__FreeBSD__) && defined(__amd64__))
00084 #define VARGS(x) (x)
00085 #define VALPARM(y) va_list y
00086 #define VALST(z) (z)
00087 #else
00088 #define VARGS(x) (&x)
00089 #define VALPARM(y) va_list *y
00090 #define VALST(z) (*z)
00091 #endif
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 struct Octstr
00118 {
00119 unsigned char *data;
00120 long len;
00121 long size;
00122 int immutable;
00123 };
00124
00125
00126
00127
00128
00129
00130 #define MAX_IMMUTABLES 1024
00131
00132 static Octstr *immutables[MAX_IMMUTABLES];
00133 static Mutex immutables_mutex;
00134 static int immutables_init = 0;
00135
00136 static char is_safe[UCHAR_MAX + 1];
00137
00138
00139
00140
00141
00142
00143
00144 #define CSTR_TO_LONG(ptr) (((long) ptr) >> 2)
00145
00146
00147
00148
00149
00150 #define H2B(a) (a >= '0' && a <= '9' ? \
00151 a - '0' : (a >= 'a' && a <= 'f' ? \
00152 a - 'a' + 10 : (a >= 'A' && a <= 'F' ? a - 'A' + 10 : -1) \
00153 ) \
00154 )
00155
00156
00157
00158
00159
00160
00161
00162
00163 static void seems_valid_real(const Octstr *ostr, const char *filename, long lineno,
00164 const char *function);
00165 #ifdef NO_GWASSERT
00166 #define seems_valid(ostr)
00167 #else
00168 #define seems_valid(ostr) \
00169 (seems_valid_real(ostr, __FILE__, __LINE__, __func__))
00170 #endif
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 static void octstr_grow(Octstr *ostr, long size)
00181 {
00182 gw_assert(!ostr->immutable);
00183 seems_valid(ostr);
00184 gw_assert(size >= 0);
00185
00186 size++;
00187
00188 if (size > ostr->size) {
00189
00190 size += 1024 - (size % 1024);
00191 ostr->data = gw_realloc(ostr->data, size);
00192 ostr->size = size;
00193 }
00194 }
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 static void urlcode_init(void)
00205 {
00206 int i;
00207
00208 unsigned char *safe = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00209 "abcdefghijklmnopqrstuvwxyz-_.!~*'()";
00210 for (i = 0; safe[i] != '\0'; ++i)
00211 is_safe[safe[i]] = 1;
00212 }
00213
00214
00215 void octstr_init(void)
00216 {
00217 urlcode_init();
00218 mutex_init_static(&immutables_mutex);
00219 immutables_init = 1;
00220 }
00221
00222
00223 void octstr_shutdown(void)
00224 {
00225 long i, n;
00226
00227 n = 0;
00228 for (i = 0; i < MAX_IMMUTABLES; ++i) {
00229 if (immutables[i] != NULL) {
00230 gw_free(immutables[i]);
00231 ++n;
00232 }
00233 }
00234 if(n>0)
00235 debug("gwlib.octstr", 0, "Immutable octet strings: %ld.", n);
00236 mutex_destroy(&immutables_mutex);
00237 }
00238
00239
00240 Octstr *octstr_create_real(const char *cstr, const char *file, long line,
00241 const char *func)
00242 {
00243 gw_assert(cstr != NULL);
00244 return octstr_create_from_data_trace(cstr, strlen(cstr), file, line, func);
00245 }
00246
00247 Octstr *octstr_create_from_data_real(const char *data, long len, const char *file,
00248 long line, const char *func)
00249 {
00250 Octstr *ostr;
00251
00252 gw_assert(len >= 0);
00253 if (data == NULL)
00254 gw_assert(len == 0);
00255
00256
00257
00258
00259 if (len < 0 || (data == NULL && len != 0))
00260 return NULL;
00261
00262 ostr = gw_malloc_trace(sizeof(*ostr), file, line, func);
00263 if (len == 0) {
00264 ostr->len = 0;
00265 ostr->size = 0;
00266 ostr->data = NULL;
00267 } else {
00268 ostr->len = len;
00269 ostr->size = len + 1;
00270 ostr->data = gw_malloc_trace(ostr->size, file, line, func);
00271 memcpy(ostr->data, data, len);
00272 ostr->data[len] = '\0';
00273 }
00274 ostr->immutable = 0;
00275 seems_valid(ostr);
00276 return ostr;
00277 }
00278
00279
00280 Octstr *octstr_imm(const char *cstr)
00281 {
00282 Octstr *os;
00283 long i, index;
00284 unsigned char *data;
00285
00286 gw_assert(immutables_init);
00287 gw_assert(cstr != NULL);
00288
00289 index = CSTR_TO_LONG(cstr) % MAX_IMMUTABLES;
00290 data = (unsigned char *) cstr;
00291
00292 mutex_lock(&immutables_mutex);
00293 i = index;
00294 for (; ; ) {
00295 if (immutables[i] == NULL || immutables[i]->data == data)
00296 break;
00297 i = (i + 1) % MAX_IMMUTABLES;
00298 if (i == index)
00299 panic(0, "Too many immutable strings.");
00300 }
00301 os = immutables[i];
00302 if (os == NULL) {
00303
00304
00305
00306
00307 os = gw_malloc(sizeof(*os));
00308 os->data = data;
00309 os->len = strlen(data);
00310 os->size = os->len + 1;
00311 os->immutable = 1;
00312 immutables[i] = os;
00313 seems_valid(os);
00314 }
00315 mutex_unlock(&immutables_mutex);
00316
00317 return os;
00318 }
00319
00320
00321 void octstr_destroy(Octstr *ostr)
00322 {
00323 if (ostr != NULL) {
00324 seems_valid(ostr);
00325 if (!ostr->immutable) {
00326 gw_free(ostr->data);
00327 gw_free(ostr);
00328 }
00329 }
00330 }
00331
00332
00333 void octstr_destroy_item(void *os)
00334 {
00335 octstr_destroy(os);
00336 }
00337
00338
00339 long octstr_len(const Octstr *ostr)
00340 {
00341 if (ostr == NULL)
00342 return 0;
00343 seems_valid(ostr);
00344 return ostr->len;
00345 }
00346
00347
00348 Octstr *octstr_copy_real(const Octstr *ostr, long from, long len, const char *file, long line,
00349 const char *func)
00350 {
00351 seems_valid(ostr);
00352 gw_assert(from >= 0);
00353 gw_assert(len >= 0);
00354
00355 if (from >= ostr->len)
00356 return octstr_create("");
00357
00358 if (len > ostr->len - from)
00359 len = ostr->len - from;
00360
00361 return octstr_create_from_data_trace(ostr->data + from, len, file,
00362 line, func);
00363 }
00364
00365
00366
00367 Octstr *octstr_duplicate_real(const Octstr *ostr, const char *file, long line,
00368 const char *func)
00369 {
00370 if (ostr == NULL)
00371 return NULL;
00372 seems_valid(ostr);
00373 return octstr_create_from_data_trace(ostr->data, ostr->len, file, line, func);
00374 }
00375
00376
00377 Octstr *octstr_cat(Octstr *ostr1, Octstr *ostr2)
00378 {
00379 Octstr *ostr;
00380
00381 seems_valid(ostr1);
00382 seems_valid(ostr2);
00383 gw_assert(!ostr1->immutable);
00384
00385 ostr = octstr_create("");
00386 ostr->len = ostr1->len + ostr2->len;
00387 ostr->size = ostr->len + 1;
00388 ostr->data = gw_malloc(ostr->size);
00389
00390 if (ostr1->len > 0)
00391 memcpy(ostr->data, ostr1->data, ostr1->len);
00392 if (ostr2->len > 0)
00393 memcpy(ostr->data + ostr1->len, ostr2->data, ostr2->len);
00394 ostr->data[ostr->len] = '\0';
00395
00396 seems_valid(ostr);
00397 return ostr;
00398 }
00399
00400
00401 int octstr_get_char(const Octstr *ostr, long pos)
00402 {
00403 seems_valid(ostr);
00404 if (pos >= ostr->len || pos < 0)
00405 return -1;
00406 return ostr->data[pos];
00407 }
00408
00409
00410 void octstr_set_char(Octstr *ostr, long pos, int ch)
00411 {
00412 seems_valid(ostr);
00413 gw_assert(!ostr->immutable);
00414 if (pos < ostr->len)
00415 ostr->data[pos] = ch;
00416 seems_valid(ostr);
00417 }
00418
00419
00420 void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len)
00421 {
00422 gw_assert(buf != NULL);
00423 seems_valid(ostr);
00424
00425 if (pos >= ostr->len)
00426 return;
00427 if (pos + len > ostr->len)
00428 len = ostr->len - pos;
00429 if (len > 0)
00430 memcpy(buf, ostr->data + pos, len);
00431 }
00432
00433
00434 char *octstr_get_cstr_real(const Octstr *ostr, const char *file, long line,
00435 const char *func)
00436 {
00437 if (!ostr)
00438 return "(null)";
00439 seems_valid_real(ostr, file, line, func);
00440 if (ostr->len == 0)
00441 return "";
00442 return ostr->data;
00443 }
00444
00445
00446 void octstr_append_from_hex(Octstr *ostr, char *hex)
00447 {
00448 Octstr *output;
00449
00450 seems_valid(ostr);
00451 gw_assert(!ostr->immutable);
00452
00453 output = octstr_create(hex);
00454 octstr_hex_to_binary(output);
00455 octstr_append(ostr, output);
00456 octstr_destroy(output);
00457 }
00458
00459
00460 void octstr_binary_to_hex(Octstr *ostr, int uppercase)
00461 {
00462 unsigned char *hexits;
00463 long i, tmp;
00464
00465 seems_valid(ostr);
00466 gw_assert(!ostr->immutable);
00467 if (ostr->len == 0)
00468 return;
00469
00470 hexits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
00471 octstr_grow(ostr, ostr->len * 2);
00472
00473
00474
00475
00476 for (i = ostr->len - 1; i >= 0; i--) {
00477 tmp = i << 1;
00478 ostr->data[tmp + 1] = hexits[ostr->data[i] & 0xf];
00479 ostr->data[tmp] = hexits[ostr->data[i] >> 4];
00480 }
00481
00482 ostr->len = ostr->len * 2;
00483 ostr->data[ostr->len] = '\0';
00484
00485 seems_valid(ostr);
00486 }
00487
00488
00489 int octstr_hex_to_binary(Octstr *ostr)
00490 {
00491 long len, i;
00492 unsigned char *p;
00493
00494 seems_valid(ostr);
00495 gw_assert(!ostr->immutable);
00496
00497 if (ostr->len == 0)
00498 return 0;
00499
00500
00501 if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit))
00502 return -1;
00503
00504 len = ostr->len;
00505
00506
00507 for (i = 0, p = ostr->data; i < len; i++, p++) {
00508 if (*p >= '0' && *p <= '9')
00509 *p -= '0';
00510 else if (*p >= 'a' && *p <= 'f')
00511 *p = *p - 'a' + 10;
00512 else if (*p >= 'A' && *p <= 'F')
00513 *p = *p - 'A' + 10;
00514 else {
00515
00516
00517 gw_assert(0);
00518 *p = 0;
00519 }
00520 }
00521
00522
00523 len = ostr->len / 2;
00524
00525 for (i = 0; i < len; i++) {
00526 ostr->data[i] = ostr->data[i * 2] * 16 | ostr->data[i * 2 + 1];
00527 }
00528
00529 ostr->len = len;
00530 ostr->data[len] = '\0';
00531
00532 seems_valid(ostr);
00533 return 0;
00534 }
00535
00536
00537 void octstr_binary_to_base64(Octstr *ostr)
00538 {
00539 static const unsigned char base64[64] =
00540 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00541 long triplets;
00542 long lines;
00543 long orig_len;
00544 unsigned char *data;
00545 long from, to;
00546 int left_on_line;
00547
00548 seems_valid(ostr);
00549 gw_assert(!ostr->immutable);
00550
00551 if (ostr->len == 0) {
00552
00553 octstr_insert(ostr, octstr_imm("\015\012"), 0);
00554 return;
00555 }
00556
00557
00558
00559
00560
00561 triplets = (ostr->len + 2) / 3;
00562 lines = (triplets + 18) / 19;
00563
00564 octstr_grow(ostr, triplets * 4 + lines * 2);
00565 orig_len = ostr->len;
00566 data = ostr->data;
00567
00568 ostr->len = triplets * 4 + lines * 2;
00569 data[ostr->len] = '\0';
00570
00571
00572
00573
00574
00575
00576 from = (triplets - 1) * 3;
00577 to = (triplets - 1) * 4 + (lines - 1) * 2;
00578
00579
00580 data[to + 5] = 10;
00581 data[to + 4] = 13;
00582 left_on_line = triplets - ((lines - 1) * 19);
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 switch (orig_len % 3) {
00596 case 0:
00597 break;
00598 case 1:
00599 data[orig_len] = 0;
00600 data[orig_len + 1] = 0;
00601 break;
00602 case 2:
00603 data[orig_len + 1] = 0;
00604 break;
00605 }
00606
00607
00608 while (from >= 0) {
00609 long whole_triplet;
00610
00611
00612 if (left_on_line == 0) {
00613 to -= 2;
00614 data[to + 5] = 10;
00615 data[to + 4] = 13;
00616 left_on_line = 19;
00617 }
00618
00619 whole_triplet = (data[from] << 16) |
00620 (data[from + 1] << 8) |
00621 data[from + 2];
00622 data[to + 3] = base64[whole_triplet % 64];
00623 data[to + 2] = base64[(whole_triplet >> 6) % 64];
00624 data[to + 1] = base64[(whole_triplet >> 12) % 64];
00625 data[to] = base64[(whole_triplet >> 18) % 64];
00626
00627 to -= 4;
00628 from -= 3;
00629 left_on_line--;
00630 }
00631
00632 gw_assert(left_on_line == 0);
00633 gw_assert(from == -3);
00634 gw_assert(to == -4);
00635
00636
00637
00638
00639 switch (orig_len % 3) {
00640 case 0:
00641 break;
00642 case 1:
00643 gw_assert(data[ostr->len - 3] == 'A');
00644 gw_assert(data[ostr->len - 4] == 'A');
00645 data[ostr->len - 3] = '=';
00646 data[ostr->len - 4] = '=';
00647 break;
00648 case 2:
00649 gw_assert(data[ostr->len - 3] == 'A');
00650 data[ostr->len - 3] = '=';
00651 break;
00652 }
00653
00654 seems_valid(ostr);
00655 }
00656
00657
00658 void octstr_base64_to_binary(Octstr *ostr)
00659 {
00660 long triplet;
00661 long pos, len;
00662 long to;
00663 int quadpos = 0;
00664 int warned = 0;
00665 unsigned char *data;
00666
00667 seems_valid(ostr);
00668 gw_assert(!ostr->immutable);
00669
00670 len = ostr->len;
00671 data = ostr->data;
00672
00673 if (len == 0)
00674 return;
00675
00676 to = 0;
00677 triplet = 0;
00678 quadpos = 0;
00679 for (pos = 0; pos < len; pos++) {
00680 int c = data[pos];
00681 int sixbits;
00682
00683 if (c >= 'A' && c <= 'Z') {
00684 sixbits = c - 'A';
00685 } else if (c >= 'a' && c <= 'z') {
00686 sixbits = 26 + c - 'a';
00687 } else if (c >= '0' && c <= '9') {
00688 sixbits = 52 + c - '0';
00689 } else if (c == '+') {
00690 sixbits = 62;
00691 } else if (c == '/') {
00692 sixbits = 63;
00693 } else if (c == '=') {
00694
00695
00696
00697 break;
00698 } else if (isspace(c)) {
00699
00700 continue;
00701 } else {
00702 if (!warned) {
00703 warning(0, "Unusual characters in base64 "
00704 "encoded text.");
00705 warned = 1;
00706 }
00707 continue;
00708 }
00709
00710 triplet = (triplet << 6) | sixbits;
00711 quadpos++;
00712
00713 if (quadpos == 4) {
00714 data[to++] = (triplet >> 16) & 0xff;
00715 data[to++] = (triplet >> 8) & 0xff;
00716 data[to++] = triplet & 0xff;
00717 quadpos = 0;
00718 }
00719 }
00720
00721
00722 switch (quadpos) {
00723 case 0:
00724 break;
00725 case 3:
00726 data[to++] = (triplet >> 10) & 0xff;
00727 data[to++] = (triplet >> 2) & 0xff;
00728 break;
00729 case 2:
00730 data[to++] = (triplet >> 4) & 0xff;
00731 break;
00732 case 1:
00733 warning(0, "Bad padding in base64 encoded text.");
00734 break;
00735 }
00736
00737 ostr->len = to;
00738 data[to] = '\0';
00739
00740 seems_valid(ostr);
00741 }
00742
00743
00744 long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
00745 {
00746
00747
00748
00749 char *endptr;
00750 unsigned char *endpos;
00751 long number;
00752
00753 seems_valid(ostr);
00754 gw_assert(nump != NULL);
00755 gw_assert(base == 0 || (base >= 2 && base <= 36));
00756
00757 if (pos >= ostr->len) {
00758 errno = EINVAL;
00759 return -1;
00760 }
00761
00762 errno = 0;
00763 number = strtol(ostr->data + pos, &endptr, base);
00764 endpos = endptr;
00765 if (errno == ERANGE)
00766 return -1;
00767 if (endpos == ostr->data + pos) {
00768 errno = EINVAL;
00769 return -1;
00770 }
00771
00772 *nump = number;
00773 return endpos - ostr->data;
00774 }
00775
00776
00777 long octstr_parse_double(double *nump, Octstr *ostr, long pos)
00778 {
00779
00780
00781
00782 char *endptr;
00783 unsigned char *endpos;
00784 double number;
00785
00786 seems_valid(ostr);
00787 gw_assert(nump != NULL);
00788
00789 if (pos >= ostr->len) {
00790 errno = EINVAL;
00791 return -1;
00792 }
00793
00794 errno = 0;
00795 number = strtod(ostr->data + pos, &endptr);
00796 endpos = endptr;
00797 if (errno == ERANGE)
00798 return -1;
00799 if (endpos == ostr->data + pos) {
00800 errno = EINVAL;
00801 return -1;
00802 }
00803
00804 *nump = number;
00805 return endpos - ostr->data;
00806 }
00807
00808
00809 int octstr_check_range(Octstr *ostr, long pos, long len,
00810 octstr_func_t filter)
00811 {
00812 long end = pos + len;
00813
00814 seems_valid(ostr);
00815 gw_assert(len >= 0);
00816
00817 if (pos >= ostr->len)
00818 return 1;
00819 if (end > ostr->len)
00820 end = ostr->len;
00821
00822 for ( ; pos < end; pos++) {
00823 if (!filter(ostr->data[pos]))
00824 return 0;
00825 }
00826
00827 return 1;
00828 }
00829
00830
00831 void octstr_convert_range(Octstr *ostr, long pos, long len,
00832 octstr_func_t map)
00833 {
00834 long end = pos + len;
00835
00836 seems_valid(ostr);
00837 gw_assert(!ostr->immutable);
00838 gw_assert(len >= 0);
00839
00840 if (pos >= ostr->len)
00841 return;
00842 if (end > ostr->len)
00843 end = ostr->len;
00844
00845 for ( ; pos < end; pos++) {
00846 ostr->data[pos] = map(ostr->data[pos]);
00847 }
00848
00849 seems_valid(ostr);
00850 }
00851
00852
00853 static int inline make_printable(int c)
00854 {
00855 return isprint(c) ? c : '.';
00856 }
00857
00858
00859 void octstr_convert_printable(Octstr *ostr)
00860 {
00861 octstr_convert_range(ostr, 0, ostr->len, make_printable);
00862 }
00863
00864
00865
00866 int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
00867 {
00868 int ret;
00869 long len;
00870
00871 seems_valid(ostr1);
00872 seems_valid(ostr2);
00873
00874 if (ostr1->len < ostr2->len)
00875 len = ostr1->len;
00876 else
00877 len = ostr2->len;
00878
00879 if (len == 0) {
00880 if (ostr1->len == 0 && ostr2->len > 0)
00881 return -1;
00882 if (ostr1->len > 0 && ostr2->len == 0)
00883 return 1;
00884 return 0;
00885 }
00886
00887 ret = memcmp(ostr1->data, ostr2->data, len);
00888 if (ret == 0) {
00889 if (ostr1->len < ostr2->len)
00890 ret = -1;
00891 else if (ostr1->len > ostr2->len)
00892 ret = 1;
00893 }
00894 return ret;
00895 }
00896
00897
00898 int octstr_case_compare(const Octstr *os1, const Octstr *os2)
00899 {
00900 int c1, c2;
00901 long i, len;
00902
00903 seems_valid(os1);
00904 seems_valid(os2);
00905
00906 if (os1->len < os2->len)
00907 len = os1->len;
00908 else
00909 len = os2->len;
00910
00911 if (len == 0) {
00912 if (os1->len == 0 && os2->len > 0)
00913 return -1;
00914 if (os1->len > 0 && os2->len == 0)
00915 return 1;
00916 return 0;
00917 }
00918
00919 c1 = c2 = 0;
00920 for (i = 0; i < len; ++i) {
00921 c1 = toupper(os1->data[i]);
00922 c2 = toupper(os2->data[i]);
00923 if (c1 != c2)
00924 break;
00925 }
00926
00927 if (i == len) {
00928 if (i == os1->len && i == os2->len)
00929 return 0;
00930 if (i == os1->len)
00931 return -1;
00932 return 1;
00933 } else {
00934
00935
00936
00937
00938 if (c1 < c2)
00939 return -1;
00940 if (c1 == c2)
00941 return 0;
00942 return 1;
00943 }
00944 }
00945
00946
00947 int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
00948 {
00949 long len;
00950
00951 seems_valid(ostr1);
00952 seems_valid(ostr2);
00953
00954 if ((ostr1->len < ostr2->len) && (ostr1->len < n))
00955 len = ostr1->len;
00956 else if ((ostr2->len < ostr1->len) && (ostr2->len < n))
00957 len = ostr2->len;
00958 else
00959 len = n;
00960
00961 if (len == 0)
00962 return 0;
00963
00964 return memcmp(ostr1->data, ostr2->data, len);
00965 }
00966
00967
00968 int octstr_str_compare(const Octstr *ostr, const char *str)
00969 {
00970 seems_valid(ostr);
00971
00972 if (str == NULL)
00973 return -1;
00974 if (ostr->data == NULL)
00975 return strcmp("", str);
00976
00977 return strcmp(ostr->data, str);
00978 }
00979
00980
00981 int octstr_str_case_compare(const Octstr *ostr, const char *str)
00982 {
00983 seems_valid(ostr);
00984
00985 if (str == NULL)
00986 return -1;
00987 if (ostr->data == NULL)
00988 return strcasecmp("", str);
00989
00990 return strcasecmp(ostr->data, str);
00991 }
00992
00993
00994 int octstr_str_ncompare(const Octstr *ostr, const char *str, long n)
00995 {
00996 seems_valid(ostr);
00997
00998 if (str == NULL)
00999 return -1;
01000 if (ostr->data == NULL)
01001 return 1;
01002
01003 return strncmp(ostr->data, str, n);
01004 }
01005
01006
01007 int octstr_search_char(const Octstr *ostr, int ch, long pos)
01008 {
01009 unsigned char *p;
01010
01011 seems_valid(ostr);
01012 gw_assert(ch >= 0);
01013 gw_assert(ch <= UCHAR_MAX);
01014 gw_assert(pos >= 0);
01015
01016 if (pos >= ostr->len)
01017 return -1;
01018
01019 p = memchr(ostr->data + pos, ch, ostr->len - pos);
01020 if (!p)
01021 return -1;
01022 return p - ostr->data;
01023 }
01024
01025
01026 int octstr_search_chars(const Octstr *ostr, const Octstr *chars, long pos)
01027 {
01028 long i, j;
01029
01030 seems_valid(ostr);
01031 seems_valid(chars);
01032 gw_assert(pos >= 0);
01033
01034 for (i = 0; i < octstr_len(chars); i++) {
01035 j = octstr_search_char(ostr, octstr_get_char(chars, i), pos);
01036 if (j != -1)
01037 return j;
01038 }
01039
01040 return -1;
01041 }
01042
01043
01044 int octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
01045 {
01046 int first;
01047
01048 seems_valid(haystack);
01049 seems_valid(needle);
01050 gw_assert(pos >= 0);
01051
01052
01053 if (needle->len == 0)
01054 return 0;
01055
01056 if (needle->len == 1)
01057 return octstr_search_char(haystack, needle->data[0], pos);
01058
01059
01060
01061
01062
01063 first = needle->data[0];
01064 pos = octstr_search_char(haystack, first, pos);
01065 while (pos >= 0 && haystack->len - pos >= needle->len) {
01066 if (memcmp(haystack->data + pos,
01067 needle->data, needle->len) == 0)
01068 return pos;
01069 pos = octstr_search_char(haystack, first, pos + 1);
01070 }
01071
01072 return -1;
01073 }
01074
01075
01076 int octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos)
01077 {
01078 long i, j;
01079 int c1, c2;
01080
01081 seems_valid(haystack);
01082 seems_valid(needle);
01083 gw_assert(pos >= 0);
01084
01085
01086 if (needle->len == 0)
01087 return 0;
01088
01089 for (i = pos; i <= haystack->len - needle->len; ++i) {
01090 for (j = 0; j < needle->len; ++j) {
01091 c1 = toupper(haystack->data[i + j]);
01092 c2 = toupper(needle->data[j]);
01093 if (c1 != c2)
01094 break;
01095 }
01096 if (j == needle->len)
01097 return i;
01098 }
01099
01100 return -1;
01101 }
01102
01103 int octstr_case_nsearch(const Octstr *haystack, const Octstr *needle, long pos, long n)
01104 {
01105 long i, j;
01106 int c1, c2;
01107
01108 seems_valid(haystack);
01109 seems_valid(needle);
01110 gw_assert(pos >= 0);
01111
01112
01113 if (needle->len == 0)
01114 return 0;
01115
01116 for (i = pos; i <= haystack->len - needle->len && i < n; ++i) {
01117 for (j = 0; j < needle->len && j < n; ++j) {
01118 c1 = toupper(haystack->data[i + j]);
01119 c2 = toupper(needle->data[j]);
01120 if (c1 != c2)
01121 break;
01122 }
01123 if (j == needle->len)
01124 return i;
01125 }
01126
01127 return -1;
01128 }
01129
01130
01131 int octstr_print(FILE *f, Octstr *ostr)
01132 {
01133 gw_assert(f != NULL);
01134 seems_valid(ostr);
01135
01136 if (ostr->len == 0)
01137 return 0;
01138 if (fwrite(ostr->data, ostr->len, 1, f) != 1) {
01139 error(errno, "Couldn't write all of octet string to file.");
01140 return -1;
01141 }
01142 return 0;
01143 }
01144
01145
01146 int octstr_pretty_print(FILE *f, Octstr *ostr)
01147 {
01148 unsigned char *p;
01149 long i;
01150
01151 gw_assert(f != NULL);
01152 seems_valid(ostr);
01153
01154 p = ostr->data;
01155 for (i = 0; i < ostr->len; ++i, ++p) {
01156 if (isprint(*p))
01157 fprintf(f, "%c", *p);
01158 else
01159 fprintf(f, "\\x%02x", *p);
01160 }
01161 if (ferror(f))
01162 return -1;
01163 return 0;
01164 }
01165
01166
01167 int octstr_write_to_socket(int socket, Octstr *ostr)
01168 {
01169 long len;
01170 unsigned char *data;
01171 int ret;
01172
01173 gw_assert(socket >= 0);
01174 seems_valid(ostr);
01175
01176 data = ostr->data;
01177 len = ostr->len;
01178 while (len > 0) {
01179 ret = write(socket, data, len);
01180 if (ret == -1) {
01181 if (errno != EINTR) {
01182 error(errno, "Writing to socket failed");
01183 return -1;
01184 }
01185 } else {
01186
01187 len -= ret;
01188 data += ret;
01189 }
01190 }
01191 return 0;
01192 }
01193
01194
01195 long octstr_write_data(Octstr *ostr, int fd, long from)
01196 {
01197 long ret;
01198
01199 gw_assert(fd >= 0);
01200 gw_assert(from >= 0);
01201 seems_valid(ostr);
01202
01203 if (from >= ostr->len)
01204 return 0;
01205
01206 ret = write(fd, ostr->data + from, ostr->len - from);
01207
01208 if (ret < 0) {
01209 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
01210 return 0;
01211 error(errno, "Error writing %ld octets to fd %d:",
01212 ostr->len - from, fd);
01213 return -1;
01214 }
01215
01216 return ret;
01217 }
01218
01219
01220 int octstr_append_from_socket(Octstr *ostr, int socket)
01221 {
01222 unsigned char buf[4096];
01223 int len;
01224
01225 seems_valid(ostr);
01226 gw_assert(!ostr->immutable);
01227
01228 again:
01229 len = recv(socket, buf, sizeof(buf), 0);
01230 if (len < 0 && errno == EINTR)
01231 goto again;
01232
01233 if (len < 0) {
01234 error(errno, "Could not read from socket %d", socket);
01235 return -1;
01236 }
01237
01238 octstr_append_data(ostr, buf, len);
01239 return len;
01240 }
01241
01242
01243 void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
01244 {
01245 if (ostr2 == NULL)
01246 return;
01247
01248 seems_valid(ostr1);
01249 seems_valid(ostr2);
01250 gw_assert(pos <= ostr1->len);
01251 gw_assert(!ostr1->immutable);
01252
01253 if (ostr2->len == 0)
01254 return;
01255
01256 octstr_grow(ostr1, ostr1->len + ostr2->len);
01257 memmove(ostr1->data + pos + ostr2->len, ostr1->data + pos,
01258 ostr1->len - pos);
01259 memcpy(ostr1->data + pos, ostr2->data, ostr2->len);
01260 ostr1->len += ostr2->len;
01261 ostr1->data[ostr1->len] = '\0';
01262
01263 seems_valid(ostr1);
01264 }
01265
01266
01267 void octstr_truncate(Octstr *ostr, int new_len)
01268 {
01269 if (ostr == NULL)
01270 return;
01271
01272 seems_valid(ostr);
01273 gw_assert(!ostr->immutable);
01274 gw_assert(new_len >= 0);
01275
01276 if (new_len >= ostr->len)
01277 return;
01278
01279 ostr->len = new_len;
01280 ostr->data[new_len] = '\0';
01281
01282 seems_valid(ostr);
01283 }
01284
01285
01286 void octstr_strip_blanks(Octstr *text)
01287 {
01288 int start = 0, end, len = 0;
01289
01290 seems_valid(text);
01291 gw_assert(!text->immutable);
01292
01293
01294 while (isspace(octstr_get_char(text, start)) &&
01295 start <= octstr_len(text))
01296 start ++;
01297
01298 if (start > 0)
01299 octstr_delete(text, 0, start);
01300
01301
01302
01303 if ((len = octstr_len(text)) > 0) {
01304 end = len = len - 1;
01305 while (isspace(octstr_get_char(text, end)) && end >= 0)
01306 end--;
01307 octstr_delete(text, end + 1, len - end);
01308 }
01309
01310 seems_valid(text);
01311 }
01312
01313 static int iscrlf(unsigned char c)
01314 {
01315 return c == '\n' || c == '\r';
01316 }
01317
01318 void octstr_strip_crlfs(Octstr *text)
01319 {
01320 int start = 0, end, len = 0;
01321
01322 seems_valid(text);
01323 gw_assert(!text->immutable);
01324
01325
01326 while (iscrlf(octstr_get_char(text, start)) &&
01327 start <= octstr_len(text))
01328 start ++;
01329
01330 if (start > 0)
01331 octstr_delete(text, 0, start);
01332
01333
01334
01335 if ((len = octstr_len(text)) > 0) {
01336 end = len = len - 1;
01337 while (iscrlf(octstr_get_char(text, end)) && end >= 0)
01338 end--;
01339 octstr_delete(text, end + 1, len - end);
01340 }
01341
01342 seems_valid(text);
01343 }
01344
01345 void octstr_strip_nonalphanums(Octstr *text)
01346 {
01347 int start = 0, end, len = 0;
01348
01349 seems_valid(text);
01350 gw_assert(!text->immutable);
01351
01352
01353 while (!isalnum(octstr_get_char(text, start)) &&
01354 start <= octstr_len(text))
01355 start ++;
01356
01357 if (start > 0)
01358 octstr_delete(text, 0, start);
01359
01360
01361
01362 if ((len = octstr_len(text)) > 0) {
01363 end = len = len - 1;
01364 while (!isalnum(octstr_get_char(text, end)) && end >= 0)
01365 end--;
01366 octstr_delete(text, end + 1, len - end);
01367 }
01368
01369 seems_valid(text);
01370 }
01371
01372
01373 void octstr_shrink_blanks(Octstr *text)
01374 {
01375 int i, j, end;
01376
01377 seems_valid(text);
01378 gw_assert(!text->immutable);
01379
01380 end = octstr_len(text);
01381
01382
01383 for (i = 0; i < end; i++) {
01384 if (isspace(octstr_get_char(text, i))) {
01385
01386 if (octstr_get_char(text, i) != ' ')
01387 octstr_set_char(text, i, ' ');
01388
01389 j = i = i + 1;
01390 while (isspace(octstr_get_char(text, j)))
01391 j ++;
01392 if (j - i > 1)
01393 octstr_delete(text, i, j - i);
01394 }
01395 }
01396
01397 seems_valid(text);
01398 }
01399
01400
01401 void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
01402 {
01403 seems_valid(ostr);
01404 gw_assert(!ostr->immutable);
01405 gw_assert(pos <= ostr->len);
01406
01407 if (len == 0)
01408 return;
01409
01410 octstr_grow(ostr, ostr->len + len);
01411 if (ostr->len > pos) {
01412 memmove(ostr->data + pos + len, ostr->data + pos, ostr->len - pos);
01413 }
01414 memcpy(ostr->data + pos, data, len);
01415 ostr->len += len;
01416 ostr->data[ostr->len] = '\0';
01417
01418 seems_valid(ostr);
01419 }
01420
01421 void octstr_insert_char(Octstr *ostr, long pos, const char c)
01422 {
01423 seems_valid(ostr);
01424 gw_assert(!ostr->immutable);
01425 gw_assert(pos <= ostr->len);
01426
01427 octstr_grow(ostr, ostr->len + 1);
01428 if (ostr->len > pos)
01429 memmove(ostr->data + pos + 1, ostr->data + pos, ostr->len - pos);
01430 memcpy(ostr->data + pos, &c, 1);
01431 ostr->len += 1;
01432 ostr->data[ostr->len] = '\0';
01433
01434 seems_valid(ostr);
01435 }
01436
01437 void octstr_append_data(Octstr *ostr, const char *data, long len)
01438 {
01439 gw_assert(ostr != NULL);
01440 octstr_insert_data(ostr, ostr->len, data, len);
01441 }
01442
01443
01444 void octstr_append(Octstr *ostr1, const Octstr *ostr2)
01445 {
01446 gw_assert(ostr1 != NULL);
01447 octstr_insert(ostr1, ostr2, ostr1->len);
01448 }
01449
01450
01451 void octstr_append_cstr(Octstr *ostr, const char *cstr)
01452 {
01453 octstr_insert_data(ostr, ostr->len, cstr, strlen(cstr));
01454 }
01455
01456
01457 void octstr_append_char(Octstr *ostr, int ch)
01458 {
01459 unsigned char c = ch;
01460
01461 gw_assert(ch >= 0);
01462 gw_assert(ch <= UCHAR_MAX);
01463 octstr_insert_data(ostr, ostr->len, &c, 1);
01464 }
01465
01466
01467 void octstr_delete(Octstr *ostr1, long pos, long len)
01468 {
01469 seems_valid(ostr1);
01470 gw_assert(!ostr1->immutable);
01471
01472 if (pos > ostr1->len)
01473 pos = ostr1->len;
01474 if (pos + len > ostr1->len)
01475 len = ostr1->len - pos;
01476 if (len > 0) {
01477 memmove(ostr1->data + pos, ostr1->data + pos + len,
01478 ostr1->len - pos - len);
01479 ostr1->len -= len;
01480 ostr1->data[ostr1->len] = '\0';
01481 }
01482
01483 seems_valid(ostr1);
01484 }
01485
01486
01487
01488 Octstr *octstr_read_file(const char *filename)
01489 {
01490 FILE *f;
01491 Octstr *os;
01492 char buf[4096];
01493 long n;
01494
01495 gw_assert(filename != NULL);
01496
01497 f = fopen(filename, "r");
01498 if (f == NULL) {
01499 error(errno, "fopen failed: couldn't open `%s'", filename);
01500 return NULL;
01501 }
01502
01503 os = octstr_create("");
01504 if (os == NULL)
01505 goto error;
01506
01507 while ((n = fread(buf, 1, sizeof(buf), f)) > 0)
01508 octstr_insert_data(os, octstr_len(os), buf, n);
01509
01510 (void) fclose(f);
01511 return os;
01512
01513 error:
01514 (void) fclose(f);
01515 octstr_destroy(os);
01516 return NULL;
01517 }
01518
01519
01520 Octstr *octstr_read_pipe(FILE *f)
01521 {
01522 Octstr *os;
01523 char buf[4096];
01524
01525 gw_assert(f != NULL);
01526
01527 os = octstr_create("");
01528 if (os == NULL)
01529 goto error;
01530
01531 while (fgets(buf, sizeof(buf), f) != NULL)
01532 octstr_append_data(os, buf, strlen(buf));
01533
01534 return os;
01535
01536 error:
01537 octstr_destroy(os);
01538 return NULL;
01539 }
01540
01541
01542 List *octstr_split_words(const Octstr *ostr)
01543 {
01544 unsigned char *p;
01545 List *list;
01546 Octstr *word;
01547 long i, start, end;
01548
01549 seems_valid(ostr);
01550
01551 list = gwlist_create();
01552
01553 p = ostr->data;
01554 i = 0;
01555 for (; ; ) {
01556 while (i < ostr->len && isspace(*p)) {
01557 ++p;
01558 ++i;
01559 }
01560 start = i;
01561
01562 while (i < ostr->len && !isspace(*p)) {
01563 ++p;
01564 ++i;
01565 }
01566 end = i;
01567
01568 if (start == end)
01569 break;
01570
01571 word = octstr_create_from_data(ostr->data + start,
01572 end - start);
01573 gwlist_append(list, word);
01574 }
01575
01576 return list;
01577 }
01578
01579
01580 List *octstr_split(const Octstr *os, const Octstr *sep)
01581 {
01582 List *list;
01583 long next, pos, seplen;
01584
01585 list = gwlist_create();
01586 pos = 0;
01587 seplen = octstr_len(sep);
01588
01589 while ((next = octstr_search(os, sep, pos)) >= 0) {
01590 gwlist_append(list, octstr_copy(os, pos, next - pos));
01591 pos = next + seplen;
01592 }
01593
01594 if (pos < octstr_len(os))
01595 gwlist_append(list, octstr_copy(os, pos, octstr_len(os)));
01596
01597 return list;
01598 }
01599
01600
01601 int octstr_item_match(void *item, void *pattern)
01602 {
01603 return octstr_compare(item, pattern) == 0;
01604 }
01605
01606
01607 int octstr_item_case_match(void *item, void *pattern)
01608 {
01609 return octstr_case_compare(item, pattern) == 0;
01610 }
01611
01612
01613 void octstr_url_encode(Octstr *ostr)
01614 {
01615 long i, n, len = 0;
01616 int all_safe;
01617 unsigned char c, *str, *str2, *res, *hexits;
01618
01619 if (ostr == NULL)
01620 return;
01621
01622 seems_valid(ostr);
01623 gw_assert(!ostr->immutable);
01624
01625 if (ostr->len == 0)
01626 return;
01627
01628
01629 for (i = n = 0, str = ostr->data, all_safe = 1; i < ostr->len; i++) {
01630 c = *str++;
01631
01632 if (c == ' ') {
01633 all_safe = 0;
01634 continue;
01635 }
01636
01637 if (!is_safe[c]) {
01638 n++;
01639 all_safe = 0;
01640 }
01641 }
01642
01643 if (all_safe)
01644 return;
01645
01646 hexits = "0123456789ABCDEF";
01647
01648
01649
01650
01651
01652
01653 res = str2 = (n ? gw_malloc((len = ostr->len + 2 * n + 1)) : ostr->data);
01654
01655 for (i = 0, str = ostr->data; i < ostr->len; i++) {
01656 c = *str++;
01657
01658 if (c == ' ') {
01659 *str2++ = '+';
01660 continue;
01661 }
01662
01663 if (!is_safe[c]) {
01664 *str2++ = '%';
01665 *str2++ = hexits[c >> 4 & 0xf];
01666 *str2++ = hexits[c & 0xf];
01667 continue;
01668 }
01669
01670 *str2++ = c;
01671 }
01672 *str2 = 0;
01673
01674
01675 if (n) {
01676 gw_free(ostr->data);
01677 ostr->data = res;
01678 ostr->size = len;
01679 ostr->len = len - 1;
01680 }
01681
01682 seems_valid(ostr);
01683 }
01684
01685
01686 int octstr_url_decode(Octstr *ostr)
01687 {
01688 unsigned char *string = ostr->data;
01689 unsigned char *dptr = ostr->data;
01690 int code, code2, ret = 0;
01691
01692 if (ostr == NULL)
01693 return 0;
01694
01695 seems_valid(ostr);
01696 gw_assert(!ostr->immutable);
01697
01698 if (ostr->len == 0)
01699 return 0;
01700
01701 do {
01702 if (*string == '%') {
01703 if (*(string + 1) == '\0' || *(string + 2) == '\0') {
01704 warning(0, "octstr_url_decode: corrupted end-of-string <%s>", string);
01705 ret = -1;
01706 break;
01707 }
01708
01709 code = H2B(*(string + 1));
01710 code2 = H2B(*(string + 2));
01711
01712 if (code == -1 || code2 == -1) {
01713 warning(0, "octstr_url_decode: garbage detected (%c%c%c) skipping.",
01714 *string, *(string + 1), *(string + 2));
01715 *dptr++ = *string++;
01716 *dptr++ = *string++;
01717 *dptr++ = *string++;
01718 ret = -1;
01719 continue;
01720 }
01721
01722 *dptr++ = code << 4 | code2;
01723 string += 3;
01724 }
01725 else if (*string == '+') {
01726 *dptr++ = ' ';
01727 string++;
01728 } else
01729 *dptr++ = *string++;
01730 } while (*string);
01731
01732 *dptr = '\0';
01733 ostr->len = (dptr - ostr->data);
01734
01735 seems_valid(ostr);
01736 return ret;
01737 }
01738
01739
01740 long octstr_get_bits(Octstr *ostr, long bitpos, int numbits)
01741 {
01742 long pos;
01743 long result;
01744 int mask;
01745 int shiftwidth;
01746
01747 seems_valid(ostr);
01748 gw_assert(bitpos >= 0);
01749 gw_assert(numbits <= 32);
01750 gw_assert(numbits >= 0);
01751
01752 pos = bitpos / 8;
01753 bitpos = bitpos % 8;
01754
01755
01756 if (pos >= ostr->len)
01757 return 0;
01758
01759 mask = (1 << numbits) - 1;
01760
01761
01762 if (bitpos + numbits <= 8) {
01763
01764
01765 shiftwidth = 8 - (bitpos + numbits);
01766 return (ostr->data[pos] >> shiftwidth) & mask;
01767 }
01768
01769
01770 result = 0;
01771 while (bitpos + numbits > 8) {
01772 result = (result << 8) | ostr->data[pos];
01773 numbits -= (8 - bitpos);
01774 bitpos = 0;
01775 pos++;
01776 if (pos >= ostr->len)
01777 return (result << numbits) & mask;
01778 }
01779
01780 gw_assert(bitpos == 0);
01781 result <<= numbits;
01782 result |= ostr->data[pos] >> (8 - numbits);
01783 return result & mask;
01784 }
01785
01786 void octstr_set_bits(Octstr *ostr, long bitpos, int numbits,
01787 unsigned long value)
01788 {
01789 long pos;
01790 unsigned long mask;
01791 int shiftwidth;
01792 int bits;
01793 int maxlen;
01794 int c;
01795
01796 seems_valid(ostr);
01797 gw_assert(!ostr->immutable);
01798 gw_assert(bitpos >= 0);
01799 gw_assert(numbits <= 32);
01800 gw_assert(numbits >= 0);
01801
01802 maxlen = (bitpos + numbits + 7) / 8;
01803 if (maxlen > ostr->len) {
01804 octstr_grow(ostr, maxlen);
01805
01806 for (pos = ostr->len; pos < maxlen; pos++) {
01807 ostr->data[pos] = 0;
01808 }
01809 ostr->len = maxlen;
01810 ostr->data[maxlen] = 0;
01811 }
01812
01813 mask = (1 << numbits) - 1;
01814
01815 gw_assert(value <= mask);
01816
01817 pos = bitpos / 8;
01818 bitpos = bitpos % 8;
01819
01820
01821 if (bitpos + numbits <= 8) {
01822
01823
01824 shiftwidth = 8 - (bitpos + numbits);
01825
01826 c = ostr->data[pos] & ~(mask << shiftwidth);
01827 c |= value << shiftwidth;
01828 gw_assert(pos < ostr->len);
01829 ostr->data[pos] = c;
01830 return;
01831 }
01832
01833
01834
01835
01836
01837 while (bitpos + numbits > 8) {
01838
01839 bits = 8 - bitpos;
01840
01841 shiftwidth = numbits - bits;
01842
01843 mask = (1 << bits) - 1;
01844
01845 c = (value >> shiftwidth) & mask;
01846
01847 gw_assert(pos < ostr->len);
01848 ostr->data[pos] = (ostr->data[pos] & ~mask) | c;
01849 numbits -= (8 - bitpos);
01850 bitpos = 0;
01851 pos++;
01852 }
01853
01854 gw_assert(bitpos == 0);
01855 gw_assert(pos < ostr->len);
01856
01857
01858 mask = (1 << numbits) - 1;
01859 shiftwidth = 8 - numbits;
01860 c = ostr->data[pos] & ~(mask << shiftwidth);
01861 c |= value << shiftwidth;
01862 ostr->data[pos] = c;
01863
01864 seems_valid(ostr);
01865 }
01866
01867
01868 void octstr_append_uintvar(Octstr *ostr, unsigned long value)
01869 {
01870
01871
01872 unsigned char octets[5];
01873 int i;
01874 int start;
01875
01876
01877
01878 octets[4] = value & 0x7f;
01879 value >>= 7;
01880
01881 for (i = 3; value > 0 && i >= 0; i--) {
01882 octets[i] = 0x80 | (value & 0x7f);
01883 value >>= 7;
01884 }
01885 start = i + 1;
01886
01887 octstr_append_data(ostr, octets + start, 5 - start);
01888 }
01889
01890
01891 long octstr_extract_uintvar(Octstr *ostr, unsigned long *value, long pos)
01892 {
01893 int c;
01894 int count;
01895 unsigned long ui;
01896
01897 ui = 0;
01898 for (count = 0; count < 5; count++) {
01899 c = octstr_get_char(ostr, pos + count);
01900 if (c < 0)
01901 return -1;
01902 ui = (ui << 7) | (c & 0x7f);
01903 if (!(c & 0x80)) {
01904 *value = ui;
01905 return pos + count + 1;
01906 }
01907 }
01908
01909 return -1;
01910 }
01911
01912
01913 void octstr_append_decimal(Octstr *ostr, long value)
01914 {
01915 char tmp[128];
01916
01917 sprintf(tmp, "%ld", value);
01918 octstr_append_cstr(ostr, tmp);
01919 }
01920
01921
01922
01923
01924
01925
01926
01927 static void octstr_dump_debug(const Octstr *ostr, int level)
01928 {
01929 unsigned char *p, *d, buf[1024], charbuf[256];
01930 long pos;
01931 const int octets_per_line = 16;
01932 int c, this_line_begins_at;
01933
01934 if (ostr == NULL)
01935 return;
01936
01937 seems_valid(ostr);
01938
01939 debug("gwlib.octstr", 0, "%*sOctet string at %p:", level, "",
01940 (void *) ostr);
01941 debug("gwlib.octstr", 0, "%*s len: %lu", level, "",
01942 (unsigned long) ostr->len);
01943 debug("gwlib.octstr", 0, "%*s size: %lu", level, "",
01944 (unsigned long) ostr->size);
01945 debug("gwlib.octstr", 0, "%*s immutable: %d", level, "",
01946 ostr->immutable);
01947
01948 buf[0] = '\0';
01949 p = buf;
01950 d = charbuf;
01951 this_line_begins_at = 0;
01952 for (pos = 0; pos < octstr_len(ostr); ) {
01953 c = octstr_get_char(ostr, pos);
01954 sprintf(p, "%02x ", c);
01955 p = strchr(p, '\0');
01956 if (isprint(c))
01957 *d++ = c;
01958 else
01959 *d++ = '.';
01960 ++pos;
01961 if (pos - this_line_begins_at == octets_per_line) {
01962 *d = '\0';
01963 debug("gwlib.octstr", 0, "%*s data: %s %s", level, "",
01964 buf, charbuf);
01965 buf[0] = '\0';
01966 charbuf[0] = '\0';
01967 p = buf;
01968 d = charbuf;
01969 this_line_begins_at = pos;
01970 }
01971 }
01972 if (pos - this_line_begins_at > 0) {
01973 *d = '\0';
01974 debug("gwlib.octstr", 0, "%*s data: %-*.*s %s", level, "",
01975 octets_per_line*3,
01976 octets_per_line*3, buf, charbuf);
01977 }
01978
01979 debug("gwlib.octstr", 0, "%*sOctet string dump ends.", level, "");
01980 }
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992 #define LLinfo info
01993 #define LLwarning warning
01994 #define LLerror error
01995
01996 #define octstr_dump_LOGLEVEL(loglevel, ostr, level) \
01997 do { \
01998 unsigned char *p, *d, buf[1024], charbuf[256]; \
01999 long pos; \
02000 const int octets_per_line = 16; \
02001 int c, this_line_begins_at; \
02002 \
02003 if (ostr == NULL) \
02004 return; \
02005 \
02006 seems_valid(ostr); \
02007 \
02008 LL##loglevel(0, "%*sOctet string at %p:", level, "", \
02009 (void *) ostr); \
02010 LL##loglevel(0, "%*s len: %lu", level, "", \
02011 (unsigned long) ostr->len); \
02012 LL##loglevel(0, "%*s size: %lu", level, "", \
02013 (unsigned long) ostr->size); \
02014 LL##loglevel(0, "%*s immutable: %d", level, "", \
02015 ostr->immutable); \
02016 \
02017 buf[0] = '\0'; \
02018 p = buf; \
02019 d = charbuf; \
02020 this_line_begins_at = 0; \
02021 for (pos = 0; pos < octstr_len(ostr); ) { \
02022 c = octstr_get_char(ostr, pos); \
02023 sprintf(p, "%02x ", c); \
02024 p = strchr(p, '\0'); \
02025 if (isprint(c)) \
02026 *d++ = c; \
02027 else \
02028 *d++ = '.'; \
02029 ++pos; \
02030 if (pos - this_line_begins_at == octets_per_line) { \
02031 *d = '\0'; \
02032 LL##loglevel(0, "%*s data: %s %s", level, "", \
02033 buf, charbuf); \
02034 buf[0] = '\0'; \
02035 charbuf[0] = '\0'; \
02036 p = buf; \
02037 d = charbuf; \
02038 this_line_begins_at = pos; \
02039 } \
02040 } \
02041 if (pos - this_line_begins_at > 0) { \
02042 *d = '\0'; \
02043 LL##loglevel(0, "%*s data: %-*.*s %s", level, "", \
02044 octets_per_line*3, \
02045 octets_per_line*3, buf, charbuf); \
02046 } \
02047 \
02048 LL##loglevel(0, "%*sOctet string dump ends.", level, ""); \
02049 } while (0)
02050
02051
02052 void octstr_dump_real(const Octstr *ostr, int level, ...)
02053 {
02054 va_list p;
02055 unsigned int loglevel;
02056
02057 va_start(p, level);
02058 loglevel = va_arg(p, unsigned int);
02059 va_end(p);
02060
02061 switch (loglevel) {
02062 case GW_DEBUG:
02063 octstr_dump_debug(ostr, level);
02064 break;
02065 case GW_INFO:
02066 octstr_dump_LOGLEVEL(info, ostr, level);
02067 break;
02068 case GW_WARNING:
02069 octstr_dump_LOGLEVEL(warning, ostr, level);
02070 break;
02071 case GW_ERROR:
02072 octstr_dump_LOGLEVEL(error, ostr, level);
02073 break;
02074 default:
02075 octstr_dump_debug(ostr, level);
02076 break;
02077 }
02078 }
02079
02080
02081 void octstr_dump_short(Octstr *ostr, int level, const char *name)
02082 {
02083 char buf[100];
02084 char *p;
02085 long i;
02086 int c;
02087
02088 if (ostr == NULL) {
02089 debug("gwlib.octstr", 0, "%*s%s: NULL", level, "", name);
02090 return;
02091 }
02092
02093 seems_valid(ostr);
02094
02095 if (ostr->len < 20) {
02096 p = buf;
02097 for (i = 0; i < ostr->len; i++) {
02098 c = ostr->data[i];
02099 if (c == '\n') {
02100 *p++ = '\\';
02101 *p++ = 'n';
02102 } else if (!isprint(c)) {
02103 break;
02104 } else if (c == '"') {
02105 *p++ = '\\';
02106 *p++ = '"';
02107 } else if (c == '\\') {
02108 *p++ = '\\';
02109 *p++ = '\\';
02110 } else {
02111 *p++ = c;
02112 }
02113 }
02114 if (i == ostr->len) {
02115 *p++ = 0;
02116
02117
02118 debug("gwlib.octstr", 0, "%*s%s: \"%s\"", level, "", name, buf);
02119 return;
02120 }
02121 }
02122
02123 debug("gwlib.octstr", 0, "%*s%s:", level, "", name);
02124 octstr_dump(ostr, level + 1);
02125 }
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137
02138 struct format
02139 {
02140 int minus;
02141 int zero;
02142
02143 long min_width;
02144
02145 int has_prec;
02146 long prec;
02147
02148 long type;
02149 };
02150
02151
02152 static void format_flags(struct format *format, const char **fmt)
02153 {
02154 int done;
02155
02156 done = 0;
02157 do
02158 {
02159 switch (**fmt) {
02160 case '-':
02161 format->minus = 1;
02162 break;
02163
02164 case '0':
02165 format->zero = 1;
02166 break;
02167
02168 default:
02169 done = 1;
02170 }
02171
02172 if (!done)
02173 ++(*fmt);
02174 } while (!done);
02175 }
02176
02177
02178 static void format_width(struct format *format, const char **fmt,
02179 VALPARM(args))
02180 {
02181 char *end;
02182
02183 if (**fmt == '*')
02184 {
02185 format->min_width = va_arg(VALST(args), int);
02186 ++(*fmt);
02187 } else if (isdigit(**(const unsigned char **) fmt))
02188 {
02189 format->min_width = strtol(*fmt, &end, 10);
02190 *fmt = end;
02191
02192 }
02193 }
02194
02195
02196 static void format_prec(struct format *format, const char **fmt,
02197 VALPARM(args))
02198 {
02199 char *end;
02200
02201 if (**fmt != '.')
02202 return;
02203 ++(*fmt);
02204 if (**fmt == '*')
02205 {
02206 format->has_prec = 1;
02207 format->prec = va_arg(VALST(args), int);
02208 ++(*fmt);
02209 } else if (isdigit(**(const unsigned char **) fmt))
02210 {
02211 format->has_prec = 1;
02212 format->prec = strtol(*fmt, &end, 10);
02213 *fmt = end;
02214
02215 }
02216 }
02217
02218
02219 static void format_type(struct format *format, const char **fmt)
02220 {
02221 switch (**fmt)
02222 {
02223 case 'h':
02224 case 'l':
02225 format->type = **fmt;
02226 ++(*fmt);
02227 break;
02228 }
02229 }
02230
02231
02232 static void convert(Octstr *os, struct format *format, const char **fmt,
02233 VALPARM(args))
02234 {
02235 Octstr *new;
02236 char *s, *pad;
02237 long n;
02238 unsigned long u;
02239 char tmpfmt[1024];
02240 char tmpbuf[1024];
02241 char c;
02242 void *p;
02243
02244 new = NULL;
02245
02246 switch (**fmt)
02247 {
02248 case 'c':
02249 c = va_arg(VALST(args), int);
02250 new = octstr_create_from_data(&c, 1);
02251 break;
02252
02253 case 'd':
02254 case 'i':
02255 switch (format->type) {
02256 case 'l':
02257 n = va_arg(VALST(args), long);
02258 break;
02259 case 'h':
02260 n = (short) va_arg(VALST(args), int);
02261 break;
02262 default:
02263 n = va_arg(VALST(args), int);
02264 break;
02265 }
02266 new = octstr_create("");
02267 octstr_append_decimal(new, n);
02268 break;
02269
02270 case 'o':
02271 case 'u':
02272 case 'x':
02273 case 'X':
02274 switch (format->type) {
02275 case 'l':
02276 u = va_arg(VALST(args), unsigned long);
02277 break;
02278 case 'h':
02279 u = (unsigned short) va_arg(VALST(args), unsigned int);
02280 break;
02281 default:
02282 u = va_arg(VALST(args), unsigned int);
02283 break;
02284 }
02285 tmpfmt[0] = '%';
02286 tmpfmt[1] = 'l';
02287 tmpfmt[2] = **fmt;
02288 tmpfmt[3] = '\0';
02289 sprintf(tmpbuf, tmpfmt, u);
02290 new = octstr_create(tmpbuf);
02291 break;
02292
02293 case 'e':
02294 case 'f':
02295 case 'g':
02296 sprintf(tmpfmt, "%%");
02297 if (format->minus)
02298 strcat(tmpfmt, "-");
02299 if (format->zero)
02300 strcat(tmpfmt, "0");
02301 if (format->min_width > 0)
02302 sprintf(strchr(tmpfmt, '\0'),
02303 "%ld", format->min_width);
02304 if (format->has_prec)
02305 sprintf(strchr(tmpfmt, '\0'),
02306 ".%ld", format->prec);
02307 if (format->type != '\0')
02308 sprintf(strchr(tmpfmt, '\0'),
02309 "%c", (int) format->type);
02310 sprintf(strchr(tmpfmt, '\0'), "%c", **fmt);
02311 snprintf(tmpbuf, sizeof(tmpbuf),
02312 tmpfmt, va_arg(VALST(args), double));
02313 new = octstr_create(tmpbuf);
02314 break;
02315
02316 case 's':
02317 s = va_arg(VALST(args), char *);
02318 if (format->has_prec && format->prec < (long) strlen(s))
02319 n = format->prec;
02320 else
02321 n = (long) strlen(s);
02322 new = octstr_create_from_data(s, n);
02323 break;
02324
02325 case 'p':
02326 p = va_arg(VALST(args), void *);
02327 sprintf(tmpfmt, "%p", p);
02328 new = octstr_create(tmpfmt);
02329 break;
02330
02331 case 'S':
02332 new = octstr_duplicate(va_arg(VALST(args), Octstr *));
02333 if (!new)
02334 new = octstr_create("(null)");
02335 if (format->has_prec)
02336 octstr_truncate(new, format->prec);
02337 break;
02338
02339 case 'E':
02340 new = octstr_duplicate(va_arg(VALST(args), Octstr *));
02341 if (!new)
02342 new = octstr_create("(null)");
02343 octstr_url_encode(new);
02344
02345
02346
02347 if (format->has_prec)
02348 octstr_truncate(new, format->prec);
02349 break;
02350
02351 case 'H':
02352 new = octstr_duplicate(va_arg(VALST(args), Octstr *));
02353 if (!new)
02354 new = octstr_create("(null)");
02355
02356 octstr_binary_to_hex(new, 1);
02357 if (format->has_prec)
02358 octstr_truncate(new, (format->prec % 2 ? format->prec - 1 : format->prec));
02359 break;
02360
02361 case '%':
02362 new = octstr_create("%");
02363 break;
02364
02365 default:
02366 panic(0, "octstr_format format string syntax error.");
02367 }
02368
02369 if (format->zero)
02370 pad = "0";
02371 else
02372 pad = " ";
02373
02374 if (format->minus) {
02375 while (format->min_width > octstr_len(new))
02376 octstr_append_data(new, pad, 1);
02377 } else {
02378 while (format->min_width > octstr_len(new))
02379 octstr_insert_data(new, 0, pad, 1);
02380 }
02381
02382 octstr_append(os, new);
02383 octstr_destroy(new);
02384
02385 if (**fmt != '\0')
02386 ++(*fmt);
02387 }
02388
02389
02390 Octstr *octstr_format(const char *fmt, ...)
02391 {
02392 Octstr *os;
02393 va_list args;
02394
02395 va_start(args, fmt);
02396 os = octstr_format_valist(fmt, args);
02397 va_end(args);
02398 return os;
02399 }
02400
02401
02402 Octstr *octstr_format_valist_real(const char *fmt, va_list args)
02403 {
02404 Octstr *os;
02405 size_t n;
02406
02407 os = octstr_create("");
02408
02409 while (*fmt != '\0') {
02410 struct format format = { 0, };
02411
02412 n = strcspn(fmt, "%");
02413 octstr_append_data(os, fmt, n);
02414 fmt += n;
02415
02416 gw_assert(*fmt == '%' || *fmt == '\0');
02417 if (*fmt == '\0')
02418 continue;
02419
02420 ++fmt;
02421 format_flags(&format, &fmt);
02422 format_width(&format, &fmt, VARGS(args));
02423 format_prec(&format, &fmt, VARGS(args));
02424 format_type(&format, &fmt);
02425 convert(os, &format, &fmt, VARGS(args));
02426 }
02427
02428 seems_valid(os);
02429 return os;
02430 }
02431
02432
02433 void octstr_format_append(Octstr *os, const char *fmt, ...)
02434 {
02435 Octstr *temp;
02436 va_list args;
02437
02438 va_start(args, fmt);
02439 temp = octstr_format_valist(fmt, args);
02440 va_end(args);
02441 octstr_append(os, temp);
02442 octstr_destroy(temp);
02443 }
02444
02445
02446 unsigned long octstr_hash_key(Octstr *ostr)
02447 {
02448 unsigned long key = 0;
02449 long i;
02450
02451 if (ostr == NULL)
02452 return 0;
02453
02454 for (i = 0; i < octstr_len(ostr); i++)
02455 key = key + octstr_get_char(ostr, i);
02456
02457 return key;
02458 }
02459
02460
02461
02462
02463
02464
02465 static void seems_valid_real(const Octstr *ostr, const char *filename, long lineno,
02466 const char *function)
02467 {
02468 gw_assert(immutables_init);
02469 gw_assert_place(ostr != NULL,
02470 filename, lineno, function);
02471 gw_assert_allocated(ostr,
02472 filename, lineno, function);
02473 gw_assert_place(ostr->len >= 0,
02474 filename, lineno, function);
02475 gw_assert_place(ostr->size >= 0,
02476 filename, lineno, function);
02477 if (ostr->size == 0) {
02478 gw_assert_place(ostr->len == 0,
02479 filename, lineno, function);
02480 gw_assert_place(ostr->data == NULL,
02481 filename, lineno, function);
02482 } else {
02483 gw_assert_place(ostr->len + 1 <= ostr->size,
02484 filename, lineno, function);
02485 gw_assert_place(ostr->data != NULL,
02486 filename, lineno, function);
02487 if (!ostr->immutable)
02488 gw_assert_allocated(ostr->data,
02489 filename, lineno, function);
02490 gw_assert_place(ostr->data[ostr->len] == '\0',
02491 filename, lineno, function);
02492 }
02493 }
02494
02495 int
02496 octstr_recode (Octstr *tocode, Octstr *fromcode, Octstr *orig)
02497 {
02498 Octstr *octstr_utf8 = NULL;
02499 Octstr *octstr_final = NULL;
02500 int resultcode = 0;
02501
02502 if (octstr_case_compare(tocode, fromcode) == 0) {
02503 goto cleanup_and_exit;
02504 }
02505
02506 if ((octstr_case_compare(fromcode, octstr_imm ("UTF-8")) != 0) &&
02507 (octstr_case_compare(fromcode, octstr_imm ("UTF8")) != 0)) {
02508 if (charset_to_utf8(orig, &octstr_utf8, fromcode) < 0) {
02509 resultcode = -1;
02510 goto cleanup_and_exit;
02511 }
02512 } else {
02513 octstr_utf8 = octstr_duplicate(orig);
02514 }
02515
02516 if ((octstr_case_compare(tocode, octstr_imm ("UTF-8")) != 0) &&
02517 (octstr_case_compare(tocode, octstr_imm ("UTF8")) != 0)) {
02518 if (charset_from_utf8(octstr_utf8, &octstr_final, tocode) < 0) {
02519 resultcode = -1;
02520 goto cleanup_and_exit;
02521 }
02522 } else {
02523 octstr_final = octstr_duplicate(octstr_utf8);
02524 }
02525
02526 octstr_truncate(orig, 0);
02527 octstr_append(orig, octstr_final);
02528
02529 cleanup_and_exit:
02530 octstr_destroy (octstr_utf8);
02531 octstr_destroy (octstr_final);
02532
02533 return resultcode;
02534 }
02535
02536 void octstr_strip_char(Octstr *text, char ch)
02537 {
02538 int start = 0;
02539
02540 seems_valid(text);
02541 gw_assert(!text->immutable);
02542
02543
02544 while ((ch == octstr_get_char(text, start)) &&
02545 start <= octstr_len(text))
02546 start ++;
02547
02548 if (start > 0)
02549 octstr_delete(text, 0, start);
02550
02551 seems_valid(text);
02552 }
02553
02554 int octstr_isnum(Octstr *ostr1)
02555 {
02556 int start = 0;
02557 char c;
02558
02559 seems_valid(ostr1);
02560 while (start < octstr_len(ostr1)) {
02561 c = octstr_get_char(ostr1, start);
02562 if (!isdigit(c) && (c!='+'))
02563 return 0;
02564 start++;
02565 }
02566 return 1;
02567 }
02568
02569 void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl)
02570 {
02571 int p = 0;
02572 long len, repl_len;
02573
02574 len = octstr_len(needle);
02575 repl_len = octstr_len(repl);
02576
02577 while ((p = octstr_search(haystack, needle, p)) != -1) {
02578 octstr_delete(haystack, p, len);
02579 octstr_insert(haystack, repl, p);
02580 p += repl_len;
02581 }
02582 }
02583
02584 int octstr_symbolize(Octstr *ostr)
02585 {
02586 long len, i;
02587
02588 seems_valid(ostr);
02589 gw_assert(!ostr->immutable);
02590
02591 if (ostr->len == 0)
02592 return 0;
02593
02594
02595 if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit))
02596 return -1;
02597
02598 len = ostr->len + (ostr->len/2);
02599 octstr_grow(ostr, ostr->len * 2);
02600
02601 for (i = 0; i < len; i += 3)
02602 octstr_insert_data(ostr, i, "%", 1);
02603
02604 return 1;
02605 }
02606
02607 void octstr_delete_matching(Octstr *haystack, Octstr *needle)
02608 {
02609 int p = 0;
02610 long len;
02611
02612 seems_valid(haystack);
02613 seems_valid(needle);
02614 gw_assert(!haystack->immutable);
02615 len = octstr_len(needle);
02616
02617 while ((p = octstr_search(haystack, needle, p)) != -1) {
02618 octstr_delete(haystack, p, len);
02619 }
02620 }
02621
02622 int octstr_is_all_hex(Octstr *os)
02623 {
02624 long len, i;
02625 int ch;
02626
02627 seems_valid(os);
02628 len = octstr_len(os);
02629 for (i = 0; i < len; ++i) {
02630 ch = octstr_get_char(os, i);
02631 if (!gw_isxdigit(ch))
02632 return 0;
02633 }
02634
02635 return 1;
02636 }
02637
02638
02639
02640
02641
02642
02643 void octstr_convert_to_html_entities(Octstr* input)
02644 {
02645 int i;
02646
02647 for (i = 0; i < octstr_len(input); ++i) {
02648 switch (octstr_get_char(input, i)) {
02649 #define ENTITY(a,b) \
02650 case a: \
02651 octstr_delete(input, i, 1); \
02652 octstr_insert(input, octstr_imm("&" b ";"), i); \
02653 i += sizeof(b); break;
02654 #include "gwlib/html-entities.def"
02655 #undef ENTITY
02656 }
02657 }
02658 }
02659
02660
02661
02662
02663
02664
02665 static int octstr_find_entity(Octstr* input, int startfind, int endfind)
02666 {
02667 #define ENTITY(a,b) { a, b },
02668 struct entity_struct {
02669 int entity;
02670 char *entity_str;
02671 };
02672 const struct entity_struct entities[] = {
02673 #include "html-entities.def"
02674 { -1, "" }
02675 };
02676 #undef ENTITY
02677 int center;
02678 int matchresult;
02679
02680 if (endfind == 0) {
02681
02682
02683 endfind = (sizeof(entities) / sizeof(struct entity_struct)) - 1;
02684 }
02685 center = startfind + ((endfind - startfind) / 2);
02686 matchresult = octstr_str_compare(input, entities[center].entity_str);
02687 if (matchresult == 0) {
02688 return entities[center].entity;
02689 }
02690 if (endfind - startfind <= 1) {
02691
02692 return -1;
02693 }
02694 if (matchresult < 0) {
02695
02696 return octstr_find_entity(input, startfind, center);
02697 } else {
02698
02699 return octstr_find_entity(input, center, endfind);
02700 }
02701 }
02702
02703
02704
02705
02706
02707
02708
02709 void octstr_convert_from_html_entities(Octstr* input)
02710 {
02711 int startpos = 0, endpos;
02712 int entity;
02713 Octstr *match;
02714
02715 while ((startpos = octstr_search_char(input, '&', startpos)) != -1) {
02716 endpos = octstr_search_char(input, ';', startpos + 1);
02717 if (endpos >= 0) {
02718 match = octstr_copy(input, startpos + 1, endpos - startpos - 1);
02719 entity = octstr_find_entity(match, 0, 0);
02720 if (entity >= 0) {
02721 octstr_delete(input, startpos, endpos - startpos + 1);
02722 octstr_insert_char(input, startpos, entity);
02723 }
02724 octstr_destroy(match);
02725 }
02726 startpos++;
02727 }
02728 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.