2010-04-20 4 views
9

Je développe un programme c/C++ sous Linux. Pouvez-vous s'il vous plaît me dire s'il y a une bibliothèque c/C++ qui décode l'URL?Bibliothèque de décodage d'URL C/C++

Je cherche des bibliothèques qui convertissent "http% 3A% 2F% 2F" à: "http: //"

ou "a + t +% 26 + t" à « au & t "

Merci.

+0

@sbi: Cela ne me ressemble pas du tout. – greyfade

+0

@greyfade: Oups, j'ai une mauvaise question. Désolé pour la confusion. Il y en avait un semblable, cependant, il y a quelques jours. – sbi

+0

Je dirais qu'il y a un dupe: http://stackoverflow.com/questions/2616011/ – sbi

Répondre

4

Le toujours excellent glib a quelques URI functions, y compris l'extraction de schéma, l'échappement et l'échappement.

+1

A moins que l'OP n'utilise initialement glib (je suppose qu'il ne l'utilise pas en C++), glib est trop puissant si le seul but est d'utiliser son URI les fonctions. Ce n'est pas une petite bibliothèque. – Void

1

uriparser La bibliothèque est petite et légère.

2

Cette fonction que je viens de fouetter est très légère et devrait faire ce que vous voulez, notez que je n'ai pas programmé cela aux normes strictes d'URI (j'ai utilisé ce que je sais sur le dessus de ma tête). Il est sécuritaire et ne déborde pas autant que je peux le voir; adapter comme vous jugerez utiles:

#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; 
     } 
    } 
} 
+1

Je pense que la fonction de Saul a également besoin de l'assert dans le cas 'STATE_SEARCH'. Sinon, vous pourriez avoir une longue url/uri sans codes hexadécimaux, et cela ne déclenchera pas l'assertion car 'state' ne sera jamais' STATE_CONVERTING'. –

+0

Correction, merci David. – Saul

+0

@Saul souffre de NIH? – Yevgeniy

18

J'ai effectivement utilisé la fonction de Saul dans un programme d'analyse que j'écrivais (analyse des millions d'URL des chaînes codées), et tout cela fonctionne, à cette échelle, il ralentissait tant mon programme horriblement, J'ai donc décidé d'écrire une version plus rapide. Celui-ci est des milliers de fois plus rapide lorsqu'il est compilé avec GCC et l'option -O2. Il peut également utiliser le même tampon de sortie que l'entrée (par exemple, urldecode2 (buf, buf) fonctionnera si la chaîne d'origine était dans buf et doit être écrasée par sa contrepartie décodée).

Edit: Il ne prend pas la taille de la mémoire tampon en entrée car il est supposé que le tampon sera assez grand, cela est sans danger, car on sait que la longueur de la sortie sera toujours < = que de l'entrée, de sorte que soit utiliser le même tampon pour la sortie ou créer un qui est au moins la taille de l'entrée + 1 pour la terminaison nulle, par exemple:

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

Edit 2: un utilisateur anonyme a tenté de éditez cette réponse pour gérer la traduction du caractère '+' en '', ce que je pense qu'il devrait probablement faire, encore une fois ce n'était pas quelque chose qui J'avais besoin de mon application, mais je l'ai ajouté ci-dessous.

est ici la routine:

#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'; 
} 
+0

La soustraction devrait être l'inverse. À l'heure actuelle, il produit des valeurs négatives et ne fonctionne que lorsque vous utilisez des majuscules HEX. – anavarroma

+1

Merci pour votre contribution. Je pouvais le mettre en usage aujourd'hui. Comme l'a commenté Adrià, les calculs "a - = 'A' - 'a'" et b - = 'A' - 'a' "étaient faux et donnaient de mauvais résultats pour les chiffres hexadécimaux en minuscules. Maintenant, l'exemple traite les hexs en majuscules et en minuscules correctement –

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 
+0

Est-ce que c'est parfait? – hB0

1

Je suggère curl and libcurl . Il est largement utilisé et devrait faire l'affaire pour vous. Vérifiez simplement leur site Web.

0

Merci à @ThomasH pour sa réponse. Je voudrais proposer ici une meilleure formattation ...

Et ... puisque le composant URI est décodé toujours moins long que le même composant URI encodée, est toujours possible de imploser dans le même tableau de caractères (aka: "chaîne").Alors, je propose ici deux possibilités:

#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) 

Et, enfin ...:

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; 

} 

Ste *

4

est ici un décodeur C pour une chaîne codée pour cent. Il renvoie -1 si l'encodage est invalide et 0 sinon. La chaîne décodée est stockée dans out. Je suis tout à fait sûr que c'est le code le plus rapide des réponses données jusqu'ici.

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; 
} 
+1

Je l'aime - le! (v1 = * en ++) et! (v2 = * en ++) sont redondants mais puisque tbl [0] reviendra - Au lieu de cela, vous pouvez faire: 'if ((v1 = tbl [(unsigned char) * dans ++]) <0 || (v2 = tbl [(unsigned char) * dans ++]) <0) {... ' – GaspardP