2010-04-20 12 views
9

Sto sviluppando un programma c/C++ su linux. Puoi dirmi se esiste una libreria c/C++ che decodifica l'url?Libreria di decodifica URL C/C++

Cerco librerie che convertono "http% 3A% 2F% 2F" a: "http: //"

o "a + t +% 26 + t" a "a & t "

Grazie.

+0

@sbi: Non mi sembra un vero capriccio. – greyfade

+0

@greyfade: Oops, ho ricevuto la domanda sbagliata. Dispiace per la confusione. Ce n'era uno simile, però, solo pochi giorni fa. – sbi

+0

Direi che c'è un dupe: http://stackoverflow.com/questions/2616011/ – sbi

risposta

4

Il sempre eccellente glib ha un numero di URI functions, inclusi estrazione di schemi, escaping e non-escape.

+1

A meno che l'OP non utilizzi glib per cominciare (presumo che non lo sia se sta usando C++), glib è eccessivo se l'unico scopo è usare il suo URI funzioni. Non è una piccola biblioteca. – Void

1

uriparser la libreria è piccola e leggera.

2

Questa funzione che ho appena montato è molto leggera e dovrebbe fare ciò che desideri, nota che non ho programmato questo a rigorosi standard URI (usato quello che so in cima alla mia testa). È sicuro per i buffer e non trabocca per quanto posso vedere; adattarsi nel modo che ritiene in forma:

#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

Penso che la funzione di Saul abbia bisogno anche del caso "STATE_SEARCH". Altrimenti potresti avere un lungo url/uri senza codici esadecimali, e non attiverà l'asserzione perché 'state' non sarà mai' STATE_CONVERTING'. –

+0

Risolto, grazie David. – Saul

+0

@ Saul soffre di NIH? – Yevgeniy

18

Ho utilizzato la funzione di Saul in un programma di analisi che stavo scrivendo (analizzando milioni di URL stringhe codificate), e mentre si lavora, a quella scala che stava rallentando il mio programma giù orribilmente, così ho deciso di scrivere una versione più veloce. Questo è migliaia di volte più veloce quando compilato con GCC e l'opzione -O2. Può anche usare lo stesso buffer di output dell'input (ad esempio urldecode2 (buf, buf) funzionerà se la stringa originale era in buf e deve essere sovrascritta dalla sua controparte decodificata).

Edit: Non prende la dimensione di buffer in ingresso perché si presume che il buffer sarà abbastanza grande, questo è sicuro perché è noto che la lunghezza dell'uscita sarà sempre < = che dell'ingresso, quindi utilizzare lo stesso tampone per l'uscita o creare uno che è almeno la dimensione dell'input + 1 per il terminatore nullo, ad esempio:

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

Edit 2: un utente anonimo ha tentato di modifica questa risposta per gestire la traduzione del carattere '+' in '', che penso che probabilmente dovrebbe fare, ancora una volta questo non era qualcosa che Avevo bisogno della mia applicazione, ma l'ho aggiunta di seguito.

Ecco 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 sottrazione dovrebbe essere il contrario. In questo momento sta producendo valori negativi e funziona solo quando si usano lettere HEX maiuscole. – anavarroma

+1

Grazie per questo. Sono stato in grado di usarlo oggi. Come ha commentato Adrià, i calcoli "a - = 'A' - 'a'" e b - = 'A' - 'a' "erano sbagliati e davano risultati negativi per cifre esadecimali minuscole. Mi sono permesso di correggere questo con il mio Ora l'esempio elabora correttamente l'esagono in maiuscolo e minuscolo –

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

È impeccabile? – hB0

1

io suggerirei curl and libcurl . È ampiamente usato e dovrebbe fare il trucco per te. Basta controllare il loro sito web.

0

Grazie a @ThomasH per la sua risposta. Vorrei proporre qui un formattation meglio ...

E ... poiché il componente URI decodificato è sempre meno lungo lo stesso componente codificata URI, è sempre possibile implodere all'interno del stesso array di caratteri (alias: "stringa").Quindi, io propongo qui due possibilità:

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

E, alla fine ...:

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

Ecco un decoder C per una stringa codificata per cento. Restituisce -1 se la codifica non è valida e 0 altrimenti. La stringa decodificata è memorizzata in out. Sono abbastanza sicuro che questo è il codice più veloce delle risposte fornite finora.

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

Mi piace - il! (v1 = * in ++) e! (v2 = * in ++) sono ridondanti anche se tbl [0] restituisce - 1 invece si può fare: 'if ((v1 = tbl [(unsigned char) * in ++]) <0 || (v2 = tbl [(unsigned char) * in ++]) <0) {... ' – GaspardP