diff --git a/src/futils.cpp b/src/futils.cpp index 82596d4b..67c910ac 100644 --- a/src/futils.cpp +++ b/src/futils.cpp @@ -139,117 +139,124 @@ namespace Exiv2 { delete [] decodeStr; } - // https://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c - static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - - static inline bool is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); - } - - static std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; - } - return ret; - } - - static std::string base64_decode(std::string const& encoded_string) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::string ret; - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - ret += char_array_3[i]; - i = 0; - } - } - - if (i) { - for (j = i; j <4; j++) - char_array_4[j] = 0; - - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; - } - - return ret; - } - int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize) { - int rc = 0 ; // failed - std::string encoded = base64_encode((unsigned char const*)data_buf, (unsigned int) dataLength) ; - if (encoded.size() < resultSize ) { - memcpy(result,encoded.c_str(),encoded.size()); - rc = 1 ; // indicate success + const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const uint8_t* data = (const uint8_t*)data_buf; + size_t resultIndex = 0; + size_t x; + uint32_t n = 0; + size_t padCount = dataLength % 3; + uint8_t n0, n1, n2, n3; + + /* increment over the length of the string, three characters at a time */ + for (x = 0; x < dataLength; x += 3) + { + /* these three 8-bit (ASCII) characters become one 24-bit number */ + n = data[x] << 16; + + if((x+1) < dataLength) + n += data[x+1] << 8; + + if((x+2) < dataLength) + n += data[x+2]; + + /* this 24-bit number gets separated into four 6-bit numbers */ + n0 = (uint8_t)(n >> 18) & 63; + n1 = (uint8_t)(n >> 12) & 63; + n2 = (uint8_t)(n >> 6) & 63; + n3 = (uint8_t)n & 63; + + /* + * if we have one byte available, then its encoding is spread + * out over two characters + */ + if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ + result[resultIndex++] = base64chars[n0]; + if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ + result[resultIndex++] = base64chars[n1]; + + /* + * if we have only two bytes available, then their encoding is + * spread out over three chars + */ + if((x+1) < dataLength) + { + if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ + result[resultIndex++] = base64chars[n2]; + } + + /* + * if we have all three bytes available, then their encoding is spread + * out over four characters + */ + if((x+2) < dataLength) + { + if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ + result[resultIndex++] = base64chars[n3]; + } } - return rc; + + /* + * create and add padding that is required if we did not have a multiple of 3 + * number of characters available + */ + if (padCount > 0) + { + for (; padCount < 3; padCount++) + { + if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ + result[resultIndex++] = '='; + } + } + if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ + result[resultIndex] = 0; + return 1; /* indicate success */ } // base64encode - long base64decode(const char *in, char *out, size_t out_size) - { - std::string in_string(in); - std::string out_string = base64_decode(in_string); - long result = (long) out_string.size(); - if ( (long) out_size > result ) { - memcpy(out,out_string.c_str(),result); - out[result] = 0; - } else result = -1 ; - return result; - } + long base64decode(const char *in, char *out, size_t out_size) { + static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW" + "$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + long len; + long i; + long done = 0; + unsigned char v; + unsigned char quad[4]; + + while (*in) { + len = 0; + for (i = 0; i < 4 && *in; i++) { + v = 0; + while (*in && !v) { + v = *in++; + v = (v < 43 || v > 122) ? 0 : decode[v - 43]; + if (v) + v = (v == '$') ? 0 : v - 61; + if (*in) { + len++; + if (v) + quad[i] = v - 1; + } else + quad[i] = 0; + } + } + if (!len) + continue; + if (out_size < (size_t) (done + len - 1)) + /* out buffer is too small */ + return -1; + if (len >= 2) + *out++ = quad[0] << 2 | quad[1] >> 4; + if (len >= 3) + *out++ = quad[1] << 4 | quad[2] >> 2; + if (len >= 4) + *out++ = ((quad[2] << 6) & 0xc0) | quad[3]; + done += len - 1; + } + if ((size_t)(done + 1) >= out_size) + return -1; + *out++ = '\0'; + return done; + } // base64decode Protocol fileProtocol(const std::string& path) { Protocol result = pFile ;