C / C ++ URL解码库

时间:2010-04-20 07:04:03

标签: c++ c linux

我正在linux上开发一个c / c ++程序。如果有任何c / c ++库解码url,你能告诉我吗?

我正在寻找哪些图书馆 兑换 的 “http%3A%2F%2F” 至: 的 “http://”

或 “a + t +%26 + t”到“t& t”

谢谢。

10 个答案:

答案 0 :(得分:23)

我实际上在我正在编写的分析程序中使用了Saul的功能(分析了数百万个URL编码的字符串),虽然它有效,但是在这个规模上它使我的程序放慢了速度,所以我决定写一个更快的版本。使用GCC和-O2选项编译时,这个速度要快几千倍。它也可以使用与输入相同的输出缓冲区(例如,如果原始字符串在buf中并且要被其解码的副本覆盖,则urldecode2(buf,buf)将起作用。)

编辑:它没有将缓冲区大小作为输入,因为假设缓冲区足够大,这是安全的,因为已知输出的长度总是be< =输入的那个,所以要么为输出使用相同的缓冲区,要么创建一个至少为null终止符的输入+ 1的大小,例如:

char *output = malloc(strlen(input)+1);
urldecode2(output, input);
printf("Decoded string: %s\n", output);

编辑2:一位匿名用户试图编辑此答案以处理'+'字符对''的翻译,我认为应该这样做,这不是我需要的东西对于我的申请,但我在下面添加了它。

这是例程:

#include <stdlib.h>
#include <ctype.h>

void urldecode2(char *dst, const char *src)
{
        char a, b;
        while (*src) {
                if ((*src == '%') &&
                    ((a = src[1]) && (b = src[2])) &&
                    (isxdigit(a) && isxdigit(b))) {
                        if (a >= 'a')
                                a -= 'a'-'A';
                        if (a >= 'A')
                                a -= ('A' - 10);
                        else
                                a -= '0';
                        if (b >= 'a')
                                b -= 'a'-'A';
                        if (b >= 'A')
                                b -= ('A' - 10);
                        else
                                b -= '0';
                        *dst++ = 16*a+b;
                        src+=3;
                } else if (*src == '+') {
                        *dst++ = ' ';
                        src++;
                } else {
                        *dst++ = *src++;
                }
        }
        *dst++ = '\0';
}

答案 1 :(得分:4)

这是一个百分比编码字符串的C解码器。如果编码无效则返回-1,否则返回0。解码后的字符串存储在out中。我非常确定这是迄今为止给出的答案中最快的代码。

