escape: use hex-pair lookup in curl_easy_escape
No binary (build failed)
—
(log yok)
| @@ -83,6 +83,73 @@ static const unsigned char hextable[256] = { | |
| NOPE, NOPE, NOPE, NOPE, NOPE, NOPE, NOPE, NOPE | |
| }; | |
| + | static const char hexpairs[][2] = { |
| + | {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, |
| + | {'0', '4'}, {'0', '5'}, {'0', '6'}, {'0', '7'}, |
| + | {'0', '8'}, {'0', '9'}, {'0', 'A'}, {'0', 'B'}, |
| + | {'0', 'C'}, {'0', 'D'}, {'0', 'E'}, {'0', 'F'}, |
| + | {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, |
| + | {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, |
| + | {'1', '8'}, {'1', '9'}, {'1', 'A'}, {'1', 'B'}, |
| + | {'1', 'C'}, {'1', 'D'}, {'1', 'E'}, {'1', 'F'}, |
| + | {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, |
| + | {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, |
| + | {'2', '8'}, {'2', '9'}, {'2', 'A'}, {'2', 'B'}, |
| + | {'2', 'C'}, {'2', 'D'}, {'2', 'E'}, {'2', 'F'}, |
| + | {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, |
| + | {'3', '4'}, {'3', '5'}, {'3', '6'}, {'3', '7'}, |
| + | {'3', '8'}, {'3', '9'}, {'3', 'A'}, {'3', 'B'}, |
| + | {'3', 'C'}, {'3', 'D'}, {'3', 'E'}, {'3', 'F'}, |
| + | {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, |
| + | {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, |
| + | {'4', '8'}, {'4', '9'}, {'4', 'A'}, {'4', 'B'}, |
| + | {'4', 'C'}, {'4', 'D'}, {'4', 'E'}, {'4', 'F'}, |
| + | {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, |
| + | {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, |
| + | {'5', '8'}, {'5', '9'}, {'5', 'A'}, {'5', 'B'}, |
| + | {'5', 'C'}, {'5', 'D'}, {'5', 'E'}, {'5', 'F'}, |
| + | {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, |
| + | {'6', '4'}, {'6', '5'}, {'6', '6'}, {'6', '7'}, |
| + | {'6', '8'}, {'6', '9'}, {'6', 'A'}, {'6', 'B'}, |
| + | {'6', 'C'}, {'6', 'D'}, {'6', 'E'}, {'6', 'F'}, |
| + | {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, |
| + | {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, |
| + | {'7', '8'}, {'7', '9'}, {'7', 'A'}, {'7', 'B'}, |
| + | {'7', 'C'}, {'7', 'D'}, {'7', 'E'}, {'7', 'F'}, |
| + | {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, |
| + | {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, |
| + | {'8', '8'}, {'8', '9'}, {'8', 'A'}, {'8', 'B'}, |
| + | {'8', 'C'}, {'8', 'D'}, {'8', 'E'}, {'8', 'F'}, |
| + | {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, |
| + | {'9', '4'}, {'9', '5'}, {'9', '6'}, {'9', '7'}, |
| + | {'9', '8'}, {'9', '9'}, {'9', 'A'}, {'9', 'B'}, |
| + | {'9', 'C'}, {'9', 'D'}, {'9', 'E'}, {'9', 'F'}, |
| + | {'A', '0'}, {'A', '1'}, {'A', '2'}, {'A', '3'}, |
| + | {'A', '4'}, {'A', '5'}, {'A', '6'}, {'A', '7'}, |
| + | {'A', '8'}, {'A', '9'}, {'A', 'A'}, {'A', 'B'}, |
| + | {'A', 'C'}, {'A', 'D'}, {'A', 'E'}, {'A', 'F'}, |
| + | {'B', '0'}, {'B', '1'}, {'B', '2'}, {'B', '3'}, |
| + | {'B', '4'}, {'B', '5'}, {'B', '6'}, {'B', '7'}, |
| + | {'B', '8'}, {'B', '9'}, {'B', 'A'}, {'B', 'B'}, |
| + | {'B', 'C'}, {'B', 'D'}, {'B', 'E'}, {'B', 'F'}, |
| + | {'C', '0'}, {'C', '1'}, {'C', '2'}, {'C', '3'}, |
| + | {'C', '4'}, {'C', '5'}, {'C', '6'}, {'C', '7'}, |
| + | {'C', '8'}, {'C', '9'}, {'C', 'A'}, {'C', 'B'}, |
| + | {'C', 'C'}, {'C', 'D'}, {'C', 'E'}, {'C', 'F'}, |
| + | {'D', '0'}, {'D', '1'}, {'D', '2'}, {'D', '3'}, |
| + | {'D', '4'}, {'D', '5'}, {'D', '6'}, {'D', '7'}, |
| + | {'D', '8'}, {'D', '9'}, {'D', 'A'}, {'D', 'B'}, |
| + | {'D', 'C'}, {'D', 'D'}, {'D', 'E'}, {'D', 'F'}, |
| + | {'E', '0'}, {'E', '1'}, {'E', '2'}, {'E', '3'}, |
| + | {'E', '4'}, {'E', '5'}, {'E', '6'}, {'E', '7'}, |
| + | {'E', '8'}, {'E', '9'}, {'E', 'A'}, {'E', 'B'}, |
| + | {'E', 'C'}, {'E', 'D'}, {'E', 'E'}, {'E', 'F'}, |
| + | {'F', '0'}, {'F', '1'}, {'F', '2'}, {'F', '3'}, |
| + | {'F', '4'}, {'F', '5'}, {'F', '6'}, {'F', '7'}, |
| + | {'F', '8'}, {'F', '9'}, {'F', 'A'}, {'F', 'B'}, |
| + | {'F', 'C'}, {'F', 'D'}, {'F', 'E'}, {'F', 'F'} |
| + | }; |
| + | |
| /* Escapes for URL the given unescaped string of given length. | |
| * 'data' is ignored since 7.82.0. | |
| */ | |
| @@ -124,8 +191,7 @@ char *curl_easy_escape(CURL *curl, const char *string, int length) | |
| f = string; | |
| /* encode it */ | |
| target[0] = '%'; | |
| - | target[1] = Curl_udigits[in >> 4]; |
| - | target[2] = Curl_udigits[in & 0x0F]; |
| + | memcpy(target + 1, hexpairs[in], 2); |
| target += 3; | |
| } | |
| } | |
| @@ -117,5 +117,43 @@ static CURLcode test_lib1396(const char *arg) | |
| curl_free(out); | |
| } | |
| + | { |
| + | unsigned char binary[256]; |
| + | char expected[sizeof(binary) * 3 + 1]; |
| + | const char digits[] = "0123456789ABCDEF"; |
| + | size_t encoded_length = 0; |
| + | unsigned int byte; |
| + | char *encoded; |
| + | char *decoded; |
| + | int decoded_length; |
| + | |
| + | for(byte = 0; byte < sizeof(binary); byte++) { |
| + | binary[byte] = (unsigned char)byte; |
| + | if((byte >= 'a' && byte <= 'z') || (byte >= 'A' && byte <= 'Z') || |
| + | (byte >= '0' && byte <= '9') || byte == '-' || byte == '.' || |
| + | byte == '_' || byte == '~') |
| + | expected[encoded_length++] = (char)byte; |
| + | else { |
| + | expected[encoded_length++] = '%'; |
| + | expected[encoded_length++] = digits[byte >> 4]; |
| + | expected[encoded_length++] = digits[byte & 15]; |
| + | } |
| + | } |
| + | expected[encoded_length] = 0; |
| + | encoded = curl_easy_escape(easy, (const char *)binary, sizeof(binary)); |
| + | abort_unless(encoded, "binary escape failed"); |
| + | fail_unless(!strcmp(encoded, expected), "wrong binary escape output"); |
| + | decoded = curl_easy_unescape(easy, encoded, 0, &decoded_length); |
| + | curl_free(encoded); |
| + | abort_unless(decoded, "binary unescape failed"); |
| + | fail_unless(decoded_length == sizeof(binary), "wrong binary output size"); |
| + | if(decoded_length == sizeof(binary)) { |
| + | fail_unless(!memcmp(decoded, binary, sizeof(binary)), |
| + | "wrong binary data"); |
| + | fail_unless(!decoded[decoded_length], "binary output not terminated"); |
| + | } |
| + | curl_free(decoded); |
| + | } |
| + | |
| UNITTEST_END(t1396_stop(easy)) | |
| } | |