octstr.c
来自「The Kannel Open Source WAP and SMS gatew」· C语言 代码 · 共 2,586 行 · 第 1/5 页
C
2,586 行
ostr->data[i] = ostr->data[i * 2] * 16 | ostr->data[i * 2 + 1]; } ostr->len = len; ostr->data[len] = '\0'; seems_valid(ostr); return 0;}void octstr_binary_to_base64(Octstr *ostr){ static const unsigned char base64[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; long triplets; long lines; long orig_len; unsigned char *data; long from, to; int left_on_line; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) { /* Always terminate with CR LF */ octstr_insert(ostr, octstr_imm("\015\012"), 0); return; } /* The lines must be 76 characters each (or less), and each * triplet will expand to 4 characters, so we can fit 19 * triplets on one line. We need a CR LF after each line, * which will add 2 octets per 19 triplets (rounded up). */ triplets = (ostr->len + 2) / 3; /* round up */ lines = (triplets + 18) / 19; octstr_grow(ostr, triplets * 4 + lines * 2); orig_len = ostr->len; data = ostr->data; ostr->len = triplets * 4 + lines * 2; data[ostr->len] = '\0'; /* This function works back-to-front, so that encoded data will * not overwrite source data. * from points to the start of the last triplet (which may be * an odd-sized one), and to points to the start of where the * last quad should go. */ from = (triplets - 1) * 3; to = (triplets - 1) * 4 + (lines - 1) * 2; /* First write the CR LF after the last quad */ data[to + 5] = 10; /* LF */ data[to + 4] = 13; /* CR */ left_on_line = triplets - ((lines - 1) * 19); /* base64 encoding is in 3-octet units. To handle leftover * octets, conceptually we have to zero-pad up to the next * 6-bit unit, and pad with '=' characters for missing 6-bit * units. * We do it by first completing the first triplet with * zero-octets, and after the loop replacing some of the * result characters with '=' characters. * There is enough room for this, because even with a 1 or 2 * octet source string, space for four octets of output * will be reserved. */ switch (orig_len % 3) { case 0: break; case 1: data[orig_len] = 0; data[orig_len + 1] = 0; break; case 2: data[orig_len + 1] = 0; break; } /* Now we only have perfect triplets. */ while (from >= 0) { long whole_triplet; /* Add a newline, if necessary */ if (left_on_line == 0) { to -= 2; data[to + 5] = 10; /* LF */ data[to + 4] = 13; /* CR */ left_on_line = 19; } whole_triplet = (data[from] << 16) | (data[from + 1] << 8) | data[from + 2]; data[to + 3] = base64[whole_triplet % 64]; data[to + 2] = base64[(whole_triplet >> 6) % 64]; data[to + 1] = base64[(whole_triplet >> 12) % 64]; data[to] = base64[(whole_triplet >> 18) % 64]; to -= 4; from -= 3; left_on_line--; } gw_assert(left_on_line == 0); gw_assert(from == -3); gw_assert(to == -4); /* Insert padding characters in the last quad. Remember that * there is a CR LF between the last quad and the end of the * string. */ switch (orig_len % 3) { case 0: break; case 1: gw_assert(data[ostr->len - 3] == 'A'); gw_assert(data[ostr->len - 4] == 'A'); data[ostr->len - 3] = '='; data[ostr->len - 4] = '='; break; case 2: gw_assert(data[ostr->len - 3] == 'A'); data[ostr->len - 3] = '='; break; } seems_valid(ostr);}void octstr_base64_to_binary(Octstr *ostr){ long triplet; long pos, len; long to; int quadpos = 0; int warned = 0; unsigned char *data; seems_valid(ostr); gw_assert(!ostr->immutable); len = ostr->len; data = ostr->data; if (len == 0) return; to = 0; triplet = 0; quadpos = 0; for (pos = 0; pos < len; pos++) { int c = data[pos]; int sixbits; if (c >= 'A' && c <= 'Z') { sixbits = c - 'A'; } else if (c >= 'a' && c <= 'z') { sixbits = 26 + c - 'a'; } else if (c >= '0' && c <= '9') { sixbits = 52 + c - '0'; } else if (c == '+') { sixbits = 62; } else if (c == '/') { sixbits = 63; } else if (c == '=') { /* These can only occur at the end of encoded * text. RFC 2045 says we can assume it really * is the end. */ break; } else if (isspace(c)) { /* skip whitespace */ continue; } else { if (!warned) { warning(0, "Unusual characters in base64 " "encoded text."); warned = 1; } continue; } triplet = (triplet << 6) | sixbits; quadpos++; if (quadpos == 4) { data[to++] = (triplet >> 16) & 0xff; data[to++] = (triplet >> 8) & 0xff; data[to++] = triplet & 0xff; quadpos = 0; } } /* Deal with leftover octets */ switch (quadpos) { case 0: break; case 3: /* triplet has 18 bits, we want the first 16 */ data[to++] = (triplet >> 10) & 0xff; data[to++] = (triplet >> 2) & 0xff; break; case 2: /* triplet has 12 bits, we want the first 8 */ data[to++] = (triplet >> 4) & 0xff; break; case 1: warning(0, "Bad padding in base64 encoded text."); break; } ostr->len = to; data[to] = '\0'; seems_valid(ostr);}long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base){ /* strtol wants a char *, and we have to compare the result to * an unsigned char *. The easiest way to avoid warnings without * introducing typecasts is to use two variables. */ char *endptr; unsigned char *endpos; long number; seems_valid(ostr); gw_assert(nump != NULL); gw_assert(base == 0 || (base >= 2 && base <= 36)); if (pos >= ostr->len) { errno = EINVAL; return -1; } errno = 0; number = strtol(ostr->data + pos, &endptr, base); endpos = endptr; if (errno == ERANGE) return -1; if (endpos == ostr->data + pos) { errno = EINVAL; return -1; } *nump = number; return endpos - ostr->data;}long octstr_parse_double(double *nump, Octstr *ostr, long pos){ /* strtod wants a char *, and we have to compare the result to * an unsigned char *. The easiest way to avoid warnings without * introducing typecasts is to use two variables. */ char *endptr; unsigned char *endpos; double number; seems_valid(ostr); gw_assert(nump != NULL); if (pos >= ostr->len) { errno = EINVAL; return -1; } errno = 0; number = strtod(ostr->data + pos, &endptr); endpos = endptr; if (errno == ERANGE) return -1; if (endpos == ostr->data + pos) { errno = EINVAL; return -1; } *nump = number; return endpos - ostr->data;}int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter){ long end = pos + len; seems_valid(ostr); gw_assert(len >= 0); if (pos >= ostr->len) return 1; if (end > ostr->len) end = ostr->len; for ( ; pos < end; pos++) { if (!filter(ostr->data[pos])) return 0; } return 1;}void octstr_convert_range(Octstr *ostr, long pos, long len, octstr_func_t map){ long end = pos + len; seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(len >= 0); if (pos >= ostr->len) return; if (end > ostr->len) end = ostr->len; for ( ; pos < end; pos++) { ostr->data[pos] = map(ostr->data[pos]); } seems_valid(ostr);}int octstr_compare(const Octstr *ostr1, const Octstr *ostr2){ int ret; long len; seems_valid(ostr1); seems_valid(ostr2); if (ostr1->len < ostr2->len) len = ostr1->len; else len = ostr2->len; if (len == 0) { if (ostr1->len == 0 && ostr2->len > 0) return -1; if (ostr1->len > 0 && ostr2->len == 0) return 1; return 0; } ret = memcmp(ostr1->data, ostr2->data, len); if (ret == 0) { if (ostr1->len < ostr2->len) ret = -1; else if (ostr1->len > ostr2->len) ret = 1; } return ret;}int octstr_case_compare(const Octstr *os1, const Octstr *os2){ int c1, c2; long i, len; seems_valid(os1); seems_valid(os2); if (os1->len < os2->len) len = os1->len; else len = os2->len; if (len == 0) { if (os1->len == 0 && os2->len > 0) return -1; if (os1->len > 0 && os2->len == 0) return 1; return 0; } for (i = 0; i < len; ++i) { c1 = toupper(os1->data[i]); c2 = toupper(os2->data[i]); if (c1 != c2) break; } if (i == len) { if (i == os1->len && i == os2->len) return 0; if (i == os1->len) return -1; return 1; } else { c1 = toupper(os1->data[i]); c2 = toupper(os2->data[i]); if (c1 < c2) return -1; if (c1 == c2) return 0; return 1; }}int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n){ long len; seems_valid(ostr1); seems_valid(ostr2); if ((ostr1->len < ostr2->len) && (ostr1->len < n)) len = ostr1->len; else if ((ostr2->len < ostr1->len) && (ostr2->len < n)) len = ostr2->len; else len = n; if (len == 0) return 0; return memcmp(ostr1->data, ostr2->data, len);}int octstr_str_compare(const Octstr *ostr, const char *str){ seems_valid(ostr); if (str == NULL) return -1; if (ostr->data == NULL) return strcmp("", str); return strcmp(ostr->data, str);}int octstr_str_ncompare(const Octstr *ostr, const char *str, long n){ seems_valid(ostr); if (str == NULL) return -1; if (ostr->data == NULL) return 1; /* str grater */ return strncmp(ostr->data, str, n);}int octstr_search_char(const Octstr *ostr, int ch, long pos){ unsigned char *p; seems_valid(ostr); gw_assert(ch >= 0); gw_assert(ch <= UCHAR_MAX); gw_assert(pos >= 0); if (pos >= ostr->len) return -1; p = memchr(ostr->data + pos, ch, ostr->len - pos); if (!p) return -1; return p - ostr->data;}int octstr_search_chars(const Octstr *ostr, const Octstr *chars, long pos){ long i, j; seems_valid(ostr); seems_valid(chars); gw_assert(pos >= 0); for (i = 0; i < octstr_len(chars); i++) { j = octstr_search_char(ostr, octstr_get_char(chars, i), pos); if (j != -1) return j; } return -1;}int octstr_search(const Octstr *haystack, const Octstr *needle, long pos){ int first; seems_valid(haystack); seems_valid(needle); gw_assert(pos >= 0); /* Always "find" an empty string */ if (needle->len == 0) return 0; if (needle->len == 1) return octstr_search_char(haystack, needle->data[0], pos); /* For each occurrence of needle's first character in ostr, * check if the rest of needle follows. Stop if there are no * more occurrences, or if the rest of needle can't possibly * fit in the haystack. */ first = needle->data[0]; pos = octstr_search_char(haystack, first, pos); while (pos >= 0 && haystack->len - pos >= needle->len) { if (memcmp(haystack->data + pos, needle->data, needle->len) == 0) return pos; pos = octstr_search_char(haystack, first, pos + 1); } return -1;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?