int percent_decode(char* out, const char* in) {
{
    static const char tbl[256] = {
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
         0, 1, 2, 3, 4, 5, 6, 7,  8, 9,-1,-1,-1,-1,-1,-1,
        -1,10,11,12,13,14,15,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,10,11,12,13,14,15,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1
    };
    char c, v1, v2, beg=out;
    if(in != NULL) {
        while((c=*in++) != '\0') {
            if(c == '%') {
                if(!(v1=*in++) || (v1=tbl[(unsigned char)v1])<0 || 
                   !(v2=*in++) || (v2=tbl[(unsigned char)v2])<0) {
                    *beg = '\0';
                    return -1;
                }
                c = (v1<<4)|v2;
            }
            *out++ = c;
        }
    }
    *out = '\0';
    return 0;
}

答案 2 :(得分:3)

卓越的glib有一些URI functions,包括计划提取,转义和取消转义。

答案 3 :(得分:3)

这个我刚刚掀起的功能非常轻巧,应该按照您的意愿行事,请注意我没有将其编程为严格的URI标准(使用我所知道的顶部)。这是缓冲安全的,并且我没有看到溢出;适应你认为适合:

#include <assert.h>

void urldecode(char *pszDecodedOut, size_t nBufferSize, const char *pszEncodedIn)
{
    memset(pszDecodedOut, 0, nBufferSize);

    enum DecodeState_e
    {
        STATE_SEARCH = 0, ///< searching for an ampersand to convert
        STATE_CONVERTING, ///< convert the two proceeding characters from hex
    };

    DecodeState_e state = STATE_SEARCH;

    for(unsigned int i = 0; i < strlen(pszEncodedIn)-1; ++i)
    {
        switch(state)
        {
        case STATE_SEARCH:
            {
                if(pszEncodedIn[i] != '%')
                {
                    strncat(pszDecodedOut, &pszEncodedIn[i], 1);
                    assert(strlen(pszDecodedOut) < nBufferSize);
                    break;
                }

                // We are now converting
                state = STATE_CONVERTING;
            }
            break;

        case STATE_CONVERTING:
            {
                // Conversion complete (i.e. don't convert again next iter)
                state = STATE_SEARCH;

                // Create a buffer to hold the hex. For example, if %20, this
                // buffer would hold 20 (in ASCII)
                char pszTempNumBuf[3] = {0};
                strncpy(pszTempNumBuf, &pszEncodedIn[i], 2);

                // Ensure both characters are hexadecimal
                bool bBothDigits = true;

                for(int j = 0; j < 2; ++j)
                {
                    if(!isxdigit(pszTempNumBuf[j]))
                        bBothDigits = false;
                }

                if(!bBothDigits)
                    break;

                // Convert two hexadecimal characters into one character
                int nAsciiCharacter;
                sscanf(pszTempNumBuf, "%x", &nAsciiCharacter);

                // Ensure we aren't going to overflow
                assert(strlen(pszDecodedOut) < nBufferSize);

                // Concatenate this character onto the output
                strncat(pszDecodedOut, (char*)&nAsciiCharacter, 1);

                // Skip the next character
                i++;
            }
            break;
        }
    }
}

答案 4 :(得分:2)

uriparser库小巧轻便。

答案 5 :(得分:1)

尝试urlcpp https://github.com/larroy/urlcpp 这是一个可以轻松集成到项目中的C ++模块,取决于boost :: regex

答案 6 :(得分:1)

我建议curl and libcurl。它被广泛使用,应该为你做的伎俩。只需查看他们的网站。

答案 7 :(得分:0)

/**
 * Locale-independent conversion of ASCII characters to lowercase.
 */
int av_tolower(int c)
{
    if (c >= 'A' && c <= 'Z')
        c ^= 0x20;
    return c;
}
/**
 * Decodes an URL from its percent-encoded form back into normal
 * representation. This function returns the decoded URL in a string.
 * The URL to be decoded does not necessarily have to be encoded but
 * in that case the original string is duplicated.
 *
 * @param url a string to be decoded.
 * @return new string with the URL decoded or NULL if decoding failed.
 * Note that the returned string should be explicitly freed when not
 * used anymore.
 */
char *urldecode(const char *url)
{
    int s = 0, d = 0, url_len = 0;
    char c;
    char *dest = NULL;

    if (!url)
        return NULL;

    url_len = strlen(url) + 1;
    dest = av_malloc(url_len);

    if (!dest)
        return NULL;

    while (s < url_len) {
        c = url[s++];

        if (c == '%' && s + 2 < url_len) {
            char c2 = url[s++];
            char c3 = url[s++];
            if (isxdigit(c2) && isxdigit(c3)) {
                c2 = av_tolower(c2);
                c3 = av_tolower(c3);

                if (c2 <= '9')
                    c2 = c2 - '0';
                else
                    c2 = c2 - 'a' + 10;

                if (c3 <= '9')
                    c3 = c3 - '0';
                else
                    c3 = c3 - 'a' + 10;

                dest[d++] = 16 * c2 + c3;

            } else { /* %zz or something other invalid */
                dest[d++] = c;
                dest[d++] = c2;
                dest[d++] = c3;
            }
        } else if (c == '+') {
            dest[d++] = ' ';
        } else {
            dest[d++] = c;
        }

    }

    return dest;
}

by
www.elesos.com

答案 8 :(得分:0)

感谢@ThomasH的回答。我想在这里提出一个更好的格式化......

并且......由于解码的URI组件始终长于相同的编码URI组件,因此始终可以在相同的字符数组中内爆它(也就是: “串”)。所以,我会在这里建议两种可能性

#include <stdio.h>

int decodeURIComponent (char *sSource, char *sDest) {
    int nLength;
    for (nLength = 0; *sSource; nLength++) {
        if (*sSource == '%' && sSource[1] && sSource[2] && isxdigit(sSource[1]) && isxdigit(sSource[2])) {
            sSource[1] -= sSource[1] <= '9' ? '0' : (sSource[1] <= 'F' ? 'A' : 'a')-10;
            sSource[2] -= sSource[2] <= '9' ? '0' : (sSource[2] <= 'F' ? 'A' : 'a')-10;
            sDest[nLength] = 16 * sSource[1] + sSource[2];
            sSource += 3;
            continue;
        }
        sDest[nLength] = *sSource++;
    }
    sDest[nLength] = '\0';
    return nLength;
}

#define implodeURIComponent(url) decodeURIComponent(url, url)

最后......:

int main () {

    char sMyUrl[] = "http%3a%2F%2ffoo+bar%2fabcd";

    int nNewLength = implodeURIComponent(sMyUrl);

    /* Let's print: "http://foo+bar/abcd\nLength: 19" */
    printf("%s\nLength: %d\n", sMyUrl, nNewLength);

    return 0;

}

步骤*

答案 9 :(得分:0)

这个与我寻找相同问题的问题已经有8年了。根据先前的答案,我还编写了自己的版本,该版本独立于libs,易于理解,而且速度可能很快(无基准)。使用gcc测试过的代码,应该解码直到结尾或无效字符(未经测试)。只记得释放分配的空间。

const char ascii_hex_4bit[23] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15};

static inline char to_upper(char c)
{
    if ((c >= 'a') && (c <= 'z')) return c ^ 0x20;
    return c;
}

char *url_decode(const char *str)
{
    size_t i, j, len = strlen(str);
    char c, d, url_hex;
    char *decoded = malloc(len + 1);

    if (decoded == NULL) return NULL;

    i = 0;
    j = 0;
    do
    {
        c = str[i];
        d = 0;

        if (c == '%')
        {
            url_hex = to_upper(str[++i]);
            if (((url_hex >= '0') && (url_hex <= '9')) || ((url_hex >= 'A') && (url_hex <= 'F')))
            {
                d = ascii_hex_4bit[url_hex - 48] << 4;

                url_hex = to_upper(str[++i]);
                if (((url_hex >= '0') && (url_hex <= '9')) || ((url_hex >= 'A') && (url_hex <= 'F')))
                {
                    d |= ascii_hex_4bit[url_hex - 48];
                }
                else
                {
                    d = 0;
                }
            }
        }
        else if (c == '+')
        {
            d = ' ';
        }
        else if ((c == '*') || (c == '-') || (c == '.') || ((c >= '0') && (c <= '9')) ||
        ((c >= 'A') && (c <= 'Z')) || (c == '_') || ((c >= 'a') && (c <= 'z')))
        {
            d = c;
        }

        decoded[j++] = d;
        ++i;
    } while ((i < len) && (d != 0));

    decoded[j] = 0;
    return decoded;
}