Библиотека декодирования URL-адресов C/С++

Я разрабатываю программу c/С++ для linux. Не могли бы вы рассказать мне, есть ли библиотека c/С++, которая расшифровывает URL-адрес?

Я ищу библиотеки, которые конвертировать "HTTP% 3A% 2F% 2F" чтобы: "HTTP://"

или "a + t +% 26 + t" до "a t и t"

Спасибо.

Ответ 1

Фактически я использовал функцию Саула в аналитической программе, которую я писал (анализируя миллионы строк с кодировкой URL), и, хотя она работает, в этом масштабе она очень замедляла мою программу, поэтому я решил написать более быструю версию. Это в тысячу раз быстрее при компиляции с GCC и опцией -O2. Он также может использовать тот же выходной буфер, что и вход (например, urldecode2 (buf, buf) будет работать, если исходная строка была в buf и должна быть перезаписана его декодированной копией).

Изменить: Он не принимает размер буфера в качестве ввода, поскольку предполагается, что буфер будет достаточно большим, это безопасно, поскольку известно, что длина вывода всегда будет be <= the the input, поэтому либо используйте один и тот же буфер для вывода, либо создайте тот, который по меньшей мере имеет размер ввода + 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';
}

Ответ 2

Вот 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=tbl[(unsigned char)*in++])<0 || 
                   (v2=tbl[(unsigned char)*in++])<0) {
                    *beg = '\0';
                    return -1;
                }
                c = (v1<<4)|v2;
            }
            *out++ = c;
        }
    }
    *out = '\0';
    return 0;
}

Ответ 3

Вечно превосходный glib имеет некоторые функции URI, включая извлечение схемы, экранирование и неэкспонирование.

Ответ 4

uriparser библиотека небольшая и легкая.

Ответ 5

Эта функция, которую я только что взбила, очень легкая и должна делать то, что вы пожелаете, заметьте, я не запрограммировал это на строгие стандарты 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;
        }
    }
}

Ответ 6

Попробуйте urlcpp https://github.com/larroy/urlcpp Это модуль С++, который вы можете легко интегрировать в свой проект, зависит от boost:: regex

Ответ 7

Я предлагаю curl и libcurl. Он широко используется и должен делать трюк для вас. Просто проверьте их сайт.

Ответ 8

/**
 * 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

Ответ 9

Спасибо @ThomasH за его ответ. Я бы хотел предложить здесь лучшую формулу...

И... поскольку декодированный компонент URI всегда менее длинный, чем тот же кодированный компонент URI, всегда можно вставить его в один массив символов (a.k.a.: "string" ). Итак, я предлагаю здесь две возможности:

#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 print: "http://foo+bar/abcd\nLength: 19" */
    printf("%s\nLength: %d\n", sMyUrl, nNewLength);

    return 0;

}

Ste *

Ответ 10

Пошел на этот 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;
}