//////////////////////////////////////////////////////////////////////////////// /// @brief collection of string utility functions /// /// @file /// /// DISCLAIMER /// /// Copyright 2014 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany /// @author Copyright 2005-2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "StringUtils.h" #include #include #include #include "Basics/logging.h" #include "Basics/tri-strings.h" #include "Basics/Exceptions.h" #include "Basics/StringBuffer.h" // TODO need to this in another way #ifndef TRI_HAVE_GLOBAL_TIMEZONE_PROTO #ifdef GLOBAL_TIMEZONE extern long GLOBAL_TIMEZONE; #else static long GLOBAL_TIMEZONE = 0; #endif #endif using namespace std; // ----------------------------------------------------------------------------- // helper functions // ----------------------------------------------------------------------------- namespace { bool isSpace (char a) { return a == ' ' || a == '\t' || a == '_'; } int32_t matchInteger (char const * & str, size_t size) { int32_t result = 0; for (size_t i = 0; i < size; i++, str++) { if ('0' <= *str && *str <= '9') { result = result * 10 + (*str - '0'); } else { std::string message("cannot parse date, expecting integer, got '" + string(1, *str) + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } return result; } int32_t matchInteger (char const * & str) { int32_t result = 0; for (; *str; str++) { if ('0' <= *str && *str <= '9') { result = result * 10 + (*str - '0'); } else { return result; } } return result; } char const * const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; char const * const BASE64U_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-_"; unsigned char const BASE64_REVS[256] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 16 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 62, '\0', '\0', '\0', 63, // 32 ' ', '!' 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, '\0', '\0', '\0', '\0', '\0', '\0', // 48 '0', '1' '\0', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64 '@', 'A' 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, '\0', '\0', '\0', '\0', '\0', // 80 '\0', 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96 '`', 'a' 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, '\0', '\0', '\0', '\0', '\0', // 112 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 128 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 144 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 160 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 176 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 192 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 208 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 224 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 240 }; unsigned char const BASE64U_REVS[256] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 16 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 62, '\0', '\0', // 32 ' ', '!' 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, '\0', '\0', '\0', '\0', '\0', '\0', // 48 '0', '1' '\0', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64 '@', 'A' 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, '\0', '\0', '\0', '\0', 63, // 80 '\0', 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96 '`', 'a' 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, '\0', '\0', '\0', '\0', '\0', // 112 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 128 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 144 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 160 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 176 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 192 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 208 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 224 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 240 }; inline bool isBase64 (unsigned char c) { return (isalnum(c) || (c == '+') || (c == '/')); } inline bool isBase64U (unsigned char c) { return (isalnum(c) || (c == '-') || (c == '_')); } bool parseHexanumber (char const *inputStr, size_t len, uint32_t * outputInt) { const uint32_t charVal[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; bool ok = true; for (size_t j = 0; j < len; j++) { if (inputStr[j] > '/' && inputStr[j] < ':') { *outputInt = (*outputInt << 4) | charVal[inputStr[j] - 48]; } else if (inputStr[j] > '@' && inputStr[j] < 'G') { *outputInt = (*outputInt << 4) | charVal[inputStr[j] - 55]; } else if (inputStr[j] > '`' && inputStr[j] < 'g') { *outputInt = (*outputInt << 4) | charVal[inputStr[j] - 87]; } else { // invalid sequence of characters received for now simply return whatever we received // *outputStr = string(inputStr,len); ok = false; break; } } return ok; } ///------------------------------------------------------- /// @brief computes the unicode value of an ut16 symbol ///------------------------------------------------------- bool toUnicode (uint16_t w1, uint16_t w2, uint32_t *v) { uint32_t vh = w1 - 0xD800; uint32_t vl = w2 - 0xDC00; uint32_t vp = (vh << 10) | vl; *v = vp + 0x10000; return true; } bool toUtf8 (uint32_t outputInt, string & outputStr) { if ((outputInt >> 7) == 0) { outputStr.append(1, (char) (outputInt)); } // unicode sequence is in the range \u0080 to \u07ff else if ((outputInt >> 11) == 0) { outputStr.append(1, (char) ((3 << 6) | (outputInt >> 6))); outputStr.append(1, (char) ((1 << 7) | (outputInt & 63))); } // unicode sequence is in the range \u0800 to \uffff else if ((outputInt >> 16) == 0) { outputStr.append(1, (char) ((7 << 5) | (outputInt >> 12))); outputStr.append(1, (char) ((1 << 7) | ((outputInt & 4095 /* 2^12 - 1*/) >> 6))); outputStr.append(1, (char) ((1 << 7) | (outputInt & 63))); } else if ((outputInt >> 21) == 0) { outputStr.append(1, (char) ((15 << 4) | (outputInt >> 18))); outputStr.append(1, (char) ((1 << 7) | ((outputInt & 262143 /* 2^18 - 1*/) >> 12))); outputStr.append(1, (char) ((1 << 7) | ((outputInt & 4095 /* 2^12 - 1*/) >> 6))); outputStr.append(1, (char) ((1 << 7) | ((outputInt & 63)))); } else { // can't handle it yet (need 5,6 etc utf8 characters), just send back the string we got return false; } return true; } ///------------------------------------------------------- /// @brief true when number lays in the range /// U+D800 U+DBFF ///------------------------------------------------------- bool isHighSurrugate (uint32_t number) { return (number >= 0xD800) && (number <= 0xDBFF); } ///------------------------------------------------------- /// @brief true when number lays in the range /// U+DC00 U+DFFF bool isLowSurrugate (uint32_t number) { return (number >= 0xDC00) && (number <= 0xDFFF); } } namespace triagens { namespace basics { namespace StringUtils { // ............................................................................. // STRING AND STRING POINTER // ............................................................................. blob_t duplicateBlob (const blob_t& source) { blob_t result = {0,0}; if (source.length == 0 || source.data == 0) { return result; } result.data = new char[source.length]; memcpy(const_cast(result.data), source.data, source.length); result.length = source.length; return result; } blob_t duplicateBlob (char const* source, size_t len) { blob_t result = {0,0}; if (source == 0 || len == 0) { return result; } result.data = new char[len]; memcpy(const_cast(result.data), source, len); result.length = (uint32_t) len; return result; } blob_t duplicateBlob (const string& source) { blob_t result = {0,0}; if (source.size() == 0) { return result; } result.data = new char[source.size()]; memcpy(const_cast(result.data), source.c_str(), source.size()); result.length = (uint32_t) source.size(); return result; } char* duplicate (string const& source) { size_t len = source.size(); char* result = new char[len + 1]; memcpy(result, source.c_str(), len); result[len] = '\0'; return result; } char* duplicate (char const* source, size_t len) { if (source == 0) { return 0; } char* result = new char[len + 1]; memcpy(result, source, len); result[len] = '\0'; return result; } char* duplicate (char const* source) { if (source == 0) { return 0; } size_t len = strlen(source); char* result = new char[len + 1]; memcpy(result, source, len); result[len] = '\0'; return result; } void destroy (char*& source) { if (source != 0) { ::memset(source, 0, ::strlen(source)); delete[] source; source = 0; } } void destroy (char*& source, size_t length) { if (source != 0) { ::memset(source, 0, length); delete[] source; source = 0; } } void destroy (blob_t& source) { if (source.data != 0) { ::memset(const_cast(source.data), 0, source.length); delete[] source.data; source.data = 0; source.length = 0; } } void erase (char*& source) { if (source != 0) { delete[] source; source = 0; } } void erase (blob_t& source) { if (source.data != 0) { delete[] source.data; source.data = 0; source.length = 0; } } // ............................................................................. // STRING CONVERSION // ............................................................................. string capitalize (string const& name, bool first) { size_t len = name.length(); if (len == 0) { std::string message("name must not be empty"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } char * buffer = new char[len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); for (; 0 < len && isSpace(*ptr); len--, ptr++) { } if (len == 0) { std::string message("object or attribute name must not be empty"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } bool upper = first; for (; 0 < len; len--, ptr++) { if (isSpace(*ptr)) { upper = true; } else { if (upper) { *qtr++ = static_cast(::toupper(*ptr)); } else { *qtr++ = static_cast(::tolower(*ptr)); } upper = false; } } *qtr = '\0'; string result(buffer); delete[] buffer; return result; } string separate (string const& name, char separator) { size_t len = name.length(); if (len == 0) { std::string message("name must not be empty"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } char * buffer = new char[len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); for (; 0 < len && isSpace(*ptr); len--, ptr++) { } if (len == 0) { std::string message("name must not be empty"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } bool useSeparator = false; for (; 0 < len; len--, ptr++) { for (; 0 < len && isSpace(*ptr); len--, ptr++) { useSeparator = true; } if (0 < len) { if (useSeparator) { *qtr++ = separator; useSeparator = false; } *qtr++ = static_cast(::tolower(*ptr)); } else { break; } } *qtr = '\0'; string result(buffer); delete[] buffer; return result; } string escape (string const& name, string const& special, char quote) { size_t len = name.length(); if (len == 0) { return name; } if (len >= (SIZE_MAX - 1) / 2) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } char * buffer = new char [2 * len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); char const * end = ptr + len; if (special.length() == 0) { for (; ptr < end; ptr++, qtr++) { if (*ptr == quote) { *qtr++ = quote; } *qtr = *ptr; } } else if (special.length() == 1) { char s = special[0]; for (; ptr < end; ptr++, qtr++) { if (*ptr == quote || *ptr == s) { *qtr++ = quote; } *qtr = *ptr; } } else { for (; ptr < end; ptr++, qtr++) { if (*ptr == quote || special.find(*ptr) != string::npos) { *qtr++ = quote; } *qtr = *ptr; } } *qtr = '\0'; string result(buffer, qtr - buffer); delete[] buffer; return result; } string escape (string const& name, size_t len, string const& special, char quote) { if (len == 0) { return name; } if (len >= (SIZE_MAX - 1) / 2) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } char * buffer = new char [2 * len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); char const * end = ptr + len; if (special.length() == 0) { for (; ptr < end; ptr++, qtr++) { if (*ptr == quote) { *qtr++ = quote; } *qtr = *ptr; } } else if (special.length() == 1) { char s = special[0]; for (; ptr < end; ptr++, qtr++) { if (*ptr == quote || *ptr == s) { *qtr++ = quote; } *qtr = *ptr; } } else { for (; ptr < end; ptr++, qtr++) { if (*ptr == quote || special.find(*ptr) != string::npos) { *qtr++ = quote; } *qtr = *ptr; } } *qtr = '\0'; string result(buffer, qtr - buffer); delete[] buffer; return result; } string escapeUnicode (string const& name, bool escapeSlash) { size_t len = name.length(); if (len == 0) { return name; } if (len >= (SIZE_MAX - 1) / 6) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } bool corrupted = false; char * buffer = new char [6 * len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); char const * end = ptr + len; for (; ptr < end; ++ptr, ++qtr) { switch (*ptr) { case '/': if (escapeSlash) { *qtr++ = '\\'; } *qtr = *ptr; break; case '\\': case '"': *qtr++ = '\\'; *qtr = *ptr; break; case '\b': *qtr++ = '\\'; *qtr = 'b'; break; case '\f': *qtr++ = '\\'; *qtr = 'f'; break; case '\n': *qtr++ = '\\'; *qtr = 'n'; break; case '\r': *qtr++ = '\\'; *qtr = 'r'; break; case '\t': *qtr++ = '\\'; *qtr = 't'; break; case '\0': *qtr++ = '\\'; *qtr++ = 'u'; *qtr++ = '0'; *qtr++ = '0'; *qtr++ = '0'; *qtr = '0'; break; default: { uint8_t c = (uint8_t) *ptr; // character is in the normal latin1 range if ((c & 0x80) == 0) { // special character, escape if (c < 32) { *qtr++ = '\\'; *qtr++ = 'u'; *qtr++ = '0'; *qtr++ = '0'; uint16_t i1 = (static_cast(c) & 0xF0) >> 4; uint16_t i2 = (static_cast(c) & 0x0F); *qtr++ = (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10); *qtr = (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10); } // normal latin1 else { *qtr = *ptr; } } // unicode range 0080 - 07ff else if ((c & 0xE0) == 0xC0) { if (ptr + 1 < end) { uint8_t d = (uint8_t) *(ptr + 1); // correct unicode if ((d & 0xC0) == 0x80) { ++ptr; *qtr++ = '\\'; *qtr++ = 'u'; uint16_t n = ((c & 0x1F) << 6) | (d & 0x3F); uint16_t i1 = (n & 0xF000) >> 12; uint16_t i2 = (n & 0x0F00) >> 8; uint16_t i3 = (n & 0x00F0) >> 4; uint16_t i4 = (n & 0x000F); *qtr++ = (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10); *qtr++ = (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10); *qtr++ = (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10); *qtr = (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10); } // corrupted unicode else { *qtr = *ptr; corrupted = true; } } // corrupted unicode else { *qtr = *ptr; corrupted = true; } } // unicode range 0800 - ffff else if ((c & 0xF0) == 0xE0) { if (ptr + 1 < end) { uint8_t d = (uint8_t) *(ptr + 1); // correct unicode if ((d & 0xC0) == 0x80) { if (ptr + 2 < end) { uint8_t e = (uint8_t) *(ptr + 2); // correct unicode if ((e & 0xC0) == 0x80) { // TODO: if & else branch are the same *qtr = *ptr; } // corrupted unicode else { *qtr = *ptr; corrupted = true; } } // corrupted unicode else { *qtr = *ptr; corrupted = true; } } // corrupted unicode else { *qtr = *ptr; corrupted = true; } } // corrupted unicode else { *qtr = *ptr; corrupted = true; } } // unicode range 010000 - 10ffff -- NOT IMPLEMENTED else { *qtr = *ptr; } } break; } } *qtr = '\0'; string result(buffer, qtr - buffer); delete[] buffer; if (corrupted) { LOG_WARNING("escaped corrupted unicode string"); } return result; } string escapeHtml (string const& name) { size_t len = name.length(); if (len == 0) { return name; } if (len >= (SIZE_MAX - 1) / 8) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } char * buffer = new char [8 * len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); char const * end = ptr + len; for (; ptr < end; ++ptr, ++qtr) { if (*ptr == '<') { *qtr++ = '&'; *qtr++ = 'l'; *qtr++ = 't'; *qtr = ';'; } else if (*ptr == '>') { *qtr++ = '&'; *qtr++ = 'g'; *qtr++ = 't'; *qtr = ';'; } else if (*ptr == '&') { *qtr++ = '&'; *qtr++ = 'a'; *qtr++ = 'm'; *qtr++ = 'p'; *qtr = ';'; } else if (*ptr == '"') { *qtr++ = '&'; *qtr++ = 'q'; *qtr++ = 'u'; *qtr++ = 'o'; *qtr++ = 't'; *qtr = ';'; } else { *qtr = *ptr; } } *qtr = '\0'; string result(buffer, qtr - buffer); delete[] buffer; return result; } string escapeXml (string const& name) { return escapeHtml(name); } string escapeHex (string const& name, char quote) { size_t len = name.length(); if (len == 0) { return name; } if (len >= (SIZE_MAX - 1) / 3) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } char * buffer = new char [3 * len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); char const * end = ptr + len; for (; ptr < end; ptr++, qtr++) { if (*ptr == quote || *ptr <= ' ' || static_cast(*ptr) >= 128) { uint8_t n = (uint8_t)(*ptr); uint8_t n1 = n >> 4; uint8_t n2 = n & 0x0F; *qtr++ = quote; *qtr++ = (n1 < 10) ? ('0' + n1) : ('A' + n1 - 10); *qtr = (n2 < 10) ? ('0' + n2) : ('A' + n2 - 10); } else { *qtr = *ptr; } } *qtr = '\0'; string result(buffer, qtr - buffer); delete[] buffer; return result; } string escapeHex (string const& name, string const& special, char quote) { size_t len = name.length(); if (len == 0) { return name; } if (len >= (SIZE_MAX - 1) / 3) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } char * buffer = new char [3 * len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); char const * end = ptr + len; if (special.length() == 0) { for (; ptr < end; ptr++, qtr++) { if (*ptr == quote) { uint8_t n = (uint8_t)(*ptr); uint8_t n1 = n >> 4; uint8_t n2 = n & 0x0F; *qtr++ = quote; *qtr++ = (n1 < 10) ? ('0' + n1) : ('A' + n1 - 10); *qtr = (n2 < 10) ? ('0' + n2) : ('A' + n2 - 10); } else { *qtr = *ptr; } } } else if (special.length() == 1) { char s = special[0]; for (; ptr < end; ptr++, qtr++) { if (*ptr == quote || *ptr == s) { uint8_t n = (uint8_t)(*ptr); uint8_t n1 = n >> 4; uint8_t n2 = n & 0x0F; *qtr++ = quote; *qtr++ = (n1 < 10) ? ('0' + n1) : ('A' + n1 - 10); *qtr = (n2 < 10) ? ('0' + n2) : ('A' + n2 - 10); } else { *qtr = *ptr; } } } else { for (; ptr < end; ptr++, qtr++) { if (*ptr == quote || special.find(*ptr) != string::npos) { uint8_t n = (uint8_t)(*ptr); uint8_t n1 = n >> 4; uint8_t n2 = n & 0x0F; *qtr++ = quote; *qtr++ = (n1 < 10) ? ('0' + n1) : ('A' + n1 - 10); *qtr = (n2 < 10) ? ('0' + n2) : ('A' + n2 - 10); } else { *qtr = *ptr; } } } *qtr = '\0'; string result(buffer, qtr - buffer); delete[] buffer; return result; } string escapeC (string const& name) { size_t len = name.length(); if (len == 0) { return name; } if (len >= (SIZE_MAX - 1) / 4) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } char * buffer = new char [4 * len + 1]; char * qtr = buffer; char const * ptr = name.c_str(); char const * end = ptr + len; for (; ptr < end; ptr++, qtr++) { uint8_t n = (uint8_t)(*ptr); switch (*ptr) { case '\n': *qtr++ = '\\'; *qtr = 'n'; break; case '\r': *qtr++ = '\\'; *qtr = 'r'; break; case '\'': case '"': *qtr++ = '\\'; *qtr = *ptr; break; default: if (n < 32 || n > 127) { uint8_t n1 = n >> 4; uint8_t n2 = n & 0x0F; *qtr++ = '\\'; *qtr++ = 'x'; *qtr++ = (n1 < 10) ? ('0' + n1) : ('A' + n1 - 10); *qtr = (n2 < 10) ? ('0' + n2) : ('A' + n2 - 10); } else { *qtr = *ptr; } break; } } *qtr = '\0'; string result(buffer, qtr - buffer); delete[] buffer; return result; } vector split (string const& source, char delim, char quote) { vector result; if (source.empty()) { return result; } char* buffer = new char[source.size() + 1]; char* p = buffer; char const* q = source.c_str(); char const* e = source.c_str() + source.size(); if (quote == '\0') { for (; q < e; ++q) { if (*q == delim) { *p = '\0'; result.push_back(string(buffer, p - buffer)); p = buffer; } else { *p++ = *q; } } } else { for (; q < e; ++q) { if (*q == quote) { if (q + 1 < e) { *p++ = *++q; } } else if (*q == delim) { *p = '\0'; result.push_back(string(buffer, p - buffer)); p = buffer; } else { *p++ = *q; } } } *p = '\0'; result.push_back(string(buffer, p - buffer)); delete[] buffer; return result; } vector split (string const& source, string const& delim, char quote) { vector result; if (source.empty()) { return result; } char* buffer = new char[source.size() + 1]; char* p = buffer; char const* q = source.c_str(); char const* e = source.c_str() + source.size(); if (quote == '\0') { for (; q < e; ++q) { if (delim.find(*q) != string::npos) { *p = '\0'; result.push_back(string(buffer, p - buffer)); p = buffer; } else { *p++ = *q; } } } else { for (; q < e; ++q) { if (*q == quote) { if (q + 1 < e) { *p++ = *++q; } } else if (delim.find(*q) != string::npos) { *p = '\0'; result.push_back(string(buffer, p - buffer)); p = buffer; } else { *p++ = *q; } } } *p = '\0'; result.push_back(string(buffer, p - buffer)); delete[] buffer; return result; } string join (vector const& source, char delim) { string result = ""; bool first = true; for (vector::const_iterator i = source.begin(); i != source.end(); ++i) { if (first) { first = false; } else { result += delim; } result += *i; } return result; } string join (vector const& source, string const& delim) { string result = ""; bool first = true; for (vector::const_iterator i = source.begin(); i != source.end(); ++i) { if (first) { first = false; } else { result += delim; } result += *i; } return result; } string join (set const& source, char delim) { string result = ""; bool first = true; for (set::const_iterator i = source.begin(); i != source.end(); ++i) { if (first) { first = false; } else { result += delim; } result += *i; } return result; } string join (set const& source, string const& delim) { string result = ""; bool first = true; for (set::const_iterator i = source.begin(); i != source.end(); ++i) { if (first) { first = false; } else { result += delim; } result += *i; } return result; } string trim (string const& sourceStr, string const& trimStr) { size_t s = sourceStr.find_first_not_of(trimStr); size_t e = sourceStr.find_last_not_of(trimStr); if (s == std::string::npos) { return string(); } else { return string(sourceStr, s, e - s + 1); } } void trimInPlace (string& str, string const& trimStr) { size_t s = str.find_first_not_of(trimStr); size_t e = str.find_last_not_of(trimStr); if (s == std::string::npos) { str.clear(); } else if (s == 0 && e == str.length() - 1) { // nothing to do } else if (s == 0) { str.erase(e + 1); } else { str = str.substr(s, e-s+1); } } string lTrim (string const& str, string const& trimStr) { size_t s = str.find_first_not_of(trimStr); if (s == std::string::npos) { return string(); } else { return string(str, s); } } string rTrim (string const& sourceStr, string const& trimStr) { size_t e = sourceStr.find_last_not_of(trimStr); return string(sourceStr, 0, e + 1); } string lFill (string const& sourceStr, size_t size, char fill) { size_t l = sourceStr.size(); if (l >= size) { return sourceStr; } return string(size - l, fill) + sourceStr; } string rFill (string const& sourceStr, size_t size, char fill) { size_t l = sourceStr.size(); if (l >= size) { return sourceStr; } return sourceStr + string(size - l, fill); } vector wrap (string const& sourceStr, size_t size, string breaks) { vector result; string next = sourceStr; if (size > 0) { while (next.size() > size) { size_t m = next.find_last_of(breaks, size - 1); if (m == string::npos || m < size / 2) { m = size; } else { m += 1; } result.push_back(next.substr(0, m)); next = next.substr(m); } } result.push_back(next); return result; } /// replaces the contents of the sourceStr = "aaebbbbcce" where ever the occurence of /// fromStr = "bb" exists with the toStr = "dd". No recursion performed on the replaced string /// e.g. replace("aaebbbbcce","bb","dd") = "aaeddddcce" /// e.g. replace("aaebbbbcce","bb","bbb") = "aaebbbbbbcce" /// e.g. replace("aaebbbbcce","bbb","bb") = "aaebbbcce" string replace (string const& sourceStr, string const& fromStr, string const& toStr) { size_t fromLength = fromStr.length(); size_t toLength = toStr.length(); size_t sourceLength = sourceStr.length(); // cannot perform a replace if the sourceStr = "" or fromStr = "" if (fromLength == 0 || sourceLength == 0) { return sourceStr; } // the max amount of memory is: size_t mt = max(static_cast(1),toLength); if ((sourceLength / fromLength) + 1 >= (SIZE_MAX - toLength) / mt) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } size_t maxLength = (((sourceLength / fromLength) + 1) * mt) + toLength; // the min amount of memory we have to allocate for the "replace" (new) string is length of sourceStr maxLength = max(maxLength, sourceLength) + 1; char* result = new char[maxLength]; size_t k = 0; for (size_t j = 0; j < sourceLength; ++j) { bool match = true; for (size_t i = 0; i < fromLength; ++i) { if (sourceStr[j + i] != fromStr[i]) { match = false; break; } } if (! match) { result[k] = sourceStr[j]; ++k; continue; } for (size_t i = 0; i < toLength; ++i) { result[k] = toStr[i]; ++k; } j += (fromLength - 1); } result[k] = '\0'; string retStr(result); delete[] result; return retStr; } void tolowerInPlace (string* str) { size_t len = str->length(); if (len == 0) { return; } for (string::iterator i = str->begin(); i != str->end(); ++i) { *i = ::tolower(*i); } } string tolower (string const& str) { size_t len = str.length(); if (len == 0) { return ""; } char * buffer = new char[len]; char * qtr = buffer; char const * ptr = str.c_str(); for (; 0 < len; len--, ptr++, qtr++) { *qtr = static_cast(::tolower(*ptr)); } string result(buffer, str.size()); delete[] buffer; return result; } void toupperInPlace (string* str) { size_t len = str->length(); if (len == 0) { return; } for (string::iterator i = str->begin(); i != str->end(); ++i) { *i = ::toupper(*i); } } string toupper (string const& str) { size_t len = str.length(); if (len == 0) { return ""; } char * buffer = new char[len]; char * qtr = buffer; char const * ptr = str.c_str(); for (; 0 < len; len--, ptr++, qtr++) { *qtr = static_cast(::toupper(*ptr)); } string result(buffer, str.size()); delete[] buffer; return result; } bool isPrefix (string const& str, string const& prefix) { if (prefix.length() > str.length()) { return false; } else if (prefix.length() == str.length()) { return str == prefix; } else { return str.compare(0, prefix.length(), prefix) == 0; } } bool isSuffix (string const& str, string const& postfix) { if (postfix.length() > str.length()) { return false; } else if (postfix.length() == str.length()) { return str == postfix; } else { return str.compare(str.size() - postfix.length(), postfix.length(), postfix) == 0; } } string urlDecode (string const& str) { char const* src = str.c_str(); char const* end = src + str.size(); char* buffer = new char[str.size() + 1]; char* ptr = buffer; for (; src < end && *src != '%'; ++src) { if (*src == '+') { *ptr++ = ' '; } else { *ptr++ = *src; } } while (src < end) { if (src + 2 < end) { int h1 = hex2int(src[1], -1); int h2 = hex2int(src[2], -1); if (h1 == -1) { src += 1; } else { if (h2 == -1) { *ptr++ = h1; src += 2; } else { *ptr++ = h1 << 4 | h2; src += 3; } } } else if (src + 1 < end) { int h1 = hex2int(src[1], -1); if (h1 == -1) { src += 1; } else { *ptr++ = h1; src += 2; } } else { src += 1; } for (; src < end && *src != '%'; ++src) { if (*src == '+') { *ptr++ = ' '; } else { *ptr++ = *src; } } } *ptr = '\0'; string result(buffer, ptr - buffer); delete[] buffer; return result; } string urlEncode (string const& str) { return urlEncode(str.c_str(), str.size()); } string urlEncode (const char* src) { if (src != 0) { size_t len = strlen(src); return urlEncode(src, len); } return ""; } string urlEncode (const char* src, const size_t len) { static char hexChars[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; char const* end = src + len; if (len >= (SIZE_MAX - 1) / 3) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } char* buffer = new char[3 * len + 1]; char* ptr = buffer; for (; src < end; ++src) { if ('0' <= *src && *src <= '9') { *ptr++ = *src; } else if ('a' <= *src && *src <= 'z') { *ptr++ = *src; } else if ('A' <= *src && *src <= 'Z') { *ptr++ = *src; } else if (*src == '-' || *src == '_' || *src == '.' || *src == '~') { *ptr++ = *src; } else { uint8_t n = (uint8_t)(*src); uint8_t n1 = n >> 4; uint8_t n2 = n & 0x0F; *ptr++ = '%'; *ptr++ = hexChars[n1]; *ptr++ = hexChars[n2]; } } *ptr = '\0'; string result(buffer, ptr - buffer); delete[] buffer; return result; } // ............................................................................. // CONVERT TO STRING // ............................................................................. string itoa (int16_t attr) { char buffer[7]; char* p = buffer; if (attr == INT16_MIN) { return "-32768"; } if (attr < 0) { *p++ = '-'; attr = -attr; } if ( 10000L <= attr) { *p++ = char((attr / 10000L) % 10 + '0'); } if ( 1000L <= attr) { *p++ = char((attr / 1000L) % 10 + '0'); } if ( 100L <= attr) { *p++ = char((attr / 100L) % 10 + '0'); } if ( 10L <= attr) { *p++ = char((attr / 10L) % 10 + '0'); } *p++ = char(attr % 10 + '0'); *p = '\0'; return buffer; } string itoa (uint16_t attr) { char buffer[6]; char* p = buffer; if ( 10000L <= attr) { *p++ = char((attr / 10000L) % 10 + '0'); } if ( 1000L <= attr) { *p++ = char((attr / 1000L) % 10 + '0'); } if ( 100L <= attr) { *p++ = char((attr / 100L) % 10 + '0'); } if ( 10L <= attr) { *p++ = char((attr / 10L) % 10 + '0'); } *p++ = char(attr % 10 + '0'); *p = '\0'; return buffer; } string itoa (int32_t attr) { char buffer[12]; char* p = buffer; if (attr == INT32_MIN) { return "-2147483648"; } if (attr < 0) { *p++ = '-'; attr = -attr; } if (1000000000L <= attr) { *p++ = char((attr / 1000000000L) % 10 + '0'); } if ( 100000000L <= attr) { *p++ = char((attr / 100000000L) % 10 + '0'); } if ( 10000000L <= attr) { *p++ = char((attr / 10000000L) % 10 + '0'); } if ( 1000000L <= attr) { *p++ = char((attr / 1000000L) % 10 + '0'); } if ( 100000L <= attr) { *p++ = char((attr / 100000L) % 10 + '0'); } if ( 10000L <= attr) { *p++ = char((attr / 10000L) % 10 + '0'); } if ( 1000L <= attr) { *p++ = char((attr / 1000L) % 10 + '0'); } if ( 100L <= attr) { *p++ = char((attr / 100L) % 10 + '0'); } if ( 10L <= attr) { *p++ = char((attr / 10L) % 10 + '0'); } *p++ = char(attr % 10 + '0'); *p = '\0'; return buffer; } string itoa (uint32_t attr) { char buffer[11]; char* p = buffer; if (1000000000L <= attr) { *p++ = char((attr / 1000000000L) % 10 + '0'); } if ( 100000000L <= attr) { *p++ = char((attr / 100000000L) % 10 + '0'); } if ( 10000000L <= attr) { *p++ = char((attr / 10000000L) % 10 + '0'); } if ( 1000000L <= attr) { *p++ = char((attr / 1000000L) % 10 + '0'); } if ( 100000L <= attr) { *p++ = char((attr / 100000L) % 10 + '0'); } if ( 10000L <= attr) { *p++ = char((attr / 10000L) % 10 + '0'); } if ( 1000L <= attr) { *p++ = char((attr / 1000L) % 10 + '0'); } if ( 100L <= attr) { *p++ = char((attr / 100L) % 10 + '0'); } if ( 10L <= attr) { *p++ = char((attr / 10L) % 10 + '0'); } *p++ = char(attr % 10 + '0'); *p = '\0'; return buffer; } string itoa (int64_t attr) { char buffer[21]; char* p = buffer; if (attr == INT64_MIN) { return "-9223372036854775808"; } if (attr < 0) { *p++ = '-'; attr = -attr; } if (1000000000000000000LL <= attr) { *p++ = char((attr / 1000000000000000000LL) % 10 + '0'); } if ( 100000000000000000LL <= attr) { *p++ = char((attr / 100000000000000000LL) % 10 + '0'); } if ( 10000000000000000LL <= attr) { *p++ = char((attr / 10000000000000000LL) % 10 + '0'); } if ( 1000000000000000LL <= attr) { *p++ = char((attr / 1000000000000000LL) % 10 + '0'); } if ( 100000000000000LL <= attr) { *p++ = char((attr / 100000000000000LL) % 10 + '0'); } if ( 10000000000000LL <= attr) { *p++ = char((attr / 10000000000000LL) % 10 + '0'); } if ( 1000000000000LL <= attr) { *p++ = char((attr / 1000000000000LL) % 10 + '0'); } if ( 100000000000LL <= attr) { *p++ = char((attr / 100000000000LL) % 10 + '0'); } if ( 10000000000LL <= attr) { *p++ = char((attr / 10000000000LL) % 10 + '0'); } if ( 1000000000LL <= attr) { *p++ = char((attr / 1000000000LL) % 10 + '0'); } if ( 100000000LL <= attr) { *p++ = char((attr / 100000000LL) % 10 + '0'); } if ( 10000000LL <= attr) { *p++ = char((attr / 10000000LL) % 10 + '0'); } if ( 1000000LL <= attr) { *p++ = char((attr / 1000000LL) % 10 + '0'); } if ( 100000LL <= attr) { *p++ = char((attr / 100000LL) % 10 + '0'); } if ( 10000LL <= attr) { *p++ = char((attr / 10000LL) % 10 + '0'); } if ( 1000LL <= attr) { *p++ = char((attr / 1000LL) % 10 + '0'); } if ( 100LL <= attr) { *p++ = char((attr / 100LL) % 10 + '0'); } if ( 10LL <= attr) { *p++ = char((attr / 10LL) % 10 + '0'); } *p++ = char(attr % 10 + '0'); *p = '\0'; return buffer; } string itoa (uint64_t attr) { char buffer[21]; char* p = buffer; if (10000000000000000000ULL <= attr) { *p++ = char((attr / 10000000000000000000ULL) % 10 + '0'); } if ( 1000000000000000000ULL <= attr) { *p++ = char((attr / 1000000000000000000ULL) % 10 + '0'); } if ( 100000000000000000ULL <= attr) { *p++ = char((attr / 100000000000000000ULL) % 10 + '0'); } if ( 10000000000000000ULL <= attr) { *p++ = char((attr / 10000000000000000ULL) % 10 + '0'); } if ( 1000000000000000ULL <= attr) { *p++ = char((attr / 1000000000000000ULL) % 10 + '0'); } if ( 100000000000000ULL <= attr) { *p++ = char((attr / 100000000000000ULL) % 10 + '0'); } if ( 10000000000000ULL <= attr) { *p++ = char((attr / 10000000000000ULL) % 10 + '0'); } if ( 1000000000000ULL <= attr) { *p++ = char((attr / 1000000000000ULL) % 10 + '0'); } if ( 100000000000ULL <= attr) { *p++ = char((attr / 100000000000ULL) % 10 + '0'); } if ( 10000000000ULL <= attr) { *p++ = char((attr / 10000000000ULL) % 10 + '0'); } if ( 1000000000ULL <= attr) { *p++ = char((attr / 1000000000ULL) % 10 + '0'); } if ( 100000000ULL <= attr) { *p++ = char((attr / 100000000ULL) % 10 + '0'); } if ( 10000000ULL <= attr) { *p++ = char((attr / 10000000ULL) % 10 + '0'); } if ( 1000000ULL <= attr) { *p++ = char((attr / 1000000ULL) % 10 + '0'); } if ( 100000ULL <= attr) { *p++ = char((attr / 100000ULL) % 10 + '0'); } if ( 10000ULL <= attr) { *p++ = char((attr / 10000ULL) % 10 + '0'); } if ( 1000ULL <= attr) { *p++ = char((attr / 1000ULL) % 10 + '0'); } if ( 100ULL <= attr) { *p++ = char((attr / 100ULL) % 10 + '0'); } if ( 10ULL <= attr) { *p++ = char((attr / 10ULL) % 10 + '0'); } *p++ = char(attr % 10 + '0'); *p = '\0'; return buffer; } string ftoa (double i) { StringBuffer buffer(TRI_CORE_MEM_ZONE); buffer.appendDecimal(i); string result(buffer.c_str()); return result; } // ............................................................................. // CONVERT FROM STRING // ............................................................................. bool boolean (string const& str) { string lower = tolower(trim(str)); if (lower == "true" || lower == "yes" || lower == "on" || lower == "y" || lower == "1") { return true; } else { return false; } } int64_t int64 (string const& str) { #ifdef TRI_HAVE_STRTOLL_R struct reent buffer; return strtoll_r(&buffer, str.c_str(), 0, 10); #else #ifdef TRI_HAVE__STRTOLL_R struct reent buffer; return _strtoll_r(&buffer, str.c_str(), 0, 10); #else #ifdef TRI_HAVE_STRTOLL return strtoll(str.c_str(), 0, 10); #else return stoll(str, 0, 10); #endif #endif #endif } int64_t int64 (char const* value, size_t size) { char tmp[22]; if (value[size] != '\0') { if (size >= sizeof(tmp)) { size = sizeof(tmp) - 1; } memcpy(tmp, value, size); tmp[size] = '\0'; value = tmp; } #ifdef TRI_HAVE_STRTOLL_R struct reent buffer; return strtoll_r(&buffer, value, 0, 10); #else #ifdef TRI_HAVE__STRTOLL_R struct reent buffer; return _strtoll_r(&buffer, value, 0, 10); #else #ifdef TRI_HAVE_STRTOLL return strtoll(value, 0, 10); #else return stoll(string(value, size), 0, 10); #endif #endif #endif } uint64_t uint64 (string const& str) { #ifdef TRI_HAVE_STRTOULL_R struct reent buffer; return strtoull_r(&buffer, str.c_str(), 0, 10); #else #ifdef TRI_HAVE__STRTOULL_R struct reent buffer; return _strtoull_r(&buffer, str.c_str(), 0, 10); #else #ifdef TRI_HAVE_STRTOULL return strtoull(str.c_str(), 0, 10); #else return stoull(str, 0, 10); #endif #endif #endif } uint64_t uint64 (char const* value, size_t size) { char tmp[22]; if (value[size] != '\0') { if (size >= sizeof(tmp)) { size = sizeof(tmp) - 1; } memcpy(tmp, value, size); tmp[size] = '\0'; value = tmp; } #ifdef TRI_HAVE_STRTOULL_R struct reent buffer; return strtoull_r(&buffer, value, 0, 10); #else #ifdef TRI_HAVE__STRTOULL_R struct reent buffer; return _strtoull_r(&buffer, value, 0, 10); #else #ifdef TRI_HAVE_STRTOULL return strtoull(value, 0, 10); #else return stoull(string(value, size), 0, 10); #endif #endif #endif } int32_t int32 (string const& str) { #ifdef TRI_HAVE_STRTOL_R struct reent buffer; return strtol_r(&buffer, str.c_str(), 0, 10); #else #ifdef TRI_HAVE__STRTOL_R struct reent buffer; return _strtol_r(&buffer, str.c_str(), 0, 10); #else return strtol(str.c_str(), 0, 10); #endif #endif } int32_t int32 (char const* value, size_t size) { char tmp[22]; if (value[size] != '\0') { if (size >= sizeof(tmp)) { size = sizeof(tmp) - 1; } memcpy(tmp, value, size); tmp[size] = '\0'; value = tmp; } #ifdef TRI_HAVE_STRTOL_R struct reent buffer; return strtol_r(&buffer, value, 0, 10); #else #ifdef TRI_HAVE__STRTOL_R struct reent buffer; return _strtol_r(&buffer, value, 0, 10); #else return strtol(value, 0, 10); #endif #endif } uint32_t uint32 (string const& str) { #ifdef TRI_HAVE_STRTOUL_R struct reent buffer; return strtoul_r(&buffer, str.c_str(), 0, 10); #else #ifdef TRI_HAVE__STRTOUL_R struct reent buffer; return _strtoul_r(&buffer, str.c_str(), 0, 10); #else return strtoul(str.c_str(), 0, 10); #endif #endif } uint32_t unhexUint32 (string const& str) { #ifdef TRI_HAVE_STRTOUL_R struct reent buffer; return strtoul_r(&buffer, str.c_str(), 0, 16); #else #ifdef TRI_HAVE__STRTOUL_R struct reent buffer; return _strtoul_r(&buffer, str.c_str(), 0, 16); #else return strtoul(str.c_str(), 0, 16); #endif #endif } uint32_t uint32 (char const* value, size_t size) { char tmp[22]; if (value[size] != '\0') { if (size >= sizeof(tmp)) { size = sizeof(tmp) - 1; } memcpy(tmp, value, size); tmp[size] = '\0'; value = tmp; } #ifdef TRI_HAVE_STRTOUL_R struct reent buffer; return strtoul_r(&buffer, value, 0, 10); #else #ifdef TRI_HAVE__STRTOUL_R struct reent buffer; return _strtoul_r(&buffer, value, 0, 10); #else return strtoul(value, 0, 10); #endif #endif } uint32_t unhexUint32 (char const* value, size_t size) { char tmp[22]; if (value[size] != '\0') { if (size >= sizeof(tmp)) { size = sizeof(tmp) - 1; } memcpy(tmp, value, size); tmp[size] = '\0'; value = tmp; } #ifdef TRI_HAVE_STRTOUL_R struct reent buffer; return strtoul_r(&buffer, value, 0, 16); #else #ifdef TRI_HAVE__STRTOUL_R struct reent buffer; return _strtoul_r(&buffer, value, 0, 16); #else return strtoul(value, 0, 16); #endif #endif } double doubleDecimal (string const& str) { return doubleDecimal(str.c_str(), str.size()); } double doubleDecimal (char const* value, size_t size) { double v = 0.0; double e = 1.0; bool seenDecimalPoint = false; uint8_t const* ptr = reinterpret_cast(value); uint8_t const* end = ptr + size; // check for the sign first if (*ptr == '-') { e = -e; ++ptr; } else if (*ptr == '+') { ++ptr; } for (; ptr < end; ++ptr) { uint8_t n = *ptr; if (n == '.' && ! seenDecimalPoint) { seenDecimalPoint = true; continue; } if ('9' < n || n < '0') { break; } v = v * 10.0 + (n - 48); if (seenDecimalPoint) { e = e * 10.0; } } // we have reached the end without an exponent if (ptr == end) { return v / e; } // invalid decimal representation if (*ptr != 'e' && *ptr != 'E') { return 0.0; } ++ptr; // move past the 'e' or 'E' int32_t expSign = 1; int32_t expValue = 0; // is there an exponent sign? if (*ptr == '-') { expSign = -1; ++ptr; } else if (*ptr == '+') { ++ptr; } for (; ptr < end; ++ptr) { uint8_t n = *ptr; if ('9' < n || n < '0') { return 0.0; } expValue = expValue * 10 + (n - 48); } expValue = expValue * expSign; return (v / e) * pow(10.0, double(expValue)); } float floatDecimal (string const& str) { return floatDecimal(str.c_str(), str.size()); } float floatDecimal (char const* value, size_t size) { return (float) doubleDecimal(value, size); } seconds_t seconds (string const& format, string const& str) { int32_t hour = 0; int32_t minute = 0; int32_t second = 0; char const * f = format.c_str(); char const * s = str.c_str(); while (*f) { if (*f == 'H') { if (strncmp(f, "HH", 2) == 0) { hour = matchInteger(s, 2); f += 2; } else { std::string message("unknown time format '" + string(f) + "', expecting 'HH'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == 'M') { if (strncmp(f, "MI", 2) == 0) { minute = matchInteger(s, 2); f += 2; } else { std::string message("unknown time format '" + string(f) + "', expecting 'MI'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == 'S') { if (strncmp(f, "SSS", 3) == 0) { int32_t seconds = matchInteger(s); f += 3; hour = (seconds / 3600); minute = (seconds / 60) % 60; second = (seconds ) % 60; } else if (strncmp(f, "SS", 2) == 0) { second = matchInteger(s, 2); f += 2; } else { std::string message("unknown time format '" + string(f) + "', expecting 'SS'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == *s) { f++; s++; } else { std::string message("cannot match time '" + str + "' with format '" + format + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } if (23 < hour || hour < 0) { std::string message("illegal hour '" + itoa(hour) + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } if (59 < minute || minute < 0) { std::string message("illegal minute '" + itoa(minute) + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } if (59 < second || second < 0) { std::string message("illegal second '" + itoa(second) + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } return hour * 3600 + minute * 60 + second; } string formatSeconds (seconds_t date) { int hour = date / 3600; int minute = (date / 60) % 60; int second = date % 60; StringBuffer buffer(TRI_CORE_MEM_ZONE); buffer.appendInteger2(hour); buffer.appendChar(':'); buffer.appendInteger2(minute); buffer.appendChar(':'); buffer.appendInteger2(second); string result(buffer.c_str()); return result; } string formatSeconds (string const& format, seconds_t date) { return formatDateTime(format, 0, date); } date_t date (string const& format, string const& str) { int32_t year = 1970; int32_t month = 1; int32_t day = 1; char const * f = format.c_str(); char const * s = str.c_str(); while (*f) { if (*f == 'Y') { if (strncmp(f, "YYYY", 4) == 0) { year = matchInteger(s, 4); f += 4; } else { std::string message("unknown date format '" + string(f) + "', expecting 'YYYY'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == 'M') { if (strncmp(f, "MM", 2) == 0) { month = matchInteger(s, 2); f += 2; } else { std::string message("unknown date format '" + string(f) + "', expecting 'MM'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == 'D') { if (strncmp(f, "DD", 2) == 0) { day = matchInteger(s, 2); f += 2; } else { std::string message("unknown date format '" + string(f) + "', expecting 'DD'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == *s) { f++; s++; } else { std::string message("cannot match date '" + str + "' with format '" + format + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } if (12 < month || month < 1) { std::string message("illegal month '" + itoa(month) + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } if (31 < day || day < 1) { std::string message("illegal day '" + itoa(day) + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } struct tm t; t.tm_sec = 0; t.tm_min = 0; t.tm_hour = 0; t.tm_mday = day; t.tm_mon = month - 1; t.tm_year = year - 1900; t.tm_isdst = 0; return date_t((mktime(&t) - GLOBAL_TIMEZONE) / 86400); } string formatDate (date_t date) { time_t ti = date * 86400; #ifdef TRI_HAVE_GMTIME_R struct tm t; gmtime_r(&ti, &t); #else #ifdef TRI_HAVE_GMTIME_S struct tm t; gmtime_s(&t, &ti); #else struct tm t; struct tm* tp = gmtime(&ti); if (tp != 0) { memcpy(&t, tp, sizeof(struct tm)); } #endif #endif StringBuffer buffer(TRI_CORE_MEM_ZONE); buffer.appendInteger4(t.tm_year + 1900); buffer.appendChar('-'); buffer.appendInteger2(t.tm_mon + 1); buffer.appendChar('-'); buffer.appendInteger2(t.tm_mday); string result(buffer.c_str()); return result; } string formatDate (string const& format, date_t date) { return formatDateTime(format, date, 0); } datetime_t datetime (string const& format, string const& str) { int32_t year = 1970; int32_t month = 1; int32_t day = 1; int32_t hour = 0; int32_t minute = 0; int32_t second = 0; char const * f = format.c_str(); char const * s = str.c_str(); while (*f) { if (*f == 'Y') { if (strncmp(f, "YYYY", 4) == 0) { year = matchInteger(s, 4); f += 4; } else { std::string message("unknown date format '" + string(f) + "', expecting 'YYYY'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == 'M') { if (strncmp(f, "MM", 2) == 0) { month = matchInteger(s, 2); f += 2; } else if (strncmp(f, "MI", 2) == 0) { minute = matchInteger(s, 2); f += 2; } else { std::string message("unknown date format '" + string(f) + "', expecting 'MM'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == 'D') { if (strncmp(f, "DD", 2) == 0) { day = matchInteger(s, 2); f += 2; } else { std::string message("unknown date format '" + string(f) + "', expecting 'DD'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == 'H') { if (strncmp(f, "HH", 2) == 0) { hour = matchInteger(s, 2); f += 2; } else { std::string message("unknown time format '" + string(f) + "', expecting 'HH'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == 'S') { if (strncmp(f, "SSSSS", 5) == 0) { time_t seconds = matchInteger(s); f += 5; #ifdef TRI_HAVE_GMTIME_R struct tm t; time_t ts = seconds; gmtime_r(&ts, &t); #else #ifdef TRI_HAVE_GMTIME_S struct tm t; time_t ts = seconds; gmtime_s(&t, &ts); #else struct tm t; time_t ts = seconds; struct tm* tp = gmtime(&ts); if (tp != 0) { memcpy(&t, tp, sizeof(struct tm)); } #endif #endif second = t.tm_sec; minute = t.tm_min; hour = t.tm_hour; day = t.tm_mday; month = t.tm_mon + 1; year = t.tm_year + 1900; } else if (strncmp(f, "SSS", 3) == 0) { int32_t seconds = matchInteger(s); f += 3; hour = (seconds / 3600); minute = (seconds / 60) % 60; second = (seconds ) % 60; } else if (strncmp(f, "SS", 2) == 0) { second = matchInteger(s, 2); f += 2; } else { std::string message("unknown time format '" + string(f) + "', expecting 'SS'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } else if (*f == *s) { f++; s++; } else { std::string message("cannot match date '" + str + "' with format '" + format + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } } if (12 < month || month < 1) { std::string message("illegal month'" + itoa(month) + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } if (31 < day || day < 1) { std::string message("illegal day '" + itoa(day) + "'"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message); } struct tm t; t.tm_sec = second; t.tm_min = minute; t.tm_hour = hour; t.tm_mday = day; t.tm_mon = month - 1; t.tm_year = year - 1900; t.tm_isdst = 0; return datetime_t((mktime(&t) - GLOBAL_TIMEZONE)); } string formatDatetime (datetime_t datetime) { int64_t cnv = static_cast(datetime); date_t d = date_t(cnv / 86400LL); seconds_t s = seconds_t(cnv % 86400LL); return formatDateTime(d, s); } string formatDatetime (string const& format, datetime_t datetime) { int64_t cnv = static_cast(datetime); date_t d = date_t(cnv / 86400LL); seconds_t s = seconds_t(cnv % 86400LL); return formatDateTime(format, d, s); } string formatDateTime (date_t date, seconds_t time) { time_t ti = date * 86400; #ifdef TRI_HAVE_GMTIME_R struct tm t; gmtime_r(&ti, &t); #else #ifdef TRI_HAVE_GMTIME_S struct tm t; gmtime_s(&t, &ti); #else struct tm t; struct tm* tp = gmtime(&ti); if (tp != 0) { memcpy(&t, tp, sizeof(struct tm)); } #endif #endif int hour = time / 3600; int minute = (time / 60) % 60; int second = time % 60; StringBuffer buffer(TRI_CORE_MEM_ZONE); buffer.appendInteger4(t.tm_year + 1900); buffer.appendChar('-'); buffer.appendInteger2(t.tm_mon + 1); buffer.appendChar('-'); buffer.appendInteger2(t.tm_mday); buffer.appendChar('T'); buffer.appendInteger2(hour); buffer.appendChar(':'); buffer.appendInteger2(minute); buffer.appendChar(':'); buffer.appendInteger2(second); string result(buffer.c_str()); return result; } string formatDateTime (string const& format, date_t date, seconds_t time) { time_t ti = date * 86400; #ifdef TRI_HAVE_GMTIME_R struct tm t; gmtime_r(&ti, &t); #else #ifdef TRI_HAVE_GMTIME_S struct tm t; gmtime_s(&t, &ti); #else struct tm t; struct tm* tp = gmtime(&ti); if (tp != 0) { memcpy(&t, tp, sizeof(struct tm)); } #endif #endif int year = t.tm_year + 1900; int month = t.tm_mon + 1; int day = t.tm_mday; int wday = t.tm_wday + 1; int yday = t.tm_yday + 1; int hour = time / 3600; int minute = (time / 60) % 60; int second = time % 60; StringBuffer buffer(TRI_CORE_MEM_ZONE); char const* p = format.c_str(); char const* e = p + format.size(); for (; p < e; ++p) { // ............................................................................. // quote // ............................................................................. if (p[0] == '"') { for (++p; p[0] != '"' && p < e; ++p) { buffer.appendChar(p[0]); } continue; } // ............................................................................. // YYYY, YYY, YY, or Y // ............................................................................. if (p[0] == 'Y' || p[0] == 'y') { // YYYY, YYY, or YY if (p + 1 < e && (p[1] == 'Y' || p[1] == 'y')) { // YYYY or YYY if (p + 2 < e && (p[2] == 'Y' || p[2] == 'y')) { // YYYY if (p + 3 < e && (p[3] == 'Y' || p[3] == 'y')) { buffer.appendInteger4(year); p += 3; } // YYY else { buffer.appendInteger3(year % 1000); p += 2; } } // YY else { buffer.appendInteger2(year % 100); p += 1; } } // Y else { buffer.appendChar((year % 10) + '0'); } continue; } // ............................................................................. // MM, MONTH, MON, MI // ............................................................................. if (p[0] == 'M' || p[0] == 'm') { // MM if (p + 1 < e && (p[1] == 'M' || p[1] == 'm')) { buffer.appendInteger2(month); p += 1; continue; } // MI else if (p + 1 < e && (p[1] == 'I' || p[1] == 'i')) { buffer.appendInteger2(minute); p += 1; continue; } // MONTH else if (p + 4 < e && strcasecmp(p + 1, "onth") == 0) { if (p[1] == 'O') { switch (month) { case 1: buffer.appendText("JANUARY"); break; case 2: buffer.appendText("FEBRUARY"); break; case 3: buffer.appendText("MARCH"); break; case 4: buffer.appendText("APRIL"); break; case 5: buffer.appendText("MAY"); break; case 6: buffer.appendText("JUNE"); break; case 7: buffer.appendText("JULY"); break; case 8: buffer.appendText("AUGUST"); break; case 9: buffer.appendText("SEPTEMBER"); break; case 10: buffer.appendText("OCTOBER"); break; case 11: buffer.appendText("NOVEMBER"); break; case 12: buffer.appendText("DECEMBER"); break; default: buffer.appendText("UNDEFINED"); break; } } else { switch (month) { case 1: buffer.appendText("January"); break; case 2: buffer.appendText("February"); break; case 3: buffer.appendText("March"); break; case 4: buffer.appendText("April"); break; case 5: buffer.appendText("May"); break; case 6: buffer.appendText("June"); break; case 7: buffer.appendText("July"); break; case 8: buffer.appendText("August"); break; case 9: buffer.appendText("September"); break; case 10: buffer.appendText("October"); break; case 11: buffer.appendText("November"); break; case 12: buffer.appendText("December"); break; default: buffer.appendText("Undefined"); break; } } p += 4; continue; } // MON else if (p + 2 < e && strcasecmp(p + 1, "on") == 0) { if (p[1] == 'O') { switch (month) { case 1: buffer.appendText("JAN"); break; case 2: buffer.appendText("FEB"); break; case 3: buffer.appendText("MAR"); break; case 4: buffer.appendText("APR"); break; case 5: buffer.appendText("MAY"); break; case 6: buffer.appendText("JUN"); break; case 7: buffer.appendText("JUL"); break; case 8: buffer.appendText("AUG"); break; case 9: buffer.appendText("SEP"); break; case 10: buffer.appendText("OCT"); break; case 11: buffer.appendText("NOV"); break; case 12: buffer.appendText("DEC"); break; default: buffer.appendText("UDF"); break; } } else { switch (month) { case 1: buffer.appendText("Jan"); break; case 2: buffer.appendText("Feb"); break; case 3: buffer.appendText("Mar"); break; case 4: buffer.appendText("Apr"); break; case 5: buffer.appendText("May"); break; case 6: buffer.appendText("Jun"); break; case 7: buffer.appendText("Jul"); break; case 8: buffer.appendText("Aug"); break; case 9: buffer.appendText("Sep"); break; case 10: buffer.appendText("Oct"); break; case 11: buffer.appendText("Nov"); break; case 12: buffer.appendText("Dec"); break; default: buffer.appendText("Udf"); break; } } p += 2; continue; } } // ............................................................................. // DAY, D, DD, DDD, DY // ............................................................................. if (p[0] == 'D' || p[0] == 'd') { // DDD, DD if (p + 1 < e && (p[1] == 'D' || p[1] == 'd')) { // DDD if (p + 2 < e && (p[2] == 'D' || p[2] == 'd')) { buffer.appendInteger3(yday); p += 2; } // DD else { buffer.appendInteger2(day); p += 1; } } // DY else if (p + 1 < e && (p[1] == 'Y' || p[1] == 'y')) { if (p[1] == 'Y') { switch (wday) { case 1: buffer.appendText("SUN"); break; case 2: buffer.appendText("MON"); break; case 3: buffer.appendText("TUE"); break; case 4: buffer.appendText("WED"); break; case 5: buffer.appendText("THU"); break; case 6: buffer.appendText("FRI"); break; case 7: buffer.appendText("SAT"); break; default: buffer.appendText("UDF"); break; } } else { switch (wday) { case 1: buffer.appendText("Sun"); break; case 2: buffer.appendText("Mon"); break; case 3: buffer.appendText("Tue"); break; case 4: buffer.appendText("Wed"); break; case 5: buffer.appendText("Thu"); break; case 6: buffer.appendText("Fri"); break; case 7: buffer.appendText("Sat"); break; default: buffer.appendText("Udf"); break; } } p += 1; } // DAY else if (p + 2 < e && (p[1] == 'A' || p[1] == 'a') && (p[2] == 'Y' || p[2] == 'y')) { if (p[2] == 'A') { switch (wday) { case 1: buffer.appendText("SUNDAY"); break; case 2: buffer.appendText("MONDAY"); break; case 3: buffer.appendText("TUESDAY"); break; case 4: buffer.appendText("WEDNESDAY"); break; case 5: buffer.appendText("THURSDAY"); break; case 6: buffer.appendText("FRIDAY"); break; case 7: buffer.appendText("SATURDAY"); break; default: buffer.appendText("UNDEFINED"); break; } } else { switch (wday) { case 1: buffer.appendText("Sunday"); break; case 2: buffer.appendText("Monday"); break; case 3: buffer.appendText("Tuesday"); break; case 4: buffer.appendText("Wednesday"); break; case 5: buffer.appendText("Thursday"); break; case 6: buffer.appendText("Friday"); break; case 7: buffer.appendText("Saturday"); break; default: buffer.appendText("Undefined"); break; } } p += 2; } // D else { buffer.appendInteger(wday); } continue; } // ............................................................................. // HH, HH12, HH24 // ............................................................................. if (p[0] == 'H' || p[0] == 'h') { if (p + 1 < e && (p[1] == 'H' || p[1] == 'h')) { // HH12 if (p + 3 < e && p[2] == '1' && p[3] == '2') { buffer.appendInteger2(hour % 12); p += 3; } // HH24 else if (p + 3 < e && p[2] == '2' && p[3] == '4') { buffer.appendInteger2(hour); p += 3; } // HH else { buffer.appendInteger2(hour); p += 1; } continue; } } // ............................................................................. // SS, SSSSS // ............................................................................. if (p[0] == 'S' || p[0] == 's') { if (p + 1 < e && (p[1] == 'S' || p[1] == 's')) { // SSSSSS if (p + 4 < e && (p[2] == 'S' || p[2] == 's') && (p[3] == 'S' || p[3] == 's') && (p[4] == 'S' || p[4] == 's')) { buffer.appendInteger(hour * 3600 + minute * 60 + second); p += 4; } // SS else { buffer.appendInteger2(second); } continue; } } // ............................................................................. // something else // ............................................................................. buffer.appendChar(*p); } string result = buffer.c_str(); return result; } // ............................................................................. // UTF8 // ............................................................................. // this function takes a sequence of hexadecimal characters (inputStr) of a particular // length (len) and output 1,2,3 or 4 characters which represents the utf8 encoding // of the unicode representation of that character. bool unicodeToUTF8 (const char* inputStr, const size_t& len, string& outputStr) { uint32_t outputInt = 0; bool ok; ok = parseHexanumber(inputStr, len, &outputInt); if (ok == false) { outputStr = string(inputStr, len); return false; } ok = isHighSurrugate(outputInt) || isLowSurrugate(outputInt); if (ok == true) { outputStr.append("?"); return false; } ok = toUtf8(outputInt, outputStr); if (ok == false) { outputStr = string(inputStr, len); } return ok; } // ............................................................................. // UTF16 // ............................................................................. // this function converts unicode symbols whose code points lies in U+10000 to U+10FFFF // // the parameters of the function correspond to the UTF16 description for // the code points mentioned above // // high_surrogate is the high surrogate bytes sequence, valid values begin with D[89AB] // low_surrogate is the low surrogate bytes sequence, valid values begin with D[CDEF] // for details see: http://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B10000_to_U.2B10FFFF // bool convertUTF16ToUTF8 (const char* high_surrogate, const char* low_surrogate, string& outputStr) { uint32_t w1 = 0; uint32_t w2 = 0; uint32_t v; bool ok = true; ok = ok && parseHexanumber(high_surrogate, 4, &w1); ok = ok && parseHexanumber(low_surrogate, 4, &w2); if (ok == false) { return false; } ok = isHighSurrugate(w1) && isLowSurrugate(w2); ok = ok && toUnicode(w1, w2, &v); if (ok == true) { toUtf8(v, outputStr); } return ok; } // ............................................................................. // BASE64 // ............................................................................. string encodeBase64 (string const& in) { unsigned char charArray3[3]; unsigned char charArray4[4]; string ret; int i = 0; unsigned char const* bytesToEncode = reinterpret_cast(in.c_str()); size_t in_len = in.size(); while (in_len--) { charArray3[i++] = *(bytesToEncode++); if (i == 3) { charArray4[0] = (charArray3[0] & 0xfc) >> 2; charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4); charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6); charArray4[3] = charArray3[2] & 0x3f; for (i = 0; i < 4; i++) { ret += BASE64_CHARS[charArray4[i]]; } i = 0; } } if (i != 0) { for(int j = i; j < 3; j++) { charArray3[j] = '\0'; } charArray4[0] = (charArray3[0] & 0xfc) >> 2; charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4); charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6); charArray4[3] = charArray3[2] & 0x3f; for (int j = 0; (j < i + 1); j++) { ret += BASE64_CHARS[charArray4[j]]; } while ((i++ < 3)) { ret += '='; } } return ret; } string decodeBase64 (string const& source) { unsigned char charArray4[4]; unsigned char charArray3[3]; string ret; int i = 0; int inp = 0; int in_len = (int) source.size(); while (in_len-- && (source[inp] != '=') && isBase64(source[inp])) { charArray4[i++] = source[inp]; inp++; if (i ==4) { for (i = 0; i < 4; i++) { charArray4[i] = BASE64_REVS[charArray4[i]]; } charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; for (i = 0; (i < 3); i++) { ret += charArray3[i]; } i = 0; } } if (i) { for (int j = i; j < 4; j++) { charArray4[j] = 0; } for (int j = 0; j < 4; j++) { charArray4[j] = BASE64_REVS[charArray4[j]]; } charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; for (int j = 0; j < i - 1; j++) { ret += charArray3[j]; } } return ret; } string encodeBase64U (string const& in) { unsigned char charArray3[3]; unsigned char charArray4[4]; string ret; int i = 0; unsigned char const* bytesToEncode = reinterpret_cast(in.c_str()); size_t in_len = in.size(); while (in_len--) { charArray3[i++] = *(bytesToEncode++); if (i == 3) { charArray4[0] = (charArray3[0] & 0xfc) >> 2; charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4); charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6); charArray4[3] = charArray3[2] & 0x3f; for (i = 0; i < 4; i++) { ret += BASE64U_CHARS[charArray4[i]]; } i = 0; } } if (i != 0) { for(size_t j = i; j < 3; j++) { charArray3[j] = '\0'; } charArray4[0] = (charArray3[0] & 0xfc) >> 2; charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4); charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6); charArray4[3] = charArray3[2] & 0x3f; for (int j = 0; (j < i + 1); j++) { ret += BASE64U_CHARS[charArray4[j]]; } while ((i++ < 3)) { ret += '='; } } return ret; } string decodeBase64U (string const& source) { unsigned char charArray4[4]; unsigned char charArray3[3]; string ret; int i = 0; int inp = 0; int in_len = (int) source.size(); while (in_len-- && (source[inp] != '=') && isBase64U(source[inp])) { charArray4[i++] = source[inp]; inp++; if (i ==4) { for (i = 0; i < 4; i++) { charArray4[i] = BASE64U_REVS[charArray4[i]]; } charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; for (i = 0; (i < 3); i++) { ret += charArray3[i]; } i = 0; } } if (i) { for (size_t j = i; j < 4; j++) { charArray4[j] = 0; } for (size_t j = 0; j < 4; j++) { charArray4[j] = BASE64U_REVS[charArray4[j]]; } charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; for (int j = 0; j < i - 1; j++) { ret += charArray3[j]; } } return ret; } // ............................................................................. // ADDITIONAL STRING UTILITIES // ............................................................................. string correctPath (const string& incorrectPath) { #ifdef _WIN32 return replace (incorrectPath, "/", "\\"); #else return replace (incorrectPath, "\\", "/"); #endif } // In a list str = "xx,yy,zz ...", entry(n,str,',') returns the nth entry of the list delimited // by ','. E.g entry(2,str,',') = 'yy' string entry (const size_t pos, string const& sourceStr, string const& delimiter) { size_t delLength = delimiter.length(); size_t sourceLength = sourceStr.length(); if (pos == 0) { return ""; } if (delLength == 0 || sourceLength == 0) { return sourceStr; } size_t k = 0; size_t offSet = 0; while (true) { size_t delPos = sourceStr.find(delimiter, offSet); if ((delPos == sourceStr.npos) || (delPos >= sourceLength) || (offSet >= sourceLength)) { return sourceStr.substr(offSet); } ++k; if (k == pos) { return sourceStr.substr(offSet, delPos - offSet); } offSet = delPos + delLength; } return sourceStr; } /// Determines the number of entries in a list str = "xx,yyy,zz,www". /// numEntries(str,',') = 4. size_t numEntries (string const& sourceStr, string const& delimiter) { size_t delLength = delimiter.length(); size_t sourceLength = sourceStr.length(); if (sourceLength == 0) { return (0); } if (delLength == 0) { return (1); } size_t k = 1; for (size_t j = 0; j < sourceLength; ++j) { bool match = true; for (size_t i = 0; i < delLength; ++i) { if (sourceStr[j + i] != delimiter[i]) { match = false; break; } } if (match) { j += (delLength - 1); ++k; continue; } } return k; } string encodeHex (string const& str) { char* tmp; size_t len; tmp = TRI_EncodeHexString(str.c_str(), str.length(), &len); string result = string(tmp, len); TRI_FreeString(TRI_CORE_MEM_ZONE, tmp); return result; } string decodeHex (string const& str) { char* tmp; size_t len; tmp = TRI_DecodeHexString(str.c_str(), str.length(), &len); string result = string(tmp, len); TRI_FreeString(TRI_CORE_MEM_ZONE, tmp); return result; } } } } // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- // Local Variables: // mode: outline-minor // outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}" // End: