diff options
Diffstat (limited to 'Utilities/cmlibrhash/librhash/hex.c')
-rw-r--r-- | Utilities/cmlibrhash/librhash/hex.c | 170 |
1 files changed, 96 insertions, 74 deletions
diff --git a/Utilities/cmlibrhash/librhash/hex.c b/Utilities/cmlibrhash/librhash/hex.c index c941149..f0bbf04 100644 --- a/Utilities/cmlibrhash/librhash/hex.c +++ b/Utilities/cmlibrhash/librhash/hex.c @@ -1,71 +1,57 @@ /* hex.c - conversion for hexadecimal and base32 strings. * - * Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com> + * Copyright (c) 2008, Aleksey Kravchenko <rhash.admin@gmail.com> * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ -#include <string.h> -#include <ctype.h> #include "hex.h" - -/** -* Convert a byte to a hexadecimal number. The result, consisting of two -* hexadecimal digits is stored into a buffer. - * - * @param dest the buffer to receive two symbols of hex representation - * @param byte the byte to decode - * @param upper_case flag to print string in uppercase - * @return pointer to the chararcter just after the written number (dest + 2) - */ -char* rhash_print_hex_byte(char *dest, const unsigned char byte, int upper_case) -{ - const char add = (upper_case ? 'A' - 10 : 'a' - 10); - unsigned char c = (byte >> 4) & 15; - *dest++ = (c > 9 ? c + add : c + '0'); - c = byte & 15; - *dest++ = (c > 9 ? c + add : c + '0'); - return dest; -} +#include <assert.h> +#include <ctype.h> +#include <string.h> /** * Store hexadecimal representation of a binary string to given buffer. * - * @param dest the buffer to receive hexadecimal representation + * @param dst the buffer to receive hexadecimal representation * @param src binary string - * @param len string length + * @param length string length * @param upper_case flag to print string in uppercase */ -void rhash_byte_to_hex(char *dest, const unsigned char *src, unsigned len, int upper_case) +void rhash_byte_to_hex(char* dst, const unsigned char* src, size_t length, int upper_case) { - while (len-- > 0) { - dest = rhash_print_hex_byte(dest, *src++, upper_case); + const char hex_add = (upper_case ? 'A' - 10 : 'a' - 10); + for (; length > 0; src++, length--) { + const unsigned char hi = (*src >> 4) & 15; + const unsigned char lo = *src & 15; + *dst++ = (hi > 9 ? hi + hex_add : hi + '0'); + *dst++ = (lo > 9 ? lo + hex_add : lo + '0'); } - *dest = '\0'; + *dst = '\0'; } /** * Encode a binary string to base32. * - * @param dest the buffer to store result + * @param dst the buffer to store result * @param src binary string - * @param len string length + * @param length string length * @param upper_case flag to print string in uppercase */ -void rhash_byte_to_base32(char* dest, const unsigned char* src, unsigned len, int upper_case) +void rhash_byte_to_base32(char* dst, const unsigned char* src, size_t length, int upper_case) { const char a = (upper_case ? 'A' : 'a'); unsigned shift = 0; unsigned char word; - const unsigned char* e = src + len; + const unsigned char* e = src + length; while (src < e) { if (shift > 3) { word = (*src & (0xFF >> shift)); @@ -79,25 +65,25 @@ void rhash_byte_to_base32(char* dest, const unsigned char* src, unsigned len, in word = ( *src >> ( (8 - shift) & 7 ) ) & 0x1F; if (shift == 0) src++; } - *dest++ = ( word < 26 ? word + a : word + '2' - 26 ); + *dst++ = ( word < 26 ? word + a : word + '2' - 26 ); } - *dest = '\0'; + *dst = '\0'; } /** * Encode a binary string to base64. * Encoded output length is always a multiple of 4 bytes. * - * @param dest the buffer to store result + * @param dst the buffer to store result * @param src binary string - * @param len string length + * @param length string length */ -void rhash_byte_to_base64(char* dest, const unsigned char* src, unsigned len) +void rhash_byte_to_base64(char* dst, const unsigned char* src, size_t length) { static const char* tail = "0123456789+/"; unsigned shift = 0; unsigned char word; - const unsigned char* e = src + len; + const unsigned char* e = src + length; while (src < e) { if (shift > 2) { word = (*src & (0xFF >> shift)); @@ -111,45 +97,80 @@ void rhash_byte_to_base64(char* dest, const unsigned char* src, unsigned len) word = ( *src >> ( (8 - shift) & 7 ) ) & 0x3F; if (shift == 0) src++; } - *dest++ = ( word < 52 ? (word < 26 ? word + 'A' : word - 26 + 'a') : tail[word - 52]); + *dst++ = ( word < 52 ? (word < 26 ? word + 'A' : word - 26 + 'a') : tail[word - 52]); } if (shift > 0) { - *dest++ = '='; - if (shift == 4) *dest++ = '='; + *dst++ = '='; + if (shift == 4) *dst++ = '='; } - *dest = '\0'; + *dst = '\0'; } -/* unsafe characters are "<>{}[]%#/|\^~`@:;?=&+ */ -#define IS_GOOD_URL_CHAR(c) (isalnum((unsigned char)c) || strchr("$-_.!'(),", c)) +size_t rhash_base64_url_encoded_helper(char* dst, const unsigned char* src, size_t length, int url_encode, int upper_case) +{ +#define B64_CHUNK_SIZE 120 + char buffer[164]; + assert((BASE64_LENGTH(B64_CHUNK_SIZE) + 4) <= sizeof(buffer)); + assert((B64_CHUNK_SIZE % 6) == 0); + if (url_encode) { + size_t result_length = 0; + for (; length > 0; src += B64_CHUNK_SIZE) { + size_t chunk_size = (length < B64_CHUNK_SIZE ? length : B64_CHUNK_SIZE); + size_t encoded_length; + rhash_byte_to_base64(buffer, src, chunk_size); + encoded_length = rhash_urlencode(dst, buffer, BASE64_LENGTH(chunk_size), upper_case); + result_length += encoded_length; + dst += encoded_length; + length -= chunk_size; + } + return result_length; + } + rhash_byte_to_base64(dst, src, length); + return BASE64_LENGTH(length); +} + +/* RFC 3986: safe url characters are ascii alpha-numeric and "-._~", other characters should be percent-encoded */ +static unsigned url_safe_char_mask[4] = { 0, 0x03ff6000, 0x87fffffe, 0x47fffffe }; +#define IS_URL_GOOD_CHAR(c) ((unsigned)(c) < 128 && (url_safe_char_mask[c >> 5] & (1 << (c & 31)))) /** - * URL-encode a string. + * URL-encode specified binary string. * - * @param dst buffer to receive result or NULL to calculate - * the lengths of encoded string - * @param filename the file name + * @param dst (nullable) buffer to output encoded string to, + * NULL to just calculate the lengths of encoded string + * @param src binary string to encode + * @param size size of the binary string + * @param upper_case flag to output hex-codes in uppercase * @return the length of the result string */ -int rhash_urlencode(char *dst, const char *name) +size_t rhash_urlencode(char* dst, const char* src, size_t size, int upper_case) { - const char *start; + const char* start; + size_t i; if (!dst) { - int len; - for (len = 0; *name; name++) len += (IS_GOOD_URL_CHAR(*name) ? 1 : 3); - return len; - } - /* encode URL as specified by RFC 1738 */ - for (start = dst; *name; name++) { - if ( IS_GOOD_URL_CHAR(*name) ) { - *dst++ = *name; - } else { - *dst++ = '%'; - dst = rhash_print_hex_byte(dst, *name, 'A'); + size_t length = size; + for (i = 0; i < size; i++) + if (!IS_URL_GOOD_CHAR(src[i])) + length += 2; + return length; + } else { + const char hex_add = (upper_case ? 'A' - 10 : 'a' - 10); + start = dst; + /* percent-encode all but unreserved URL characters */ + for (i = 0; i < size; i++) { + if (IS_URL_GOOD_CHAR(src[i])) { + *dst++ = src[i]; + } else { + unsigned char hi = ((unsigned char)(src[i]) >> 4) & 0x0f; + unsigned char lo = (unsigned char)(src[i]) & 0x0f; + *dst++ = '%'; + *dst++ = (hi > 9 ? hi + hex_add : hi + '0'); + *dst++ = (lo > 9 ? lo + hex_add : lo + '0'); + } } + *dst = 0; } - *dst = 0; - return (int)(dst - start); + return dst - start; } /** @@ -160,10 +181,11 @@ int rhash_urlencode(char *dst, const char *name) * @param number the number to print * @return length of the printed number (without trailing '\0') */ -int rhash_sprintI64(char *dst, uint64_t number) +int rhash_sprintI64(char* dst, uint64_t number) { /* The biggest number has 20 digits: 2^64 = 18 446 744 073 709 551 616 */ - char buf[24], *p; + char buf[24]; + char* p; size_t length; if (dst == NULL) { |