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 + -
显示快捷键?