/************************************************************************************************* * Utility functions * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Cabinet. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * 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. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KCUTIL_H // duplication check #define _KCUTIL_H #include namespace kyotocabinet { // common namespace /** The maximum value of int8_t. */ const int8_t INT8MAX = (std::numeric_limits::max)(); /** The maximum value of int16_t. */ const int16_t INT16MAX = (std::numeric_limits::max)(); /** The maximum value of int32_t. */ const int32_t INT32MAX = (std::numeric_limits::max)(); /** The maximum value of int64_t. */ const int64_t INT64MAX = (std::numeric_limits::max)(); /** The minimum value of int8_t. */ const int8_t INT8MIN = (std::numeric_limits::min)(); /** The minimum value of int16_t. */ const int16_t INT16MIN = (std::numeric_limits::min)(); /** The minimum value of int32_t. */ const int32_t INT32MIN = (std::numeric_limits::min)(); /** The minimum value of int64_t. */ const int64_t INT64MIN = (std::numeric_limits::min)(); /** The maximum value of uint8_t. */ const uint8_t UINT8MAX = (std::numeric_limits::max)(); /** The maximum value of uint16_t. */ const uint16_t UINT16MAX = (std::numeric_limits::max)(); /** The maximum value of uint32_t. */ const uint32_t UINT32MAX = (std::numeric_limits::max)(); /** The maximum value of uint64_t. */ const uint64_t UINT64MAX = (std::numeric_limits::max)(); /** The maximum value of size_t. */ const size_t SIZEMAX = (std::numeric_limits::max)(); /** The maximum value of float. */ const float FLTMAX = (std::numeric_limits::max)(); /** The maximum value of double. */ const double DBLMAX = (std::numeric_limits::max)(); /** An alias of hash map of strings. */ typedef std::unordered_map StringHashMap; /** An alias of tree map of strings. */ typedef std::map StringTreeMap; /** The package version. */ extern const char* const VERSION; /** The library version. */ extern const int32_t LIBVER; /** The library revision. */ extern const int32_t LIBREV; /** The database format version. */ extern const int32_t FMTVER; /** The system name. */ extern const char* const OSNAME; /** The flag for big endian environments. */ extern const bool BIGEND; /** The clock tick of interruption. */ extern const int32_t CLOCKTICK; /** The size of a page. */ extern const int32_t PAGESIZ; /** The extra feature list. */ extern const char* const FEATURES; /** The buffer size for numeric data. */ const size_t NUMBUFSIZ = 32; /** The maximum memory size for debugging. */ const size_t MEMMAXSIZ = INT32MAX / 2; /** * Convert a decimal string to an integer. * @param str the decimal string. * @return the integer. If the string does not contain numeric expression, 0 is returned. */ int64_t atoi(const char* str); /** * Convert a decimal string with a metric prefix to an integer. * @param str the decimal string, which can be trailed by a binary metric prefix. "K", "M", "G", * "T", "P", and "E" are supported. They are case-insensitive. * @return the integer. If the string does not contain numeric expression, 0 is returned. If * the integer overflows the domain, kyotocabinet::INT64MAX or kyotocabinet::INT64_MIN is * returned according to the sign. */ int64_t atoix(const char* str); /** * Convert a hexadecimal string to an integer. * @param str the hexadecimal string. * @return the integer. If the string does not contain numeric expression, 0 is returned. */ int64_t atoih(const char* str); /** * Convert a decimal byte array to an integer. * @param ptr the decimal byte array. * @param size the size of the decimal byte array. * @return the integer. If the string does not contain numeric expression, 0 is returned. */ int64_t atoin(const char* ptr, size_t size); /** * Convert a decimal string to a real number. * @param str the decimal string. * @return the real number. If the string does not contain numeric expression, 0.0 is returned. */ double atof(const char* str); /** * Convert a decimal byte array to a real number. * @param ptr the decimal byte array. * @param size the size of the decimal byte array. * @return the real number. If the string does not contain numeric expression, 0.0 is returned. */ double atofn(const char* ptr, size_t size); /** * Normalize a 16-bit number in the native order into the network byte order. * @param num the 16-bit number in the native order. * @return the number in the network byte order. */ uint16_t hton16(uint16_t num); /** * Normalize a 32-bit number in the native order into the network byte order. * @param num the 32-bit number in the native order. * @return the number in the network byte order. */ uint32_t hton32(uint32_t num); /** * Normalize a 64-bit number in the native order into the network byte order. * @param num the 64-bit number in the native order. * @return the number in the network byte order. */ uint64_t hton64(uint64_t num); /** * Denormalize a 16-bit number in the network byte order into the native order. * @param num the 16-bit number in the network byte order. * @return the converted number in the native order. */ uint16_t ntoh16(uint16_t num); /** * Denormalize a 32-bit number in the network byte order into the native order. * @param num the 32-bit number in the network byte order. * @return the converted number in the native order. */ uint32_t ntoh32(uint32_t num); /** * Denormalize a 64-bit number in the network byte order into the native order. * @param num the 64-bit number in the network byte order. * @return the converted number in the native order. */ uint64_t ntoh64(uint64_t num); /** * Write a number in fixed length format into a buffer. * @param buf the desitination buffer. * @param num the number. * @param width the width. */ void writefixnum(void* buf, uint64_t num, size_t width); /** * Read a number in fixed length format from a buffer. * @param buf the source buffer. * @param width the width. * @return the read number. */ uint64_t readfixnum(const void* buf, size_t width); /** * Write a number in variable length format into a buffer. * @param buf the desitination buffer. * @param num the number. * @return the length of the written region. */ size_t writevarnum(void* buf, uint64_t num); /** * Read a number in variable length format from a buffer. * @param buf the source buffer. * @param size the size of the source buffer. * @param np the pointer to the variable into which the read number is assigned. * @return the length of the read region, or 0 on failure. */ size_t readvarnum(const void* buf, size_t size, uint64_t* np); /** * Check the size of variable length format of a number. * @return the size of variable length format. */ size_t sizevarnum(uint64_t num); /** * Get the hash value by MurMur hashing. * @param buf the source buffer. * @param size the size of the source buffer. * @return the hash value. */ uint64_t hashmurmur(const void* buf, size_t size); /** * Get the hash value by FNV hashing. * @param buf the source buffer. * @param size the size of the source buffer. * @return the hash value. */ uint64_t hashfnv(const void* buf, size_t size); /** * Get the hash value suitable for a file name. * @param buf the source buffer. * @param size the size of the source buffer. * @param obuf the buffer into which the result hash string is written. It must be more than * NUMBUFSIZ. * @return the auxiliary hash value. */ uint32_t hashpath(const void* buf, size_t size, char* obuf); /** * Get a prime number nearby a number. * @param num a natural number. * @return the result number. */ uint64_t nearbyprime(uint64_t num); /** * Get the quiet Not-a-Number value. * @return the quiet Not-a-Number value. */ double nan(); /** * Get the positive infinity value. * @return the positive infinity value. */ double inf(); /** * Check a number is a Not-a-Number value. * @return true for the number is a Not-a-Number value, or false if not. */ bool chknan(double num); /** * Check a number is an infinity value. * @return true for the number is an infinity value, or false if not. */ bool chkinf(double num); /** * Append a formatted string at the end of a string. * @param dest the destination string. * @param format the printf-like format string. The conversion character `%' can be used with * such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `%'. * @param ap used according to the format string. */ void vstrprintf(std::string* dest, const char* format, va_list ap); /** * Append a formatted string at the end of a string. * @param dest the destination string. * @param format the printf-like format string. The conversion character `%' can be used with * such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `%'. * @param ... used according to the format string. */ void strprintf(std::string* dest, const char* format, ...); /** * Generate a formatted string. * @param format the printf-like format string. The conversion character `%' can be used with * such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `%'. * @param ... used according to the format string. * @return the result string. */ std::string strprintf(const char* format, ...); /** * Split a string with a delimiter. * @param str the string. * @param delim the delimiter. * @param elems a vector object into which the result elements are pushed. * @return the number of result elements. */ size_t strsplit(const std::string& str, char delim, std::vector* elems); /** * Split a string with delimiters. * @param str the string. * @param delims the delimiters. * @param elems a vector object into which the result elements are pushed. * @return the number of result elements. */ size_t strsplit(const std::string& str, const std::string& delims, std::vector* elems); /** * Convert the letters of a string into upper case. * @param str the string to convert. * @return the string itself. */ std::string* strtoupper(std::string* str); /** * Convert the letters of a string into lower case. * @param str the string to convert. * @return the string itself. */ std::string* strtolower(std::string* str); /** * Check whether a string begins with a key. * @param str the string. * @param key the forward matching key string. * @return true if the target string begins with the key, else, it is false. */ bool strfwm(const std::string& str, const std::string& key); /** * Check whether a string ends with a key. * @param str the string. * @param key the backward matching key string. * @return true if the target string ends with the key, else, it is false. */ bool strbwm(const std::string& str, const std::string& key); /** * Cut space characters at head or tail of a string. * @param str the string to convert. * @return the string itself. */ std::string* strtrim(std::string* str); /** * Convert a UTF-8 string into a UCS-4 array. * @param src the source object. * @param dest the destination object. */ void strutftoucs(const std::string& src, std::vector* dest); /** * Convert a UCS-4 array into a UTF-8 string. * @param src the source object. * @param dest the destination object. */ void strucstoutf(const std::vector& src, std::string* dest); /** * Serialize a string vector object into a string object. * @param src the source object. * @param dest the destination object. */ void strvecdump(const std::vector& src, std::string* dest); /** * Deserialize a string object into a string vector object. * @param src the source object. * @param dest the destination object. */ void strvecload(const std::string& src, std::vector* dest); /** * Serialize a string vector object into a string object. * @param src the source object. * @param dest the destination object. */ void strmapdump(const std::map& src, std::string* dest); /** * Deserialize a string object into a string map object. * @param src the source object. * @param dest the destination object. */ void strmapload(const std::string& src, std::map* dest); /** * Encode a serial object by hexadecimal encoding. * @param buf the pointer to the region. * @param size the size of the region. * @return the result string. * @note Because the region of the return value is allocated with the the new[] operator, it * should be released with the delete[] operator when it is no longer in use. */ char* hexencode(const void* buf, size_t size); /** * Decode a string encoded by hexadecimal encoding. * @param str specifies the encoded string. * @param sp the pointer to the variable into which the size of the region of the return value * is assigned. * @return the pointer to the region of the result. * @note Because an additional zero code is appended at the end of the region of the return * value, the return value can be treated as a character string. Because the region of the * return value is allocated with the the new[] operator, it should be released with the delete[] * operator when it is no longer in use. */ char* hexdecode(const char* str, size_t* sp); /** * Encode a serial object by URL encoding. * @param buf the pointer to the region. * @param size the size of the region. * @return the result string. * @note Because the region of the return value is allocated with the the new[] operator, it * should be released with the delete[] operator when it is no longer in use. */ char* urlencode(const void* buf, size_t size); /** * Decode a string encoded by URL encoding. * @param str specifies the encoded string. * @param sp the pointer to the variable into which the size of the region of the return value * is assigned. * @return the pointer to the region of the result. * @note Because an additional zero code is appended at the end of the region of the return * value, the return value can be treated as a character string. Because the region of the * return value is allocated with the the new[] operator, it should be released with the delete[] * operator when it is no longer in use. */ char* urldecode(const char* str, size_t* sp); /** * Encode a serial object by Quoted-printable encoding. * @param buf the pointer to the region. * @param size the size of the region. * @return the result string. * @note Because the region of the return value is allocated with the the new[] operator, it * should be released with the delete[] operator when it is no longer in use. */ char* quoteencode(const void* buf, size_t size); /** * Decode a string encoded by Quoted-printable encoding. * @param str specifies the encoded string. * @param sp the pointer to the variable into which the size of the region of the return value * is assigned. * @return the pointer to the region of the result. * @note Because an additional zero code is appended at the end of the region of the return * value, the return value can be treated as a character string. Because the region of the * return value is allocated with the the new[] operator, it should be released with the delete[] * operator when it is no longer in use. */ char* quotedecode(const char* str, size_t* sp); /** * Encode a serial object by Base64 encoding. * @param buf the pointer to the region. * @param size the size of the region. * @return the result string. * @note Because the region of the return value is allocated with the the new[] operator, it * should be released with the delete[] operator when it is no longer in use. */ char* baseencode(const void* buf, size_t size); /** * Decode a string encoded by Base64 encoding. * @param str specifies the encoded string. * @param sp the pointer to the variable into which the size of the region of the return value * is assigned. * @return the pointer to the region of the result. * @note Because an additional zero code is appended at the end of the region of the return * value, the return value can be treated as a character string. Because the region of the * return value is allocated with the the new[] operator, it should be released with the delete[] * operator when it is no longer in use. */ char* basedecode(const char* str, size_t* sp); /** * Cipher or decipher a serial object with the Arcfour stream cipher. * @param ptr the pointer to the region. * @param size the size of the region. * @param kbuf the pointer to the region of the cipher key. * @param ksiz the size of the region of the cipher key. * @param obuf the pointer to the region into which the result data is written. The size of the * buffer should be equal to or more than the input region. The region can be the same as the * source region. */ void arccipher(const void* ptr, size_t size, const void* kbuf, size_t ksiz, void* obuf); /** * Duplicate a region on memory. * @param ptr the source buffer. * @param size the size of the source buffer. * @note Because the region of the return value is allocated with the the new[] operator, it * should be released with the delete[] operator when it is no longer in use. */ char* memdup(const char* ptr, size_t size); /** * Compare two regions by case insensitive evaluation. * @param abuf a buffer. * @param bbuf the other buffer. * @param size the size of each buffer. * @return positive if the former is big, negative if the latter is big, 0 if both are * equivalent. */ int32_t memicmp(const void* abuf, const void* bbuf, size_t size); /** * Find the first occurrence of a sub pattern. * @param hbuf the target pattern buffer. * @param hsiz the size of the target pattern buffer. * @param nbuf the sub pattern buffer. * @param nsiz the size of the sub pattern buffer. * @return the pointer to the beginning of the sub pattern in the target pattern buffer, or NULL * if the sub pattern is not found. */ void* memmem(const void* hbuf, size_t hsiz, const void* nbuf, size_t nsiz); /** * Find the first occurrence of a sub pattern by case insensitive evaluation. * @param hbuf the target pattern buffer. * @param hsiz the size of the target pattern buffer. * @param nbuf the sub pattern buffer. * @param nsiz the size of the sub pattern buffer. * @return the pointer to the beginning of the sub pattern in the target pattern buffer, or NULL * if the sub pattern is not found. */ void* memimem(const void* hbuf, size_t hsiz, const void* nbuf, size_t nsiz); /** * Calculate the levenshtein distance of two regions in bytes. * @param abuf the pointer to the region of one buffer. * @param asiz the size of the region of one buffer. * @param bbuf the pointer to the region of the other buffer. * @param bsiz the size of the region of the other buffer. * @return the levenshtein distance of two regions. */ size_t memdist(const void* abuf, size_t asiz, const void* bbuf, size_t bsiz); /** * Duplicate a string on memory. * @param str the source string. * @note Because the region of the return value is allocated with the the new[] operator, it * should be released with the delete[] operator when it is no longer in use. */ char* strdup(const char* str); /** * Convert the letters of a string into upper case. * @param str the string to convert. * @return the string itself. */ char* strtoupper(char* str); /** * Convert the letters of a string into lower case. * @param str the string to convert. * @return the string itself. */ char* strtolower(char* str); /** * Cut space characters at head or tail of a string. * @param str the string to convert. * @return the string itself. */ char* strtrim(char* str); /** * Squeeze space characters in a string and trim it. * @param str the string to convert. * @return the string itself. */ char* strsqzspc(char* str); /** * Normalize space characters in a string and trim it. * @param str the string to convert. * @return the string itself. */ char* strnrmspc(char* str); /** * Compare two strings by case insensitive evaluation. * @param astr a string. * @param bstr the other string. * @return positive if the former is big, negative if the latter is big, 0 if both are * equivalent. */ int32_t stricmp(const char* astr, const char* bstr); /** * Find the first occurrence of a substring by case insensitive evaluation. * @param hstr the target string. * @param nstr the substring. * @return the pointer to the beginning of the substring in the target string, or NULL if the * substring is not found. */ char* stristr(const char* hstr, const char* nstr); /** * Check whether a string begins with a key. * @param str the string. * @param key the forward matching key string. * @return true if the target string begins with the key, else, it is false. */ bool strfwm(const char* str, const char* key); /** * Check whether a string begins with a key by case insensitive evaluation. * @param str the string. * @param key the forward matching key string. * @return true if the target string begins with the key, else, it is false. */ bool strifwm(const char* str, const char* key); /** * Check whether a string ends with a key. * @param str the string. * @param key the backward matching key string. * @return true if the target string ends with the key, else, it is false. */ bool strbwm(const char* str, const char* key); /** * Check whether a string ends with a key by case insensitive evaluation. * @param str the string. * @param key the backward matching key string. * @return true if the target string ends with the key, else, it is false. */ bool stribwm(const char* str, const char* key); /** * Get the number of characters in a UTF-8 string. * @param str the UTF-8 string. * @return the number of characters in the string. */ size_t strutflen(const char* str); /** * Convert a UTF-8 string into a UCS-4 array. * @param src the source object. * @param dest the destination object. It must have enough size. * @param np the pointer to the variable into which the number of elements in the destination * object is assgined. */ void strutftoucs(const char* src, uint32_t* dest, size_t* np); /** * Convert a UTF-8 string into a UCS-4 array. * @param src the source object which does not have to be trailed by zero code. * @param slen the length of the source object. * @param dest the destination object. It must have enough size. * @param np the pointer to the variable into which the number of elements in the destination * object is assgined. */ void strutftoucs(const char* src, size_t slen, uint32_t* dest, size_t* np); /** * Convert a UCS-4 array into a UTF-8 string. * @param src the source object. * @param snum the number of elements in the source object. * @param dest the destination object. It must have enough size. * @return the size of the result string. */ size_t strucstoutf(const uint32_t* src, size_t snum, char* dest); /** * Calculate the levenshtein distance of two UTF-8 strings. * @param astr one UTF-8 string. * @param bstr the other UTF-8 string. * @return the levenshtein distance of two arrays. */ size_t strutfdist(const char* astr, const char* bstr); /** * Calculate the levenshtein distance of two UCS-4 arrays. * @param aary one UCS-4 array. * @param anum the number of elements of one array. * @param bary the other UCS-4 array. * @param bnum the number of elements of the other array. * @return the levenshtein distance of two arrays. */ size_t strucsdist(const uint32_t* aary, size_t anum, const uint32_t* bary, size_t bnum); /** * Allocate a region on memory. * @param size the size of the region. * @return the pointer to the allocated region. */ void* xmalloc(size_t size); /** * Allocate a nullified region on memory. * @param nmemb the number of elements. * @param size the size of each element. * @return the pointer to the allocated region. */ void* xcalloc(size_t nmemb, size_t size); /** * Re-allocate a region on memory. * @param ptr the pointer to the region. * @param size the size of the region. * @return the pointer to the re-allocated region. */ void* xrealloc(void* ptr, size_t size); /** * Free a region on memory. * @param ptr the pointer to the region. */ void xfree(void* ptr); /** * Allocate a nullified region on mapped memory. * @param size the size of the region. * @return the pointer to the allocated region. It should be released with the memfree call. */ void* mapalloc(size_t size); /** * Free a region on mapped memory. * @param ptr the pointer to the allocated region. */ void mapfree(void* ptr); /** * Get the time of day in seconds. * @return the time of day in seconds. The accuracy is in microseconds. */ double time(); /** * Get the process ID. * @return the process ID. */ int64_t getpid(); /** * Get the value of an environment variable. * @return the value of the environment variable, or NULL on failure. */ const char* getenv(const char* name); /** * Get system information of the environment. * @param strmap a string map to contain the result. */ void getsysinfo(std::map* strmap); /** * Set the standard streams into the binary mode. */ void setstdiobin(); /** * Dummy test driver. * @return always true. */ bool _dummytest(); /** * Convert a decimal string to an integer. */ inline int64_t atoi(const char* str) { _assert_(str); while (*str > '\0' && *str <= ' ') { str++; } int32_t sign = 1; int64_t num = 0; if (*str == '-') { str++; sign = -1; } else if (*str == '+') { str++; } while (*str != '\0') { if (*str < '0' || *str > '9') break; num = num * 10 + *str - '0'; str++; } return num * sign; } /** * Convert a decimal string with a metric prefix to an integer. */ inline int64_t atoix(const char* str) { _assert_(str); while (*str > '\0' && *str <= ' ') { str++; } int32_t sign = 1; if (*str == '-') { str++; sign = -1; } else if (*str == '+') { str++; } long double num = 0; while (*str != '\0') { if (*str < '0' || *str > '9') break; num = num * 10 + *str - '0'; str++; } if (*str == '.') { str++; long double base = 10; while (*str != '\0') { if (*str < '0' || *str > '9') break; num += (*str - '0') / base; str++; base *= 10; } } num *= sign; while (*str > '\0' && *str <= ' ') { str++; } if (*str == 'k' || *str == 'K') { num *= 1LL << 10; } else if (*str == 'm' || *str == 'M') { num *= 1LL << 20; } else if (*str == 'g' || *str == 'G') { num *= 1LL << 30; } else if (*str == 't' || *str == 'T') { num *= 1LL << 40; } else if (*str == 'p' || *str == 'P') { num *= 1LL << 50; } else if (*str == 'e' || *str == 'E') { num *= 1LL << 60; } if (num > INT64MAX) return INT64MAX; if (num < INT64MIN) return INT64MIN; return (int64_t)num; } /** * Convert a hexadecimal string to an integer. */ inline int64_t atoih(const char* str) { _assert_(str); while (*str > '\0' && *str <= ' ') { str++; } if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { str += 2; } int64_t num = 0; while (true) { if (*str >= '0' && *str <= '9') { num = num * 0x10 + *str - '0'; } else if (*str >= 'a' && *str <= 'f') { num = num * 0x10 + *str - 'a' + 10; } else if (*str >= 'A' && *str <= 'F') { num = num * 0x10 + *str - 'A' + 10; } else { break; } str++; } return num; } /** * Convert a decimal byte array to an integer. */ inline int64_t atoin(const char* ptr, size_t size) { _assert_(ptr && size <= MEMMAXSIZ); while (size > 0 && *ptr >= '\0' && *ptr <= ' ') { ptr++; size--; } int32_t sign = 1; int64_t num = 0; if (size > 0) { if (*ptr == '-') { ptr++; size--; sign = -1; } else if (*ptr == '+') { ptr++; size--; } } while (size > 0) { if (*ptr < '0' || *ptr > '9') break; num = num * 10 + *ptr - '0'; ptr++; size--; } return num * sign; } /** * Convert a decimal string to a real number. */ inline double atof(const char* str) { _assert_(str); while (*str > '\0' && *str <= ' ') { str++; } int32_t sign = 1; if (*str == '-') { str++; sign = -1; } else if (*str == '+') { str++; } if ((str[0] == 'i' || str[0] == 'I') && (str[1] == 'n' || str[1] == 'N') && (str[2] == 'f' || str[2] == 'F')) return HUGE_VAL * sign; if ((str[0] == 'n' || str[0] == 'N') && (str[1] == 'a' || str[1] == 'A') && (str[2] == 'n' || str[2] == 'N')) return nan(); long double num = 0; int32_t col = 0; while (*str != '\0') { if (*str < '0' || *str > '9') break; num = num * 10 + *str - '0'; str++; if (num > 0) col++; } if (*str == '.') { str++; long double fract = 0.0; long double base = 10; while (col < 16 && *str != '\0') { if (*str < '0' || *str > '9') break; fract += (*str - '0') / base; str++; col++; base *= 10; } num += fract; } if (*str == 'e' || *str == 'E') { str++; num *= std::pow((long double)10, (long double)atoi(str)); } return num * sign; } /** * Convert a decimal byte array to a real number. */ inline double atofn(const char* ptr, size_t size) { _assert_(ptr && size <= MEMMAXSIZ); while (size > 0 && *ptr >= '\0' && *ptr <= ' ') { ptr++; size--; } int32_t sign = 1; if (size > 0) { if (*ptr == '-') { ptr++; size--; sign = -1; } else if (*ptr == '+') { ptr++; size--; } } if (size > 2) { if ((ptr[0] == 'i' || ptr[0] == 'I') && (ptr[1] == 'n' || ptr[1] == 'N') && (ptr[2] == 'f' || ptr[2] == 'F')) return HUGE_VAL * sign; if ((ptr[0] == 'n' || ptr[0] == 'N') && (ptr[1] == 'a' || ptr[1] == 'A') && (ptr[2] == 'n' || ptr[2] == 'N')) return nan(); } long double num = 0; int32_t col = 0; while (size > 0) { if (*ptr < '0' || *ptr > '9') break; num = num * 10 + *ptr - '0'; ptr++; size--; if (num > 0) col++; } if (size > 0 && *ptr == '.') { ptr++; size--; long double fract = 0.0; long double base = 10; while (col < 16 && size > 0) { if (*ptr < '0' || *ptr > '9') break; fract += (*ptr - '0') / base; ptr++; size--; col++; base *= 10; } num += fract; } if (size > 0 && (*ptr == 'e' || *ptr == 'E')) { ptr++; size--; num *= std::pow((long double)10, (long double)atoin(ptr, size)); } return num * sign; } /** * Normalize a 16-bit number in the native order into the network byte order. */ inline uint16_t hton16(uint16_t num) { _assert_(true); if (BIGEND) return num; return ((num & 0x00ffU) << 8) | ((num & 0xff00U) >> 8); } /** * Normalize a 32-bit number in the native order into the network byte order. */ inline uint32_t hton32(uint32_t num) { _assert_(true); if (BIGEND) return num; return ((num & 0x000000ffUL) << 24) | ((num & 0x0000ff00UL) << 8) | \ ((num & 0x00ff0000UL) >> 8) | ((num & 0xff000000UL) >> 24); } /** * Normalize a 64-bit number in the native order into the network byte order. */ inline uint64_t hton64(uint64_t num) { _assert_(true); if (BIGEND) return num; return ((num & 0x00000000000000ffULL) << 56) | ((num & 0x000000000000ff00ULL) << 40) | ((num & 0x0000000000ff0000ULL) << 24) | ((num & 0x00000000ff000000ULL) << 8) | ((num & 0x000000ff00000000ULL) >> 8) | ((num & 0x0000ff0000000000ULL) >> 24) | ((num & 0x00ff000000000000ULL) >> 40) | ((num & 0xff00000000000000ULL) >> 56); } /** * Denormalize a 16-bit number in the network byte order into the native order. */ inline uint16_t ntoh16(uint16_t num) { _assert_(true); return hton16(num); } /** * Denormalize a 32-bit number in the network byte order into the native order. */ inline uint32_t ntoh32(uint32_t num) { _assert_(true); return hton32(num); } /** * Denormalize a 64-bit number in the network byte order into the native order. */ inline uint64_t ntoh64(uint64_t num) { _assert_(true); return hton64(num); } /** * Write a number in fixed length format into a buffer. */ inline void writefixnum(void* buf, uint64_t num, size_t width) { _assert_(buf && width <= sizeof(int64_t)); num = hton64(num); std::memcpy(buf, (const char*)&num + sizeof(num) - width, width); } /** * Read a number in fixed length format from a buffer. */ inline uint64_t readfixnum(const void* buf, size_t width) { _assert_(buf && width <= sizeof(int64_t)); uint64_t num = 0; std::memcpy(&num, buf, width); return ntoh64(num) >> ((sizeof(num) - width) * 8); } /** * Write a number in variable length format into a buffer. */ inline size_t writevarnum(void* buf, uint64_t num) { _assert_(buf); unsigned char* wp = (unsigned char*)buf; if (num < (1ULL << 7)) { *(wp++) = num; } else if (num < (1ULL << 14)) { *(wp++) = (num >> 7) | 0x80; *(wp++) = num & 0x7f; } else if (num < (1ULL << 21)) { *(wp++) = (num >> 14) | 0x80; *(wp++) = ((num >> 7) & 0x7f) | 0x80; *(wp++) = num & 0x7f; } else if (num < (1ULL << 28)) { *(wp++) = (num >> 21) | 0x80; *(wp++) = ((num >> 14) & 0x7f) | 0x80; *(wp++) = ((num >> 7) & 0x7f) | 0x80; *(wp++) = num & 0x7f; } else if (num < (1ULL << 35)) { *(wp++) = (num >> 28) | 0x80; *(wp++) = ((num >> 21) & 0x7f) | 0x80; *(wp++) = ((num >> 14) & 0x7f) | 0x80; *(wp++) = ((num >> 7) & 0x7f) | 0x80; *(wp++) = num & 0x7f; } else if (num < (1ULL << 42)) { *(wp++) = (num >> 35) | 0x80; *(wp++) = ((num >> 28) & 0x7f) | 0x80; *(wp++) = ((num >> 21) & 0x7f) | 0x80; *(wp++) = ((num >> 14) & 0x7f) | 0x80; *(wp++) = ((num >> 7) & 0x7f) | 0x80; *(wp++) = num & 0x7f; } else if (num < (1ULL << 49)) { *(wp++) = (num >> 42) | 0x80; *(wp++) = ((num >> 35) & 0x7f) | 0x80; *(wp++) = ((num >> 28) & 0x7f) | 0x80; *(wp++) = ((num >> 21) & 0x7f) | 0x80; *(wp++) = ((num >> 14) & 0x7f) | 0x80; *(wp++) = ((num >> 7) & 0x7f) | 0x80; *(wp++) = num & 0x7f; } else if (num < (1ULL << 56)) { *(wp++) = (num >> 49) | 0x80; *(wp++) = ((num >> 42) & 0x7f) | 0x80; *(wp++) = ((num >> 35) & 0x7f) | 0x80; *(wp++) = ((num >> 28) & 0x7f) | 0x80; *(wp++) = ((num >> 21) & 0x7f) | 0x80; *(wp++) = ((num >> 14) & 0x7f) | 0x80; *(wp++) = ((num >> 7) & 0x7f) | 0x80; *(wp++) = num & 0x7f; } else if (num < (1ULL << 63)) { *(wp++) = (num >> 56) | 0x80; *(wp++) = ((num >> 49) & 0x7f) | 0x80; *(wp++) = ((num >> 42) & 0x7f) | 0x80; *(wp++) = ((num >> 35) & 0x7f) | 0x80; *(wp++) = ((num >> 28) & 0x7f) | 0x80; *(wp++) = ((num >> 21) & 0x7f) | 0x80; *(wp++) = ((num >> 14) & 0x7f) | 0x80; *(wp++) = ((num >> 7) & 0x7f) | 0x80; *(wp++) = num & 0x7f; } else { *(wp++) = (num >> 63) | 0x80; *(wp++) = ((num >> 56) & 0x7f) | 0x80; *(wp++) = ((num >> 49) & 0x7f) | 0x80; *(wp++) = ((num >> 42) & 0x7f) | 0x80; *(wp++) = ((num >> 35) & 0x7f) | 0x80; *(wp++) = ((num >> 28) & 0x7f) | 0x80; *(wp++) = ((num >> 21) & 0x7f) | 0x80; *(wp++) = ((num >> 14) & 0x7f) | 0x80; *(wp++) = ((num >> 7) & 0x7f) | 0x80; *(wp++) = num & 0x7f; } return wp - (unsigned char*)buf; } /** * Read a number in variable length format from a buffer. */ inline size_t readvarnum(const void* buf, size_t size, uint64_t* np) { _assert_(buf && size <= MEMMAXSIZ && np); const unsigned char* rp = (const unsigned char*)buf; const unsigned char* ep = rp + size; uint64_t num = 0; uint32_t c; do { if (rp >= ep) { *np = 0; return 0; } c = *rp; num = (num << 7) + (c & 0x7f); rp++; } while (c >= 0x80); *np = num; return rp - (const unsigned char*)buf; } /** * Check the size of variable length format of a number. */ inline size_t sizevarnum(uint64_t num) { _assert_(true); if (num < (1ULL << 7)) return 1; if (num < (1ULL << 14)) return 2; if (num < (1ULL << 21)) return 3; if (num < (1ULL << 28)) return 4; if (num < (1ULL << 35)) return 5; if (num < (1ULL << 42)) return 6; if (num < (1ULL << 49)) return 7; if (num < (1ULL << 56)) return 8; if (num < (1ULL << 63)) return 9; return 10; } /** * Get the hash value by MurMur hashing. */ inline uint64_t hashmurmur(const void* buf, size_t size) { _assert_(buf && size <= MEMMAXSIZ); const uint64_t mul = 0xc6a4a7935bd1e995ULL; const int32_t rtt = 47; uint64_t hash = 19780211ULL ^ (size * mul); const unsigned char* rp = (const unsigned char*)buf; while (size >= sizeof(uint64_t)) { uint64_t num = ((uint64_t)rp[0] << 0) | ((uint64_t)rp[1] << 8) | ((uint64_t)rp[2] << 16) | ((uint64_t)rp[3] << 24) | ((uint64_t)rp[4] << 32) | ((uint64_t)rp[5] << 40) | ((uint64_t)rp[6] << 48) | ((uint64_t)rp[7] << 56); num *= mul; num ^= num >> rtt; num *= mul; hash *= mul; hash ^= num; rp += sizeof(uint64_t); size -= sizeof(uint64_t); } switch (size) { case 7: hash ^= (uint64_t)rp[6] << 48; case 6: hash ^= (uint64_t)rp[5] << 40; case 5: hash ^= (uint64_t)rp[4] << 32; case 4: hash ^= (uint64_t)rp[3] << 24; case 3: hash ^= (uint64_t)rp[2] << 16; case 2: hash ^= (uint64_t)rp[1] << 8; case 1: hash ^= (uint64_t)rp[0]; hash *= mul; }; hash ^= hash >> rtt; hash *= mul; hash ^= hash >> rtt; return hash; } /** * Get the hash value by FNV hashing. */ inline uint64_t hashfnv(const void* buf, size_t size) { _assert_(buf && size <= MEMMAXSIZ); uint64_t hash = 14695981039346656037ULL; const unsigned char* rp = (unsigned char*)buf; const unsigned char* ep = rp + size; while (rp < ep) { hash = (hash ^ *(rp++)) * 109951162811ULL; } return hash; } /** * Get the hash value suitable for a file name. */ inline uint32_t hashpath(const void* buf, size_t size, char* obuf) { _assert_(buf && size <= MEMMAXSIZ && obuf); const unsigned char* rp = (const unsigned char*)buf; uint32_t rv; char* wp = obuf; if (size <= 10) { if (size > 0) { const unsigned char* ep = rp + size; while (rp < ep) { int32_t num = *rp >> 4; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } num = *rp & 0x0f; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } rp++; } } else { *(wp++) = '0'; } uint64_t hash = hashmurmur(buf, size); rv = (((hash & 0xffff000000000000ULL) >> 48) | ((hash & 0x0000ffff00000000ULL) >> 16)) ^ (((hash & 0x000000000000ffffULL) << 16) | ((hash & 0x00000000ffff0000ULL) >> 16)); } else { *(wp++) = 'f' + 1 + (size & 0x0f); for (int32_t i = 0; i <= 6; i += 3) { uint32_t num = (rp[i] ^ rp[i+1] ^ rp[i+2] ^ rp[size-i-1] ^ rp[size-i-2] ^ rp[size-i-3]) % 36; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } } uint64_t hash = hashmurmur(buf, size); rv = (((hash & 0xffff000000000000ULL) >> 48) | ((hash & 0x0000ffff00000000ULL) >> 16)) ^ (((hash & 0x000000000000ffffULL) << 16) | ((hash & 0x00000000ffff0000ULL) >> 16)); uint64_t inc = hashfnv(buf, size); inc = (((inc & 0xffff000000000000ULL) >> 48) | ((inc & 0x0000ffff00000000ULL) >> 16)) ^ (((inc & 0x000000000000ffffULL) << 16) | ((inc & 0x00000000ffff0000ULL) >> 16)); for (size_t i = 0; i < sizeof(hash); i++) { uint32_t least = hash >> ((sizeof(hash) - 1) * 8); uint64_t num = least >> 4; if (inc & 0x01) num += 0x10; inc = inc >> 1; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } num = least & 0x0f; if (inc & 0x01) num += 0x10; inc = inc >> 1; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } hash = hash << 8; } } *wp = '\0'; return rv; } /** * Get a prime number nearby a number. */ inline uint64_t nearbyprime(uint64_t num) { _assert_(true); static uint64_t table[] = { 2ULL, 3ULL, 5ULL, 7ULL, 11ULL, 13ULL, 17ULL, 19ULL, 23ULL, 29ULL, 31ULL, 37ULL, 41ULL, 43ULL, 47ULL, 53ULL, 59ULL, 61ULL, 67ULL, 71ULL, 79ULL, 97ULL, 107ULL, 131ULL, 157ULL, 181ULL, 223ULL, 257ULL, 307ULL, 367ULL, 431ULL, 521ULL, 613ULL, 727ULL, 863ULL, 1031ULL, 1217ULL, 1451ULL, 1723ULL, 2053ULL, 2437ULL, 2897ULL, 3449ULL, 4099ULL, 4871ULL, 5801ULL, 6899ULL, 8209ULL, 9743ULL, 11587ULL, 13781ULL, 16411ULL, 19483ULL, 23173ULL, 27581ULL, 32771ULL, 38971ULL, 46349ULL, 55109ULL, 65537ULL, 77951ULL, 92681ULL, 110221ULL, 131101ULL, 155887ULL, 185363ULL, 220447ULL, 262147ULL, 311743ULL, 370759ULL, 440893ULL, 524309ULL, 623521ULL, 741457ULL, 881743ULL, 1048583ULL, 1246997ULL, 1482919ULL, 1763491ULL, 2097169ULL, 2493949ULL, 2965847ULL, 3526987ULL, 4194319ULL, 4987901ULL, 5931641ULL, 7053971ULL, 8388617ULL, 9975803ULL, 11863289ULL, 14107921ULL, 16777259ULL, 19951597ULL, 23726569ULL, 28215809ULL, 33554467ULL, 39903197ULL, 47453149ULL, 56431657ULL, 67108879ULL, 79806341ULL, 94906297ULL, 112863217ULL, 134217757ULL, 159612679ULL, 189812533ULL, 225726419ULL, 268435459ULL, 319225391ULL, 379625083ULL, 451452839ULL, 536870923ULL, 638450719ULL, 759250133ULL, 902905657ULL, 1073741827ULL, 1276901429ULL, 1518500279ULL, 1805811341ULL, 2147483659ULL, 2553802871ULL, 3037000507ULL, 3611622607ULL, 4294967311ULL, 5107605691ULL, 6074001001ULL, 7223245229ULL, 8589934609ULL, 10215211387ULL, 12148002047ULL, 14446490449ULL, 17179869209ULL, 20430422699ULL, 24296004011ULL, 28892980877ULL, 34359738421ULL, 40860845437ULL, 48592008053ULL, 57785961671ULL, 68719476767ULL, 81721690807ULL, 97184016049ULL, 115571923303ULL, 137438953481ULL, 163443381347ULL, 194368032011ULL, 231143846587ULL, 274877906951ULL, 326886762733ULL, 388736063999ULL, 462287693167ULL, 549755813911ULL, 653773525393ULL, 777472128049ULL, 924575386373ULL, 1099511627791ULL, 1307547050819ULL, 1554944255989ULL, 1849150772699ULL, 2199023255579ULL, 2615094101561ULL, 3109888512037ULL, 3698301545321ULL, 4398046511119ULL, 5230188203153ULL, 6219777023959ULL, 7396603090651ULL, 8796093022237ULL, 10460376406273ULL, 12439554047911ULL, 14793206181251ULL, 17592186044423ULL, 20920752812471ULL, 24879108095833ULL, 29586412362491ULL, 35184372088891ULL, 41841505624973ULL, 49758216191633ULL, 59172824724919ULL, 70368744177679ULL, 83683011249917ULL, 99516432383281ULL, 118345649449813ULL, 140737488355333ULL, 167366022499847ULL, 199032864766447ULL, 236691298899683ULL, 281474976710677ULL, 334732044999557ULL, 398065729532981ULL, 473382597799229ULL, 562949953421381ULL, 669464089999087ULL, 796131459065743ULL, 946765195598473ULL, 1125899906842679ULL, 1338928179998197ULL, 1592262918131449ULL, 1893530391196921ULL, 2251799813685269ULL, 2677856359996339ULL, 3184525836262943ULL, 3787060782393821ULL, 4503599627370517ULL, 5355712719992603ULL, 6369051672525833ULL, 7574121564787633ULL }; static const size_t tnum = sizeof(table) / sizeof(table[0]); uint64_t* ub = std::lower_bound(table, table + tnum, num); return ub == (uint64_t*)table + tnum ? num : *ub; } /** * Get the quiet Not-a-Number value. */ inline double nan() { _assert_(true); return std::numeric_limits::quiet_NaN(); } /** * Get the positive infinity value. */ inline double inf() { _assert_(true); return std::numeric_limits::infinity(); } /** * Check a number is a Not-a-Number value. */ inline bool chknan(double num) { _assert_(true); return num != num; } /** * Check a number is an infinity value. */ inline bool chkinf(double num) { _assert_(true); return num == inf() || num == -inf(); } /** * Append a formatted string at the end of a string. */ inline void vstrprintf(std::string* dest, const char* format, va_list ap) { _assert_(dest && format); while (*format != '\0') { if (*format == '%') { char cbuf[NUMBUFSIZ]; cbuf[0] = '%'; size_t cbsiz = 1; int32_t lnum = 0; format++; while (std::strchr("0123456789 .+-hlLz", *format) && *format != '\0' && cbsiz < NUMBUFSIZ - 1) { if (*format == 'l' || *format == 'L') lnum++; cbuf[cbsiz++] = *(format++); } cbuf[cbsiz++] = *format; cbuf[cbsiz] = '\0'; switch (*format) { case 's': { const char* tmp = va_arg(ap, const char*); if (tmp) { dest->append(tmp); } else { dest->append("(null)"); } break; } case 'd': { char tbuf[NUMBUFSIZ*4]; size_t tsiz; if (lnum >= 2) { tsiz = std::sprintf(tbuf, cbuf, va_arg(ap, long long)); } else if (lnum >= 1) { tsiz = std::sprintf(tbuf, cbuf, va_arg(ap, long)); } else { tsiz = std::sprintf(tbuf, cbuf, va_arg(ap, int)); } dest->append(tbuf, tsiz); break; } case 'o': case 'u': case 'x': case 'X': case 'c': { char tbuf[NUMBUFSIZ*4]; size_t tsiz; if (lnum >= 2) { tsiz = std::sprintf(tbuf, cbuf, va_arg(ap, unsigned long long)); } else if (lnum >= 1) { tsiz = std::sprintf(tbuf, cbuf, va_arg(ap, unsigned long)); } else { tsiz = std::sprintf(tbuf, cbuf, va_arg(ap, unsigned int)); } dest->append(tbuf, tsiz); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { char tbuf[NUMBUFSIZ*4]; size_t tsiz; if (lnum >= 1) { tsiz = std::snprintf(tbuf, sizeof(tbuf), cbuf, va_arg(ap, long double)); } else { tsiz = std::snprintf(tbuf, sizeof(tbuf), cbuf, va_arg(ap, double)); } if (tsiz > sizeof(tbuf)) { tbuf[sizeof(tbuf)-1] = '*'; tsiz = sizeof(tbuf); } dest->append(tbuf, tsiz); break; } case 'p': { char tbuf[NUMBUFSIZ*4]; size_t tsiz = std::sprintf(tbuf, "%p", va_arg(ap, void*)); dest->append(tbuf, tsiz); break; } case '%': { dest->append("%", 1); break; } } } else { dest->append(format, 1); } format++; } } /** * Append a formatted string at the end of a string. */ inline void strprintf(std::string* dest, const char* format, ...) { _assert_(dest && format); va_list ap; va_start(ap, format); vstrprintf(dest, format, ap); va_end(ap); } /** * Generate a formatted string on memory. */ inline std::string strprintf(const char* format, ...) { _assert_(format); std::string str; va_list ap; va_start(ap, format); vstrprintf(&str, format, ap); va_end(ap); return str; } /** * Split a string with a delimiter */ inline size_t strsplit(const std::string& str, char delim, std::vector* elems) { _assert_(elems); elems->clear(); std::string::const_iterator it = str.begin(); std::string::const_iterator pv = it; while (it != str.end()) { if (*it == delim) { std::string col(pv, it); elems->push_back(col); pv = it + 1; } ++it; } std::string col(pv, it); elems->push_back(col); return elems->size(); } /** * Split a string with delimiters. */ inline size_t strsplit(const std::string& str, const std::string& delims, std::vector* elems) { _assert_(elems); elems->clear(); std::string::const_iterator it = str.begin(); std::string::const_iterator pv = it; while (it != str.end()) { while (delims.find(*it, 0) != std::string::npos) { std::string col(pv, it); elems->push_back(col); pv = it + 1; break; } ++it; } std::string col(pv, it); elems->push_back(col); return elems->size(); } /** * Convert the letters of a string into upper case. */ inline std::string* strtoupper(std::string* str) { _assert_(str); size_t size = str->size(); for (size_t i = 0; i < size; i++) { int32_t c = (unsigned char)(*str)[i]; if (c >= 'a' && c <= 'z') (*str)[i] = c - ('a' - 'A'); } return str; } /** * Convert the letters of a string into lower case. */ inline std::string* strtolower(std::string* str) { _assert_(str); size_t size = str->size(); for (size_t i = 0; i < size; i++) { int32_t c = (unsigned char)(*str)[i]; if (c >= 'A' && c <= 'Z') (*str)[i] = c + ('a' - 'A'); } return str; } /** * Check whether a string begins with a key. */ inline bool strfwm(const std::string& str, const std::string& key) { _assert_(true); size_t ksiz = key.size(); if (ksiz > str.size()) return false; return !std::memcmp(str.data(), key.data(), ksiz); } /** * Check whether a string ends with a key. */ inline bool strbwm(const std::string& str, const std::string& key) { _assert_(true); size_t ksiz = key.size(); if (ksiz > str.size()) return false; return !std::memcmp(str.data() + str.size() - ksiz, key.data(), ksiz); } /** * Cut space characters at head or tail of a string. */ inline std::string* strtrim(std::string* str) { _assert_(str); size_t size = str->size(); size_t wi = 0; size_t li = 0; for (size_t i = 0; i < size; i++) { int32_t c = (unsigned char)(*str)[i]; if (c >= '\0' && c <= ' ') { if (wi > 0) (*str)[wi++] = c; } else { (*str)[wi++] = c; li = wi; } } str->resize(li); return str; } /** * Convert a UTF-8 string into a UCS-4 array. */ inline void strutftoucs(const std::string& src, std::vector* dest) { _assert_(dest); dest->reserve(dest->size() + src.size()); size_t size = src.size(); size_t ri = 0; while (ri < size) { uint32_t c = (unsigned char)src[ri]; if (c < 0x80) { dest->push_back(c); } else if (c < 0xe0) { if (c >= 0xc0 && ri + 1 < size) { c = ((c & 0x1f) << 6) | (src[ri+1] & 0x3f); if (c >= 0x80) dest->push_back(c); ri++; } } else if (c < 0xf0) { if (ri + 2 < size) { c = ((c & 0x0f) << 12) | ((src[ri+1] & 0x3f) << 6) | (src[ri+2] & 0x3f); if (c >= 0x800) dest->push_back(c); ri += 2; } } else if (c < 0xf8) { if (ri + 3 < size) { c = ((c & 0x07) << 18) | ((src[ri+1] & 0x3f) << 12) | ((src[ri+2] & 0x3f) << 6) | (src[ri+3] & 0x3f); if (c >= 0x10000) dest->push_back(c); ri += 3; } } else if (c < 0xfc) { if (ri + 4 < size) { c = ((c & 0x03) << 24) | ((src[ri+1] & 0x3f) << 18) | ((src[ri+2] & 0x3f) << 12) | ((src[ri+3] & 0x3f) << 6) | (src[ri+4] & 0x3f); if (c >= 0x200000) dest->push_back(c); ri += 4; } } else if (c < 0xfe) { if (ri + 5 < size) { c = ((c & 0x01) << 30) | ((src[ri+1] & 0x3f) << 24) | ((src[ri+2] & 0x3f) << 18) | ((src[ri+3] & 0x3f) << 12) | ((src[ri+4] & 0x3f) << 6) | (src[ri+5] & 0x3f); if (c >= 0x4000000) dest->push_back(c); ri += 5; } } ri++; } } /** * Convert a UCS-4 array into a UTF-8 string. */ inline void strucstoutf(const std::vector& src, std::string* dest) { _assert_(dest); dest->reserve(dest->size() + src.size() * 3); std::vector::const_iterator it = src.begin(); std::vector::const_iterator itend = src.end(); while (it != itend) { uint32_t c = *it; if (c < 0x80) { dest->append(1, c); } else if (c < 0x800) { dest->append(1, 0xc0 | (c >> 6)); dest->append(1, 0x80 | (c & 0x3f)); } else if (c < 0x10000) { dest->append(1, 0xe0 | (c >> 12)); dest->append(1, 0x80 | ((c & 0xfff) >> 6)); dest->append(1, 0x80 | (c & 0x3f)); } else if (c < 0x200000) { dest->append(1, 0xf0 | (c >> 18)); dest->append(1, 0x80 | ((c & 0x3ffff) >> 12)); dest->append(1, 0x80 | ((c & 0xfff) >> 6)); dest->append(1, 0x80 | (c & 0x3f)); } else if (c < 0x4000000) { dest->append(1, 0xf8 | (c >> 24)); dest->append(1, 0x80 | ((c & 0xffffff) >> 18)); dest->append(1, 0x80 | ((c & 0x3ffff) >> 12)); dest->append(1, 0x80 | ((c & 0xfff) >> 6)); dest->append(1, 0x80 | (c & 0x3f)); } else if (c < 0x80000000) { dest->append(1, 0xfc | (c >> 30)); dest->append(1, 0x80 | ((c & 0x3fffffff) >> 24)); dest->append(1, 0x80 | ((c & 0xffffff) >> 18)); dest->append(1, 0x80 | ((c & 0x3ffff) >> 12)); dest->append(1, 0x80 | ((c & 0xfff) >> 6)); dest->append(1, 0x80 | (c & 0x3f)); } ++it; } } /** * Serialize a string vector object into a string object. */ inline void strvecdump(const std::vector& src, std::string* dest) { _assert_(dest); std::vector::const_iterator it = src.begin(); std::vector::const_iterator itend = src.end(); size_t dsiz = 1; while (it != itend) { dsiz += 2 + it->size(); ++it; } dest->reserve(dest->size() + dsiz); it = src.begin(); while (it != itend) { char nbuf[NUMBUFSIZ]; size_t nsiz = writevarnum(nbuf, it->size()); dest->append(nbuf, nsiz); dest->append(it->data(), it->size()); ++it; } } /** * Deserialize a string object into a string vector object. */ inline void strvecload(const std::string& src, std::vector* dest) { _assert_(dest); const char* rp = src.data(); size_t size = src.size(); while (size > 0) { uint64_t vsiz; size_t step = readvarnum(rp, size, &vsiz); rp += step; size -= step; if (vsiz > size) break; dest->push_back(std::string(rp, vsiz)); rp += vsiz; size -= vsiz; } } /** * Serialize a string vector object into a string object. */ inline void strmapdump(const std::map& src, std::string* dest) { _assert_(dest); std::map::const_iterator it = src.begin(); std::map::const_iterator itend = src.end(); size_t dsiz = 1; while (it != itend) { dsiz += 4 + it->first.size() + it->second.size(); ++it; } dest->reserve(dest->size() + dsiz); it = src.begin(); while (it != itend) { char nbuf[NUMBUFSIZ*2]; size_t nsiz = writevarnum(nbuf, it->first.size()); nsiz += writevarnum(nbuf + nsiz, it->second.size()); dest->append(nbuf, nsiz); dest->append(it->first.data(), it->first.size()); dest->append(it->second.data(), it->second.size()); ++it; } } /** * Deserialize a string object into a string map object. */ inline void strmapload(const std::string& src, std::map* dest) { _assert_(dest); const char* rp = src.data(); int64_t size = src.size(); while (size > 1) { uint64_t ksiz; size_t step = readvarnum(rp, size, &ksiz); rp += step; size -= step; if (size < 1) break; uint64_t vsiz; step = readvarnum(rp, size, &vsiz); rp += step; size -= step; int64_t rsiz = ksiz + vsiz; if (rsiz > size) break; (*dest)[std::string(rp, ksiz)] = std::string(rp + ksiz, vsiz); rp += rsiz; size -= rsiz; } } /** * Encode a serial object by hexadecimal encoding. */ inline char* hexencode(const void* buf, size_t size) { _assert_(buf && size <= MEMMAXSIZ); const unsigned char* rp = (const unsigned char*)buf; char* zbuf = new char[size*2+1]; char* wp = zbuf; for (const unsigned char* ep = rp + size; rp < ep; rp++) { int32_t num = *rp >> 4; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } num = *rp & 0x0f; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } } *wp = '\0'; return zbuf; } /** * Decode a string encoded by hexadecimal encoding. */ inline char* hexdecode(const char* str, size_t* sp) { _assert_(str && sp); char* zbuf = new char[std::strlen(str)+1]; char* wp = zbuf; while (true) { while (*str > '\0' && *str <= ' ') { str++; } int32_t num = 0; int32_t c = *(str++); if (c >= '0' && c <= '9') { num = c - '0'; } else if (c >= 'a' && c <= 'f') { num = c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { num = c - 'A' + 10; } else if (c == '\0') { break; } c = *(str++); if (c >= '0' && c <= '9') { num = num * 0x10 + c - '0'; } else if (c >= 'a' && c <= 'f') { num = num * 0x10 + c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { num = num * 0x10 + c - 'A' + 10; } else if (c == '\0') { *(wp++) = num; break; } *(wp++) = num; } *wp = '\0'; *sp = wp - zbuf; return zbuf; } /** * Encode a serial object by URL encoding. */ inline char* urlencode(const void* buf, size_t size) { _assert_(buf && size <= MEMMAXSIZ); const unsigned char* rp = (const unsigned char*)buf; char* zbuf = new char[size*3+1]; char* wp = zbuf; for (const unsigned char* ep = rp + size; rp < ep; rp++) { int32_t c = *rp; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c != '\0' && std::strchr("_-.~", c))) { *(wp++) = c; } else { *(wp++) = '%'; int32_t num = c >> 4; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } num = c & 0x0f; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } } } *wp = '\0'; return zbuf; } /** * Decode a string encoded by URL encoding. */ inline char* urldecode(const char* str, size_t* sp) { _assert_(str && sp); size_t zsiz = std::strlen(str); char* zbuf = new char[zsiz+1]; char* wp = zbuf; const char* ep = str + zsiz; while (str < ep) { int32_t c = *str; if (c == '%') { int32_t num = 0; if (++str >= ep) break; c = *str; if (c >= '0' && c <= '9') { num = c - '0'; } else if (c >= 'a' && c <= 'f') { num = c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { num = c - 'A' + 10; } if (++str >= ep) break; c = *str; if (c >= '0' && c <= '9') { num = num * 0x10 + c - '0'; } else if (c >= 'a' && c <= 'f') { num = num * 0x10 + c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { num = num * 0x10 + c - 'A' + 10; } *(wp++) = num; str++; } else if (c == '+') { *(wp++) = ' '; str++; } else if (c <= ' ' || c == 0x7f) { str++; } else { *(wp++) = c; str++; } } *wp = '\0'; *sp = wp - zbuf; return zbuf; } /** * Encode a serial object by Quoted-printable encoding. */ inline char* quoteencode(const void* buf, size_t size) { _assert_(buf && size <= MEMMAXSIZ); const unsigned char* rp = (const unsigned char*)buf; char* zbuf = new char[size*3+1]; char* wp = zbuf; for (const unsigned char* ep = rp + size; rp < ep; rp++) { int32_t c = *rp; if (c == '=' || c < ' ' || c > 0x7e) { *(wp++) = '='; int32_t num = c >> 4; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'A' + num - 10; } num = c & 0x0f; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'A' + num - 10; } } else { *(wp++) = c; } } *wp = '\0'; return zbuf; } /** * Decode a string encoded by Quoted-printable encoding. */ inline char* quotedecode(const char* str, size_t* sp) { _assert_(str && sp); size_t zsiz = std::strlen(str); char* zbuf = new char[zsiz+1]; char* wp = zbuf; const char* ep = str + zsiz; while (str < ep) { int32_t c = *str; if (c == '=') { int32_t num = 0; if (++str >= ep) break; c = *str; if (c == '\r') { if (++str >= ep) break; if (*str == '\n') str++; } else if (c == '\n') { str++; } else { if (c >= '0' && c <= '9') { num = c - '0'; } else if (c >= 'a' && c <= 'f') { num = c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { num = c - 'A' + 10; } if (++str >= ep) break; c = *str; if (c >= '0' && c <= '9') { num = num * 0x10 + c - '0'; } else if (c >= 'a' && c <= 'f') { num = num * 0x10 + c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { num = num * 0x10 + c - 'A' + 10; } *(wp++) = num; str++; } } else if (c < ' ' || c == 0x7f) { str++; } else { *(wp++) = c; str++; } } *wp = '\0'; *sp = wp - zbuf; return zbuf; } /** * Encode a serial object by Base64 encoding. */ inline char* baseencode(const void* buf, size_t size) { _assert_(buf && size <= MEMMAXSIZ); const char* tbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const unsigned char* rp = (const unsigned char*)buf; char* zbuf = new char[size*4/3+5]; char* wp = zbuf; for (size_t i = 0; i < size; i += 3) { switch (size - i) { case 1: { *(wp++) = tbl[rp[0] >> 2]; *(wp++) = tbl[(rp[0] & 3) << 4]; *(wp++) = '='; *(wp++) = '='; break; } case 2: { *(wp++) = tbl[rp[0] >> 2]; *(wp++) = tbl[((rp[0] & 3) << 4) + (rp[1] >> 4)]; *(wp++) = tbl[(rp[1] & 0xf) << 2]; *(wp++) = '='; break; } default: { *(wp++) = tbl[rp[0] >> 2]; *(wp++) = tbl[((rp[0] & 3) << 4) + (rp[1] >> 4)]; *(wp++) = tbl[((rp[1] & 0xf) << 2) + (rp[2] >> 6)]; *(wp++) = tbl[rp[2] & 0x3f]; break; } } rp += 3; } *wp = '\0'; return zbuf; } /** * Decode a string encoded by Base64 encoding. */ inline char* basedecode(const char* str, size_t* sp) { _assert_(str && sp); size_t bpos = 0; size_t eqcnt = 0; size_t len = std::strlen(str); unsigned char* zbuf = new unsigned char[len+4]; unsigned char* wp = zbuf; size_t zsiz = 0; while (bpos < len && eqcnt == 0) { size_t bits = 0; size_t i; for (i = 0; bpos < len && i < 4; bpos++) { if (str[bpos] >= 'A' && str[bpos] <= 'Z') { bits = (bits << 6) | (str[bpos] - 'A'); i++; } else if (str[bpos] >= 'a' && str[bpos] <= 'z') { bits = (bits << 6) | (str[bpos] - 'a' + 26); i++; } else if (str[bpos] >= '0' && str[bpos] <= '9') { bits = (bits << 6) | (str[bpos] - '0' + 52); i++; } else if (str[bpos] == '+') { bits = (bits << 6) | 62; i++; } else if (str[bpos] == '/') { bits = (bits << 6) | 63; i++; } else if (str[bpos] == '=') { bits <<= 6; i++; eqcnt++; } } if (i == 0 && bpos >= len) continue; switch (eqcnt) { case 0: { *wp++ = (bits >> 16) & 0xff; *wp++ = (bits >> 8) & 0xff; *wp++ = bits & 0xff; zsiz += 3; break; } case 1: { *wp++ = (bits >> 16) & 0xff; *wp++ = (bits >> 8) & 0xff; zsiz += 2; break; } case 2: { *wp++ = (bits >> 16) & 0xff; zsiz += 1; break; } } } zbuf[zsiz] = '\0'; *sp = zsiz; return (char*)zbuf; } /** * Cipher or decipher a serial object with the Arcfour stream cipher. */ inline void arccipher(const void* ptr, size_t size, const void* kbuf, size_t ksiz, void* obuf) { _assert_(ptr && size <= MEMMAXSIZ && kbuf && ksiz <= MEMMAXSIZ && obuf); if (ksiz < 1) { kbuf = ""; ksiz = 1; } uint32_t sbox[0x100], kbox[0x100]; for (int32_t i = 0; i < 0x100; i++) { sbox[i] = i; kbox[i] = ((uint8_t*)kbuf)[i%ksiz]; } uint32_t sidx = 0; for (int32_t i = 0; i < 0x100; i++) { sidx = (sidx + sbox[i] + kbox[i]) & 0xff; uint32_t swap = sbox[i]; sbox[i] = sbox[sidx]; sbox[sidx] = swap; } uint32_t x = 0; uint32_t y = 0; for (size_t i = 0; i < size; i++) { x = (x + 1) & 0xff; y = (y + sbox[x]) & 0xff; uint32_t swap = sbox[x]; sbox[x] = sbox[y]; sbox[y] = swap; ((uint8_t*)obuf)[i] = ((uint8_t*)ptr)[i] ^ sbox[(sbox[x]+sbox[y])&0xff]; } } /** * Duplicate a region on memory. */ inline char* memdup(const char* ptr, size_t size) { _assert_(ptr && size <= MEMMAXSIZ); char* obuf = new char[size+1]; std::memcpy(obuf, ptr, size); return obuf; } /** * Compare two regions by case insensitive evaluation. */ inline int32_t memicmp(const void* abuf, const void* bbuf, size_t size) { _assert_(abuf && bbuf && size <= MEMMAXSIZ); const unsigned char* ap = (unsigned char*)abuf; const unsigned char* bp = (unsigned char*)bbuf; const unsigned char* ep = ap + size; while (ap < ep) { int32_t ac = *ap; if (ac >= 'A' && ac <= 'Z') ac += 'a' - 'A'; int32_t bc = *bp; if (bc >= 'A' && bc <= 'Z') bc += 'a' - 'A'; if (ac != bc) return ac - bc; ap++; bp++; } return 0; } /** * Find the first occurrence of a sub pattern. */ inline void* memmem(const void* hbuf, size_t hsiz, const void* nbuf, size_t nsiz) { _assert_(hbuf && hsiz <= MEMMAXSIZ && nbuf && nsiz <= MEMMAXSIZ); if (nsiz < 1) return (void*)hbuf; if (hsiz < nsiz) return NULL; int32_t tc = *(unsigned char*)nbuf; const unsigned char* rp = (unsigned char*)hbuf; const unsigned char* ep = (unsigned char*)hbuf + hsiz - nsiz; while (rp <= ep) { if (*rp == tc) { bool hit = true; for (size_t i = 1; i < nsiz; i++) { if (rp[i] != ((unsigned char*)nbuf)[i]) { hit = false; break; } } if (hit) return (void*)rp; } rp++; } return NULL; } /** * Find the first occurrence of a sub pattern by case insensitive evaluation. */ inline void* memimem(const void* hbuf, size_t hsiz, const void* nbuf, size_t nsiz) { _assert_(hbuf && hsiz <= MEMMAXSIZ && nbuf && nsiz <= MEMMAXSIZ); if (nsiz < 1) return (void*)hbuf; if (hsiz < nsiz) return NULL; int32_t tc = *(unsigned char*)nbuf; if (tc >= 'A' && tc <= 'Z') tc += 'a' - 'A'; const unsigned char* rp = (unsigned char*)hbuf; const unsigned char* ep = (unsigned char*)hbuf + hsiz - nsiz; while (rp <= ep) { int32_t cc = *rp; if (cc >= 'A' && cc <= 'Z') cc += 'a' - 'A'; if (cc == tc) { bool hit = true; for (size_t i = 1; i < nsiz; i++) { int32_t hc = rp[i]; if (hc >= 'A' && hc <= 'Z') hc += 'a' - 'A'; int32_t nc = ((unsigned char*)nbuf)[i]; if (nc >= 'A' && nc <= 'Z') nc += 'a' - 'A'; if (hc != nc) { hit = false; break; } } if (hit) return (void*)rp; } rp++; } return NULL; } /** * Duplicate a string on memory. */ inline char* strdup(const char* str) { _assert_(str); size_t size = std::strlen(str); char* obuf = memdup(str, size); obuf[size] = '\0'; return obuf; } /** * Convert the letters of a string into upper case. */ inline char* strtoupper(char* str) { _assert_(str); char* wp = str; while (*wp != '\0') { if (*wp >= 'a' && *wp <= 'z') *wp -= 'a' - 'A'; wp++; } return str; } /** * Convert the letters of a string into lower case. */ inline char* strtolower(char* str) { _assert_(str); char* wp = str; while (*wp != '\0') { if (*wp >= 'A' && *wp <= 'Z') *wp += 'a' - 'A'; wp++; } return str; } /** * Cut space characters at head or tail of a string. */ inline char* strtrim(char* str) { _assert_(str); const char* rp = str; char* wp = str; bool head = true; while (*rp != '\0') { if (*rp > '\0' && *rp <= ' ') { if (!head) *(wp++) = *rp; } else { *(wp++) = *rp; head = false; } rp++; } *wp = '\0'; while (wp > str && wp[-1] > '\0' && wp[-1] <= ' ') { *(--wp) = '\0'; } return str; } /** * Squeeze space characters in a string and trim it. */ inline char* strsqzspc(char* str) { _assert_(str); const char* rp = str; char* wp = str; bool spc = true; while (*rp != '\0') { if (*rp > '\0' && *rp <= ' ') { if (!spc) *(wp++) = *rp; spc = true; } else { *(wp++) = *rp; spc = false; } rp++; } *wp = '\0'; for (wp--; wp >= str; wp--) { if (*wp > '\0' && *wp <= ' ') { *wp = '\0'; } else { break; } } return str; } /** * Normalize space characters in a string and trim it. */ inline char* strnrmspc(char* str) { _assert_(str); const char* rp = str; char* wp = str; bool spc = true; while (*rp != '\0') { if ((*rp > '\0' && *rp <= ' ') || *rp == 0x7f) { if (!spc) *(wp++) = ' '; spc = true; } else { *(wp++) = *rp; spc = false; } rp++; } *wp = '\0'; for (wp--; wp >= str; wp--) { if (*wp == ' ') { *wp = '\0'; } else { break; } } return str; } /** * Compare two strings by case insensitive evaluation. */ inline int32_t stricmp(const char* astr, const char* bstr) { _assert_(astr && bstr); while (*astr != '\0') { if (*bstr == '\0') return 1; int32_t ac = *(unsigned char*)astr; if (ac >= 'A' && ac <= 'Z') ac += 'a' - 'A'; int32_t bc = *(unsigned char*)bstr; if (bc >= 'A' && bc <= 'Z') bc += 'a' - 'A'; if (ac != bc) return ac - bc; astr++; bstr++; } return (*bstr == '\0') ? 0 : -1; } /** * Find the first occurrence of a substring by case insensitive evaluation. */ inline char* stristr(const char* hstr, const char* nstr) { _assert_(hstr && nstr); if (*nstr == '\0') return (char*)hstr; int32_t tc = *nstr; if (tc >= 'A' && tc <= 'Z') tc += 'a' - 'A'; const char* rp = hstr; while (*rp != '\0') { int32_t cc = *rp; if (cc >= 'A' && cc <= 'Z') cc += 'a' - 'A'; if (cc == tc) { bool hit = true; for (size_t i = 1; nstr[i] != '\0'; i++) { int32_t hc = rp[i]; if (hc >= 'A' && hc <= 'Z') hc += 'a' - 'A'; int32_t nc = nstr[i]; if (nc >= 'A' && nc <= 'Z') nc += 'a' - 'A'; if (hc != nc) { hit = false; break; } } if (hit) return (char*)rp; } rp++; } return NULL; } /** * Check whether a string begins with a key. */ inline bool strfwm(const char* str, const char* key) { _assert_(str && key); while (*key != '\0') { if (*str != *key || *str == '\0') return false; key++; str++; } return true; } /** * Check whether a string begins with a key by case insensitive evaluation. */ inline bool strifwm(const char* str, const char* key) { _assert_(str && key); while (*key != '\0') { if (*str == '\0') return false; int32_t sc = *str; if (sc >= 'A' && sc <= 'Z') sc += 'a' - 'A'; int32_t kc = *key; if (kc >= 'A' && kc <= 'Z') kc += 'a' - 'A'; if (sc != kc) return false; key++; str++; } return true; } /** * Check whether a string ends with a key. */ inline bool strbwm(const char* str, const char* key) { _assert_(str && key); size_t slen = std::strlen(str); size_t klen = std::strlen(key); for (size_t i = 1; i <= klen; i++) { if (i > slen || str[slen-i] != key[klen-i]) return false; } return true; } /** * Check whether a string ends with a key by case insensitive evaluation. */ inline bool stribwm(const char* str, const char* key) { _assert_(str && key); size_t slen = std::strlen(str); size_t klen = std::strlen(key); for (size_t i = 1; i <= klen; i++) { if (i > slen) return false; int32_t sc = str[slen-i]; if (sc >= 'A' && sc <= 'Z') sc += 'a' - 'A'; int32_t kc = key[klen-i]; if (kc >= 'A' && kc <= 'Z') kc += 'a' - 'A'; if (sc != kc) return false; } return true; } /** * Get the number of characters in a UTF-8 string. */ inline size_t strutflen(const char* str) { _assert_(str); size_t len = 0; while (*str != '\0') { len += (*(unsigned char*)str & 0xc0) != 0x80; str++; } return len; } /** * Convert a UTF-8 string into a UCS-4 array. */ inline void strutftoucs(const char* src, uint32_t* dest, size_t* np) { _assert_(src && dest && np); const unsigned char* rp = (unsigned char*)src; size_t dnum = 0; while (*rp != '\0') { uint32_t c = *rp; if (c < 0x80) { dest[dnum++] = c; } else if (c < 0xe0) { if (rp[1] != '\0') { c = ((c & 0x1f) << 6) | (rp[1] & 0x3f); if (c >= 0x80) dest[dnum++] = c; rp++; } } else if (c < 0xf0) { if (rp[1] != '\0' && rp[2] != '\0') { c = ((c & 0x0f) << 12) | ((rp[1] & 0x3f) << 6) | (rp[2] & 0x3f); if (c >= 0x800) dest[dnum++] = c; rp += 2; } } else if (c < 0xf8) { if (rp[1] != '\0' && rp[2] != '\0' && rp[3] != '\0') { c = ((c & 0x07) << 18) | ((rp[1] & 0x3f) << 12) | ((rp[2] & 0x3f) << 6) | (rp[3] & 0x3f); if (c >= 0x10000) dest[dnum++] = c; rp += 3; } } else if (c < 0xfc) { if (rp[1] != '\0' && rp[2] != '\0' && rp[3] != '\0' && rp[4] != '\0') { c = ((c & 0x03) << 24) | ((rp[1] & 0x3f) << 18) | ((rp[2] & 0x3f) << 12) | ((rp[3] & 0x3f) << 6) | (rp[4] & 0x3f); if (c >= 0x200000) dest[dnum++] = c; rp += 4; } } else if (c < 0xfe) { if (rp[1] != '\0' && rp[2] != '\0' && rp[3] != '\0' && rp[4] != '\0' && rp[5] != '\0') { c = ((c & 0x01) << 30) | ((rp[1] & 0x3f) << 24) | ((rp[2] & 0x3f) << 18) | ((rp[3] & 0x3f) << 12) | ((rp[4] & 0x3f) << 6) | (rp[5] & 0x3f); if (c >= 0x4000000) dest[dnum++] = c; rp += 5; } } rp++; } *np = dnum; } /** * Convert a UTF-8 string into a UCS-4 array. */ inline void strutftoucs(const char* src, size_t slen, uint32_t* dest, size_t* np) { _assert_(src && slen <= MEMMAXSIZ && dest && np); const unsigned char* rp = (unsigned char*)src; const unsigned char* ep = rp + slen; size_t dnum = 0; while (rp < ep) { uint32_t c = *rp; if (c < 0x80) { dest[dnum++] = c; } else if (c < 0xe0) { if (rp[1] != '\0') { c = ((c & 0x1f) << 6) | (rp[1] & 0x3f); if (c >= 0x80) dest[dnum++] = c; rp++; } } else if (c < 0xf0) { if (rp[1] != '\0' && rp[2] != '\0') { c = ((c & 0x0f) << 12) | ((rp[1] & 0x3f) << 6) | (rp[2] & 0x3f); if (c >= 0x800) dest[dnum++] = c; rp += 2; } } else if (c < 0xf8) { if (rp[1] != '\0' && rp[2] != '\0' && rp[3] != '\0') { c = ((c & 0x07) << 18) | ((rp[1] & 0x3f) << 12) | ((rp[2] & 0x3f) << 6) | (rp[3] & 0x3f); if (c >= 0x10000) dest[dnum++] = c; rp += 3; } } else if (c < 0xfc) { if (rp[1] != '\0' && rp[2] != '\0' && rp[3] != '\0' && rp[4] != '\0') { c = ((c & 0x03) << 24) | ((rp[1] & 0x3f) << 18) | ((rp[2] & 0x3f) << 12) | ((rp[3] & 0x3f) << 6) | (rp[4] & 0x3f); if (c >= 0x200000) dest[dnum++] = c; rp += 4; } } else if (c < 0xfe) { if (rp[1] != '\0' && rp[2] != '\0' && rp[3] != '\0' && rp[4] != '\0' && rp[5] != '\0') { c = ((c & 0x01) << 30) | ((rp[1] & 0x3f) << 24) | ((rp[2] & 0x3f) << 18) | ((rp[3] & 0x3f) << 12) | ((rp[4] & 0x3f) << 6) | (rp[5] & 0x3f); if (c >= 0x4000000) dest[dnum++] = c; rp += 5; } } rp++; } *np = dnum; } /** * Convert a UCS-4 array into a UTF-8 string. */ inline size_t strucstoutf(const uint32_t* src, size_t snum, char* dest) { _assert_(src && snum <= MEMMAXSIZ && dest); const uint32_t* ep = src + snum; unsigned char* wp = (unsigned char*)dest; while (src < ep) { uint32_t c = *src; if (c < 0x80) { *(wp++) = c; } else if (c < 0x800) { *(wp++) = 0xc0 | (c >> 6); *(wp++) = 0x80 | (c & 0x3f); } else if (c < 0x10000) { *(wp++) = 0xe0 | (c >> 12); *(wp++) = 0x80 | ((c & 0xfff) >> 6); *(wp++) = 0x80 | (c & 0x3f); } else if (c < 0x200000) { *(wp++) = 0xf0 | (c >> 18); *(wp++) = 0x80 | ((c & 0x3ffff) >> 12); *(wp++) = 0x80 | ((c & 0xfff) >> 6); *(wp++) = 0x80 | (c & 0x3f); } else if (c < 0x4000000) { *(wp++) = 0xf8 | (c >> 24); *(wp++) = 0x80 | ((c & 0xffffff) >> 18); *(wp++) = 0x80 | ((c & 0x3ffff) >> 12); *(wp++) = 0x80 | ((c & 0xfff) >> 6); *(wp++) = 0x80 | (c & 0x3f); } else if (c < 0x80000000) { *(wp++) = 0xfc | (c >> 30); *(wp++) = 0x80 | ((c & 0x3fffffff) >> 24); *(wp++) = 0x80 | ((c & 0xffffff) >> 18); *(wp++) = 0x80 | ((c & 0x3ffff) >> 12); *(wp++) = 0x80 | ((c & 0xfff) >> 6); *(wp++) = 0x80 | (c & 0x3f); } src++; } *wp = '\0'; return wp - (unsigned char*)dest; } /** * Allocate a region on memory. */ inline void* xmalloc(size_t size) { _assert_(size <= MEMMAXSIZ); void* ptr = std::malloc(size); if (!ptr) throw std::bad_alloc(); return ptr; } /** * Allocate a nullified region on memory. */ inline void* xcalloc(size_t nmemb, size_t size) { _assert_(nmemb <= MEMMAXSIZ && size <= MEMMAXSIZ); void* ptr = std::calloc(nmemb, size); if (!ptr) throw std::bad_alloc(); return ptr; } /** * Re-allocate a region on memory. */ inline void* xrealloc(void* ptr, size_t size) { _assert_(size <= MEMMAXSIZ); ptr = std::realloc(ptr, size); if (!ptr) throw std::bad_alloc(); return ptr; } /** * Free a region on memory. */ inline void xfree(void* ptr) { _assert_(true); std::free(ptr); } /** * Dummy test driver. */ inline bool _dummytest() { _assert_(true); std::ostringstream oss; oss << INT8MAX << INT16MAX << INT32MAX << INT64MAX; oss << INT8MIN << INT16MIN << INT32MIN << INT64MIN; oss << UINT8MAX << UINT16MAX << UINT32MAX << UINT64MAX; oss << SIZEMAX << FLTMAX << DBLMAX; oss << VERSION << LIBVER << LIBREV << FMTVER << OSNAME; oss << BIGEND << CLOCKTICK << PAGESIZ << FEATURES; oss << NUMBUFSIZ << MEMMAXSIZ; return oss.tellp() > 0; } } // common namespace #endif // duplication check // END OF FILE