//------------------------------------------------------------------------------ /* Copyright (c) 2011-2013, OpenCoin, Inc. */ //============================================================================== // VFALCO TODO Replace these with something more robust and without macros. // #if ! BEAST_MSVC #define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) #endif std::string strprintf (const char* format, ...) { char buffer[50000]; char* p = buffer; int limit = sizeof (buffer); int ret; for (;;) { va_list arg_ptr; va_start (arg_ptr, format); ret = _vsnprintf (p, limit, format, arg_ptr); va_end (arg_ptr); if (ret >= 0 && ret < limit) break; if (p != buffer) delete[] p; limit *= 2; p = new char[limit]; if (p == NULL) throw std::bad_alloc (); } std::string str (p, p + ret); if (p != buffer) delete[] p; return str; } char charHex (int iDigit) { return iDigit < 10 ? '0' + iDigit : 'A' - 10 + iDigit; } int charUnHex (char cDigit) { return cDigit >= '0' && cDigit <= '9' ? cDigit - '0' : cDigit >= 'A' && cDigit <= 'F' ? cDigit - 'A' + 10 : cDigit >= 'a' && cDigit <= 'f' ? cDigit - 'a' + 10 : -1; } int strUnHex (std::string& strDst, const std::string& strSrc) { int iBytes = (strSrc.size () + 1) / 2; strDst.resize (iBytes); const char* pSrc = &strSrc[0]; char* pDst = &strDst[0]; if (strSrc.size () & 1) { int c = charUnHex (*pSrc++); if (c < 0) { iBytes = -1; } else { *pDst++ = c; } } for (int i = 0; iBytes >= 0 && i != iBytes; i++) { int cHigh = charUnHex (*pSrc++); int cLow = charUnHex (*pSrc++); if (cHigh < 0 || cLow < 0) { iBytes = -1; } else { strDst[i] = (cHigh << 4) | cLow; } } if (iBytes < 0) strDst.clear (); return iBytes; } Blob strUnHex (const std::string& strSrc) { std::string strTmp; strUnHex (strTmp, strSrc); return strCopy (strTmp); } uint64_t uintFromHex (const std::string& strSrc) { uint64_t uValue = 0; BOOST_FOREACH (char c, strSrc) uValue = (uValue << 4) | charUnHex (c); return uValue; } // // Misc string // Blob strCopy (const std::string& strSrc) { Blob vucDst; vucDst.resize (strSrc.size ()); std::copy (strSrc.begin (), strSrc.end (), vucDst.begin ()); return vucDst; } std::string strCopy (Blob const& vucSrc) { std::string strDst; strDst.resize (vucSrc.size ()); std::copy (vucSrc.begin (), vucSrc.end (), strDst.begin ()); return strDst; } extern std::string urlEncode (const std::string& strSrc) { std::string strDst; int iOutput = 0; int iSize = strSrc.length (); strDst.resize (iSize * 3); for (int iInput = 0; iInput < iSize; iInput++) { unsigned char c = strSrc[iInput]; if (c == ' ') { strDst[iOutput++] = '+'; } else if (isalnum (c)) { strDst[iOutput++] = c; } else { strDst[iOutput++] = '%'; strDst[iOutput++] = charHex (c >> 4); strDst[iOutput++] = charHex (c & 15); } } strDst.resize (iOutput); return strDst; } // // IP Port parsing // // <-- iPort: "" = -1 // VFALCO TODO Make this not require boost... and especially boost::asio bool parseIpPort (const std::string& strSource, std::string& strIP, int& iPort) { boost::smatch smMatch; bool bValid = false; static boost::regex reEndpoint ("\\`\\s*(\\S+)(?:\\s+(\\d+))?\\s*\\'"); if (boost::regex_match (strSource, smMatch, reEndpoint)) { boost::system::error_code err; std::string strIPRaw = smMatch[1]; std::string strPortRaw = smMatch[2]; boost::asio::ip::address addrIP = boost::asio::ip::address::from_string (strIPRaw, err); bValid = !err; if (bValid) { strIP = addrIP.to_string (); iPort = strPortRaw.empty () ? -1 : boost::lexical_cast (strPortRaw); } } return bValid; } bool parseUrl (const std::string& strUrl, std::string& strScheme, std::string& strDomain, int& iPort, std::string& strPath) { // scheme://username:password@hostname:port/rest static boost::regex reUrl ("(?i)\\`\\s*([[:alpha:]][-+.[:alpha:][:digit:]]*)://([^:/]+)(?::(\\d+))?(/.*)?\\s*?\\'"); boost::smatch smMatch; bool bMatch = boost::regex_match (strUrl, smMatch, reUrl); // Match status code. if (bMatch) { std::string strPort; strScheme = smMatch[1]; strDomain = smMatch[2]; strPort = smMatch[3]; strPath = smMatch[4]; boost::algorithm::to_lower (strScheme); iPort = strPort.empty () ? -1 : lexical_cast_s (strPort); // Log::out() << strUrl << " : " << bMatch << " : '" << strDomain << "' : '" << strPort << "' : " << iPort << " : '" << strPath << "'"; } // Log::out() << strUrl << " : " << bMatch << " : '" << strDomain << "' : '" << strPath << "'"; return bMatch; } // // Quality parsing // - integers as is. // - floats multiplied by a billion bool parseQuality (const std::string& strSource, uint32& uQuality) { uQuality = lexical_cast_s (strSource); if (!uQuality) { float fQuality = lexical_cast_s (strSource); if (fQuality) uQuality = (uint32) (QUALITY_ONE * fQuality); } return !!uQuality; } std::string addressToString (void const* address) { // VFALCO TODO Clean this up, use uintptr_t and only produce a 32 bit // output on 32 bit platforms // return strHex (static_cast (address) - static_cast (0)); } StringPairArray parseDelimitedKeyValueString (String parameters, beast_wchar delimiter) { StringPairArray keyValues; while (parameters.isNotEmpty ()) { String pair; { int const delimiterPos = parameters.indexOfChar (delimiter); if (delimiterPos != -1) { pair = parameters.substring (0, delimiterPos); parameters = parameters.substring (delimiterPos + 1); } else { pair = parameters; parameters = String::empty; } } int const equalPos = pair.indexOfChar ('='); if (equalPos != -1) { String const key = pair.substring (0, equalPos); String const value = pair.substring (equalPos + 1, pair.length ()); keyValues.set (key, value); } } return keyValues; }