1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdio.h> 27 #include <stdarg.h> 28 #include <stdexcept> 29 #include <algorithm> 30 31 #include "tstrings.h" 32 #include "ErrorHandling.h" 33 34 35 namespace tstrings { 36 37 /* Create formatted string 38 */ 39 tstring unsafe_format(tstring::const_pointer format, ...) { 40 if (!format) { 41 throw std::invalid_argument("Destination buffer can't be NULL"); 42 } 43 44 tstring fmtout; 45 int ret; 46 const int inc = 256; 47 48 va_list args; 49 va_start(args, format); 50 do { 51 fmtout.resize(fmtout.size() + inc); 52 #ifdef _MSC_VER 53 ret = _vsntprintf_s(&*fmtout.begin(), fmtout.size(), _TRUNCATE, format, args); 54 #else 55 // With g++ this compiles only with '-std=gnu++0x' option 56 ret = vsnprintf(&*fmtout.begin(), fmtout.size(), format, args); 57 #endif 58 } while(-1 == ret); 59 va_end(args); 60 61 //update string size by actual value 62 fmtout.resize(ret); 63 64 return fmtout; 65 } 66 67 /* 68 * Tests if two strings are equal according to CompareType. 69 * 70 * a - string to compare 71 * b - string to compare 72 * ct - CASE_SENSITIVE: case sensitive comparing type 73 * IGNORE_CASE: case insensitive comparing type 74 */ 75 bool equals(const tstring& a, const tstring& b, const CompareType ct) { 76 if (IGNORE_CASE==ct) { 77 return toLower(a) == toLower(b); 78 } 79 return a == b; 80 } 81 82 bool startsWith(const tstring &str, const tstring &substr, const CompareType ct) 83 { 84 if (str.size() < substr.size()) { 85 return false; 86 } 87 const tstring startOfStr = str.substr(0, substr.size()); 88 return tstrings::equals(startOfStr, substr, ct); 89 } 90 91 bool endsWith(const tstring &str, const tstring &substr, const CompareType ct) 92 { 93 if (str.size() < substr.size()) { 94 return false; 95 } 96 const tstring endOfStr = str.substr(str.size() - substr.size()); 97 return tstrings::equals(endOfStr, substr, ct); 98 } 99 100 /* 101 * Split string into a vector with given delimiter string 102 * 103 * strVector - string vector to store split tstring 104 * str - string to split 105 * delimiter - delimiter to split the string around 106 * st - ST_ALL: return value includes an empty string 107 * ST_EXCEPT_EMPTY_STRING: return value does not include an empty string 108 * 109 * Note: It does not support multiple delimiters 110 */ 111 void split(tstring_array &strVector, const tstring &str, 112 const tstring &delimiter, const SplitType st) { 113 tstring::size_type start = 0, end = 0, length = str.length(); 114 115 if (length == 0 || delimiter.length() == 0) { 116 return; 117 } 118 119 end = str.find(delimiter, start); 120 while(end != tstring::npos) { 121 if(st == ST_ALL || end - start > 1 ) { 122 strVector.push_back(str.substr(start, end == tstring::npos ? 123 tstring::npos : end - start)); 124 } 125 start = end > (tstring::npos - delimiter.size()) ? 126 tstring::npos : end + delimiter.size(); 127 end = str.find(delimiter, start); 128 } 129 130 if(st == ST_ALL || start < length) { 131 strVector.push_back(str.substr(start, length - start)); 132 } 133 } 134 135 /* 136 * Convert uppercase letters to lowercase 137 */ 138 tstring toLower(const tstring& str) { 139 tstring lower(str); 140 tstring::iterator ok = std::transform(lower.begin(), lower.end(), 141 lower.begin(), tolower); 142 if (ok!=lower.end()) { 143 lower.resize(0); 144 } 145 return lower; 146 } 147 148 149 /* 150 * Replace all substring occurrences in a tstring. 151 * If 'str' or 'search' is empty the function returns 'str'. 152 * The given 'str' remains unchanged in any case. 153 * The function returns changed copy of 'str'. 154 */ 155 tstring replace(const tstring &str, const tstring &search, const tstring &replace) 156 { 157 if (search.empty()) { 158 return str; 159 } 160 161 tstring s(str); 162 163 for (size_t pos = 0; ; pos += replace.length()) { 164 pos = s.find(search, pos); 165 if (pos == tstring::npos) { 166 break; 167 } 168 s.erase(pos, search.length()); 169 s.insert(pos, replace); 170 } 171 return s; 172 } 173 174 175 /* 176 * Remove trailing spaces 177 */ 178 179 tstring trim(const tstring& str, const tstring& whitespace) { 180 const size_t strBegin = str.find_first_not_of(whitespace); 181 if (strBegin == std::string::npos) { 182 return tstring(); // no content 183 } 184 185 const size_t strEnd = str.find_last_not_of(whitespace); 186 const size_t strRange = strEnd - strBegin + 1; 187 188 return str.substr(strBegin, strRange); 189 } 190 191 } // namespace tstrings 192 193 194 #ifdef TSTRINGS_WITH_WCHAR 195 namespace tstrings { 196 197 namespace { 198 /* 199 * Converts UTF16-encoded string into multi-byte string of the given encoding. 200 */ 201 std::string toMultiByte(const std::wstring& utf16str, int encoding) { 202 std::string reply; 203 do { 204 int cm = WideCharToMultiByte(encoding, 205 0, 206 utf16str.c_str(), 207 int(utf16str.size()), 208 NULL, 209 0, 210 NULL, 211 NULL); 212 if (cm < 0) { 213 JP_THROW("Unexpected reply from WideCharToMultiByte()"); 214 } 215 if (0 == cm) { 216 break; 217 } 218 219 reply.resize(cm); 220 int cm2 = WideCharToMultiByte(encoding, 221 0, 222 utf16str.c_str(), 223 int(utf16str.size()), 224 &*reply.begin(), 225 cm, 226 NULL, 227 NULL); 228 if (cm != cm2) { 229 JP_THROW("Unexpected reply from WideCharToMultiByte()"); 230 } 231 } while(0); 232 233 return reply; 234 } 235 236 /* 237 * Converts multi-byte string of the given encoding into UTF16-encoded string. 238 */ 239 std::wstring fromMultiByte(const std::string& str, int encoding) { 240 std::wstring utf16; 241 do { 242 int cw = MultiByteToWideChar(encoding, 243 MB_ERR_INVALID_CHARS, 244 str.c_str(), 245 int(str.size()), 246 NULL, 247 0); 248 if (cw < 0) { 249 JP_THROW("Unexpected reply from MultiByteToWideChar()"); 250 } 251 if (0 == cw) { 252 break; 253 } 254 255 utf16.resize(cw); 256 int cw2 = MultiByteToWideChar(encoding, 257 MB_ERR_INVALID_CHARS, 258 str.c_str(), 259 int(str.size()), 260 &*utf16.begin(), 261 cw); 262 if (cw != cw2) { 263 JP_THROW("Unexpected reply from MultiByteToWideChar()"); 264 } 265 } while(0); 266 267 return utf16; 268 } 269 } // namespace 270 271 std::string toUtf8(const std::wstring& utf16str) { 272 return toMultiByte(utf16str, CP_UTF8); 273 } 274 275 std::wstring toUtf16(const std::string& utf8str) { 276 return fromMultiByte(utf8str, CP_UTF8); 277 } 278 279 } // namespace tstrings 280 #endif // ifdef TSTRINGS_WITH_WCHAR