2010-04-20 19 views
9

Ich entwickle ein c/C++ Programm unter Linux. Können Sie mir bitte sagen, ob es eine C/C++ Bibliothek gibt, die URL dekodiert?C/C++ URL-Dekodierbibliothek

Ich suche nach Bibliotheken, die "http% 3A% 2F% 2F" zu konvertieren: "http: //"

oder "a + t +% 26 + t" bis „an & t "

Vielen Dank.

+0

@sbi: Sieht für mich nicht wie ein Betrogener aus. – greyfade

+0

@greyfade: Ups, ich habe die falsche Frage. Entschuldigung für die Verwirrung. Vor ein paar Tagen gab es ein ähnliches. – sbi

+0

Ich würde sagen, es gibt einen Betrogenen: http://StackOverflow.com/Questions/2616011/ – sbi

Antwort

4

Die immer hervorragende glib hat einige URI functions, einschließlich Schema-Extraktion, Entweichen und Entfliehen.

+1

Wenn das OP nicht glib verwendet (ich nehme an, er ist nicht, wenn er C++ verwendet), ist glib übertrieben, wenn der einzige Zweck darin besteht, seinen URI zu verwenden Funktionen. Es ist keine kleine Bibliothek. – Void

2

Diese Funktion, die ich gerade aufgepeitscht habe, ist sehr leicht und sollte tun, was Sie wollen, beachten Sie, dass ich dies nicht auf strenge URI-Standards (verwendet, was ich weiß von oben) programmiert habe. Es ist puffersicher und überfließt nicht, soweit ich sehen kann; anpassen, wie Sie deem passen:

#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

Ich denke, Sauls Funktion benötigt die Assert auch im 'STATE_SEARCH' Fall. Sonst könnten Sie eine lange URL/URI ohne Hex-Codes haben, und es wird nicht die Assertion auslösen, weil 'state' nie' STATE_CONVERTING' sein wird. –

+0

Behoben, danke David. – Saul

+0

@Saul von NIH? – Yevgeniy

18

ich Sauls Funktion in einem Analyseprogramm tatsächlich verwende ich schreibe (in Millionen URL kodierten Strings Analyse), und während es funktioniert, in dieser Größenordnung war es mein Programm verlangsamt schrecklich, Also habe ich beschlossen, eine schnellere Version zu schreiben. Dieser ist tausende Male schneller, wenn er mit GCC und der Option -O2 kompiliert wird. Es kann auch den gleichen Ausgabepuffer als Eingabe verwenden (z. B. urldecode2 (buf, buf) funktioniert, wenn die ursprüngliche Zeichenkette in buf war und von ihrem dekodierten Gegenstück überschrieben werden soll).

Edit: Es ist nicht die Puffergröße als Eingabe nehmen, weil angenommen wird, dass der Puffer groß genug sein wird, das ist sicher, weil es, dass die Länge des Ausgangs immer < = sein wird, bekannt ist, dass der Eingangs, so entweder den gleichen Puffer für die Ausgabe verwendet werden oder eine erstellen, die die Größe der Eingabe + 1 für den null-Terminator, zB mindestens ist:

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

Edit 2: ein anonymer Benutzer versucht, bearbeite diese Antwort, um die Übersetzung des '+' - Charakters in '' zu übernehmen, was meiner Meinung nach wahrscheinlich auch sein sollte Ich brauchte für meine Bewerbung, aber ich habe es unten hinzugefügt.

Hier ist die 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

Die Subtraktion sollte umgekehrt sein. Im Moment produziert es negative Werte und funktioniert nur, wenn Großbuchstaben verwendet werden. – anavarroma

+1

Danke dafür. Ich konnte es heute nutzen. Wie Adrià bemerkte, waren die "a - = 'A' - 'a'" und b - = 'A' - 'a' "calcs falsch und ergaben schlechte Ergebnisse für kleine Hexadezimalziffern. Ich habe mir die Freiheit genommen, dies mit meinem zu korrigieren Bearbeiten von Privilegien Nun verarbeitet das Beispiel Groß- und Kleinbuchstaben korrekt –

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

Ist das fehlerlos? – hB0

1

ich curl and libcurl würde vorschlagen . Es ist weit verbreitet und sollte den Trick für Sie tun. Überprüfen Sie einfach ihre Website.

0

Danke an @ThomasH für seine Antwort. Ich mag würde hier eine bessere formattation vorzuschlagen ...

Und ... da die dekodiert URI-Komponente immer weniger lang als die gleiche kodierte URI-Komponente ist, ist immer möglich, es im gleichen Array von Zeichen zu implodieren (aka: "string").So werde ich vorschlagen hier zwei Möglichkeiten:

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

Und schließlich ...:

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

Hier ist ein C-Decoder für ein Prozent codierte Zeichenfolge. Es gibt -1 zurück, wenn die Codierung ungültig ist und andernfalls 0. Die decodierte Zeichenfolge wird in out gespeichert. Ich bin mir ziemlich sicher, dass dies der schnellste Code der bisher gegebenen Antworten ist.

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

Ich mag es - die! (v1 = * in ++) und! (v2 = * in ++) sind redundant, da tbl [0] zurückgibt - Ich kann das trotzdem: 'if ((v1 = tbl [(vorzeichenloses Zeichen) * in ++]) <0 || (v2 = tbl [(vorzeichenloses Zeichen) * in ++]) <0) {... ' – GaspardP