1 /* 2 * Copyright (C) 2004-2020 ZNC, see the NOTICE file for details. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ZNCSTRING_H 18 #define ZNCSTRING_H 19 20 #include <znc/zncconfig.h> 21 #include <map> 22 #include <set> 23 #include <string> 24 #include <vector> 25 #include <sstream> 26 #include <sys/types.h> 27 #include <initializer_list> 28 29 #define _SQL(s) CString("'" + CString(s).Escape_n(CString::ESQL) + "'") 30 #define _URL(s) CString(s).Escape_n(CString::EURL) 31 #define _HTML(s) CString(s).Escape_n(CString::EHTML) 32 #define _NAMEDFMT(s) CString(s).Escape_n(CString::ENAMEDFMT) 33 34 class CString; 35 class MCString; 36 37 typedef std::set<CString> SCString; 38 typedef std::vector<CString> VCString; 39 typedef std::vector<std::pair<CString, CString>> VPair; 40 41 static const unsigned char XX = 0xff; 42 static const unsigned char base64_table[256] = { 43 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 44 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 45 XX, XX, XX, XX, XX, 62, XX, XX, XX, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 46 61, XX, XX, XX, XX, XX, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 47 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, 48 XX, XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 49 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 50 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 51 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 52 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 53 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 54 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 55 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 56 XX, XX, XX, XX, XX, XX, XX, XX, XX, 57 }; 58 59 enum class CaseSensitivity { CaseInsensitive, CaseSensitive }; 60 61 /** 62 * @brief String class that is used inside ZNC. 63 * 64 * All strings that are used in ZNC and its modules should use instances of this 65 * class. It provides helpful functions for parsing input like Token() and 66 * Split(). 67 */ 68 class CString : public std::string { 69 public: 70 typedef enum { 71 EASCII, 72 EURL, 73 EHTML, 74 ESQL, 75 ENAMEDFMT, 76 EDEBUG, 77 EMSGTAG, 78 EHEXCOLON, 79 } EEscape; 80 81 static const CaseSensitivity CaseSensitive = CaseSensitivity::CaseSensitive; 82 static const CaseSensitivity CaseInsensitive = 83 CaseSensitivity::CaseInsensitive; 84 CString(bool b)85 explicit CString(bool b) : std::string(b ? "true" : "false") {} 86 explicit CString(char c); 87 explicit CString(unsigned char c); 88 explicit CString(short i); 89 explicit CString(unsigned short i); 90 explicit CString(int i); 91 explicit CString(unsigned int i); 92 explicit CString(long i); 93 explicit CString(unsigned long i); 94 explicit CString(long long i); 95 explicit CString(unsigned long long i); 96 explicit CString(double i, int precision = 2); 97 explicit CString(float i, int precision = 2); 98 CString()99 CString() : std::string() {} CString(const char * c)100 CString(const char* c) : std::string(c) {} CString(const char * c,size_t l)101 CString(const char* c, size_t l) : std::string(c, l) {} CString(const std::string & s)102 CString(const std::string& s) : std::string(s) {} CString(size_t n,char c)103 CString(size_t n, char c) : std::string(n, c) {} CString(std::initializer_list<char> list)104 CString(std::initializer_list<char> list) : std::string(list) {} ~CString()105 ~CString() {} 106 107 /** 108 * Casts a CString to another type. Implemented via std::stringstream, you use this 109 * for any class that has an operator<<(std::ostream, YourClass). 110 * @param target The object to cast into. If the cast fails, its state is unspecified. 111 * @return True if the cast succeeds, and false if it fails. 112 */ 113 template <typename T> Convert(T * target)114 bool Convert(T* target) const { 115 std::stringstream ss(*this); 116 ss >> *target; 117 return (bool)ss; // we don't care why it failed, only whether it failed 118 } 119 120 /** 121 * Joins a collection of objects together, using 'this' as a delimiter. 122 * You can pass either pointers to arrays, or iterators to collections. 123 * @param i_begin An iterator pointing to the beginning of a group of objects. 124 * @param i_end An iterator pointing past the end of a group of objects. 125 * @return The joined string 126 */ 127 template <typename Iterator> Join(Iterator i_start,const Iterator & i_end)128 CString Join(Iterator i_start, const Iterator& i_end) const { 129 if (i_start == i_end) return CString(""); 130 std::ostringstream output; 131 output << *i_start; 132 while (true) { 133 ++i_start; 134 if (i_start == i_end) return CString(output.str()); 135 output << *this; 136 output << *i_start; 137 } 138 } 139 140 /** 141 * Compare this string caselessly to some other string. 142 * @param s The string to compare to. 143 * @param uLen The number of characters to compare. 144 * @return An integer less than, equal to, or greater than zero if this 145 * string smaller, equal.... to the given string. 146 */ 147 int CaseCmp(const CString& s, 148 CString::size_type uLen = CString::npos) const; 149 /** 150 * Compare this string case sensitively to some other string. 151 * @param s The string to compare to. 152 * @param uLen The number of characters to compare. 153 * @return An integer less than, equal to, or greater than zero if this 154 * string smaller, equal.... to the given string. 155 */ 156 int StrCmp(const CString& s, CString::size_type uLen = CString::npos) const; 157 /** 158 * Check if this string is equal to some other string. 159 * @param s The string to compare to. 160 * @param cs CaseSensitive if you want the comparison to be case 161 * sensitive, CaseInsensitive (default) otherwise. 162 * @return True if the strings are equal. 163 */ 164 bool Equals(const CString& s, CaseSensitivity cs = CaseInsensitive) const; 165 /** 166 * @deprecated 167 */ 168 bool Equals(const CString& s, bool bCaseSensitive, 169 CString::size_type uLen = CString::npos) const; 170 /** 171 * Do a wildcard comparison between two strings. 172 * For example, the following returns true: 173 * <code>WildCmp("*!?bar@foo", "I_am!~bar@foo");</code> 174 * @param sWild The wildcards used for the comparison. 175 * @param sString The string that is used for comparing. 176 * @param cs CaseSensitive (default) if you want the comparison 177 * to be case sensitive, CaseInsensitive otherwise. 178 * @todo Make cs CaseInsensitive by default. 179 * @return true if the wildcard matches. 180 */ 181 static bool WildCmp(const CString& sWild, const CString& sString, 182 CaseSensitivity cs = CaseSensitive); 183 /** 184 * Do a wild compare on this string. 185 * @param sWild The wildcards used to for the comparison. 186 * @param cs CaseSensitive (default) if you want the comparison 187 * to be case sensitive, CaseInsensitive otherwise. 188 * @todo Make cs CaseInsensitive by default. 189 * @return The result of <code>this->WildCmp(sWild, *this);</code>. 190 */ 191 bool WildCmp(const CString& sWild, 192 CaseSensitivity cs = CaseSensitive) const; 193 194 /** 195 * Turn all characters in this string into their upper-case equivalent. 196 * @returns A reference to *this. 197 */ 198 CString& MakeUpper(); 199 /** 200 * Turn all characters in this string into their lower-case equivalent. 201 * @returns A reference to *this. 202 */ 203 CString& MakeLower(); 204 /** 205 * Return a copy of this string with all characters turned into 206 * upper-case. 207 * @return The new string. 208 */ 209 CString AsUpper() const; 210 /** 211 * Return a copy of this string with all characters turned into 212 * lower-case. 213 * @return The new string. 214 */ 215 CString AsLower() const; 216 217 static EEscape ToEscape(const CString& sEsc); 218 CString Escape_n(EEscape eFrom, EEscape eTo) const; 219 CString Escape_n(EEscape eTo) const; 220 CString& Escape(EEscape eFrom, EEscape eTo); 221 CString& Escape(EEscape eTo); 222 223 /** Replace all occurrences in a string. 224 * 225 * You can specify a "safe zone" via sLeft and sRight. Anything inside 226 * of such a zone will not be replaced. This does not do recursion, so 227 * e.g. with <code>Replace("(a()a)", "a", "b", "(", ")", true)</code> 228 * you would get "a(b)" as result. The second opening brace and the 229 * second closing brace would not be seen as a delimitered and thus 230 * wouldn't be removed. The first a is inside a "safe zone" and thus is 231 * left alone, too. 232 * 233 * @param sStr The string to do the replacing on. This will also contain 234 * the result when this function returns. 235 * @param sReplace The string that should be replaced. 236 * @param sWith The replacement to use. 237 * @param sLeft The string that marks the begin of the "safe zone". 238 * @param sRight The string that marks the end of the "safe zone". 239 * @param bRemoveDelims If this is true, all matches for sLeft and 240 * sRight are removed. 241 * @returns The number of replacements done. 242 */ 243 static unsigned int Replace(CString& sStr, const CString& sReplace, 244 const CString& sWith, const CString& sLeft = "", 245 const CString& sRight = "", 246 bool bRemoveDelims = false); 247 248 /** Replace all occurrences in the current string. 249 * @see CString::Replace 250 * @param sReplace The string to look for. 251 * @param sWith The replacement to use. 252 * @param sLeft The delimiter at the beginning of a safe zone. 253 * @param sRight The delimiter at the end of a safe zone. 254 * @param bRemoveDelims If true, all matching delimiters are removed. 255 * @return The result of the replacing. The current string is left 256 * unchanged. 257 */ 258 CString Replace_n(const CString& sReplace, const CString& sWith, 259 const CString& sLeft = "", const CString& sRight = "", 260 bool bRemoveDelims = false) const; 261 /** Replace all occurrences in the current string. 262 * @see CString::Replace 263 * @param sReplace The string to look for. 264 * @param sWith The replacement to use. 265 * @param sLeft The delimiter at the beginning of a safe zone. 266 * @param sRight The delimiter at the end of a safe zone. 267 * @param bRemoveDelims If true, all matching delimiters are removed. 268 * @returns The number of replacements done. 269 */ 270 unsigned int Replace(const CString& sReplace, const CString& sWith, 271 const CString& sLeft = "", const CString& sRight = "", 272 bool bRemoveDelims = false); 273 /** Ellipsize the current string. 274 * For example, ellipsizing "Hello, I'm Bob" to the length 9 would 275 * result in "Hello,...". 276 * @param uLen The length to ellipsize to. 277 * @return The ellipsized string. 278 */ 279 CString Ellipsize(unsigned int uLen) const; 280 /** Return the left part of the string. 281 * @param uCount The number of characters to keep. 282 * @return The resulting string. 283 */ 284 CString Left(size_type uCount) const; 285 /** Return the right part of the string. 286 * @param uCount The number of characters to keep. 287 * @return The resulting string. 288 */ 289 CString Right(size_type uCount) const; 290 291 /** Get the first line of this string. 292 * @return The first line of text. 293 */ FirstLine()294 CString FirstLine() const { return Token(0, false, "\n"); } 295 296 /** Get a token out of this string. For example in the string "a bc d e", 297 * each of "a", "bc", "d" and "e" are tokens. 298 * @param uPos The number of the token you are interested. The first 299 * token has a position of 0. 300 * @param bRest If false, only the token you asked for is returned. Else 301 * you get the substring starting from the beginning of 302 * your token. 303 * @param sSep Seperator between tokens. 304 * @param bAllowEmpty If this is true, empty tokens are allowed. In the 305 * example from above this means that there is a 306 * token "" before the "e" token. 307 * @return The token you asked for and, if bRest is true, everything 308 * after it. 309 * @see Split() if you need a string split into all of its tokens. 310 */ 311 CString Token(size_t uPos, bool bRest = false, const CString& sSep = " ", 312 bool bAllowEmpty = false) const; 313 314 /** Get a token out of this string. This function behaves much like the 315 * other Token() function in this class. The extra arguments are 316 * handled similarly to Split(). 317 */ 318 CString Token(size_t uPos, bool bRest, const CString& sSep, 319 bool bAllowEmpty, const CString& sLeft, const CString& sRight, 320 bool bTrimQuotes = true) const; 321 322 size_type URLSplit(MCString& msRet) const; 323 size_type OptionSplit(MCString& msRet, bool bUpperKeys = false) const; 324 size_type QuoteSplit(VCString& vsRet) const; 325 326 /** Split up this string into tokens. 327 * Via sLeft and sRight you can define "markers" like with Replace(). 328 * Anything in such a marked section is treated as a single token. All 329 * occurrences of sDelim in such a block are ignored. 330 * @param sDelim Delimiter between tokens. 331 * @param vsRet Vector for returning the result. 332 * @param bAllowEmpty Do empty tokens count as a valid token? 333 * @param sLeft Left delimiter like with Replace(). 334 * @param sRight Right delimiter like with Replace(). 335 * @param bTrimQuotes Should sLeft and sRight be removed from the token 336 * they mark? 337 * @param bTrimWhiteSpace If this is true, CString::Trim() is called on 338 * each token. 339 * @return The number of tokens found. 340 */ 341 size_type Split(const CString& sDelim, VCString& vsRet, 342 bool bAllowEmpty = true, const CString& sLeft = "", 343 const CString& sRight = "", bool bTrimQuotes = true, 344 bool bTrimWhiteSpace = false) const; 345 346 /** Split up this string into tokens. 347 * This function is identical to the other CString::Split(), except that 348 * the result is returned as a SCString instead of a VCString. 349 */ 350 size_type Split(const CString& sDelim, SCString& ssRet, 351 bool bAllowEmpty = true, const CString& sLeft = "", 352 const CString& sRight = "", bool bTrimQuotes = true, 353 bool bTrimWhiteSpace = false) const; 354 355 /** Build a string from a format string, replacing values from a map. 356 * The format specification can contain simple named parameters that match 357 * keys in the given map. For example in the string "a {b} c", the key "b" 358 * is looked up in the map, and inserted for "{b}". 359 * @param sFormat The format specification. 360 * @param msValues A map of named parameters to their values. 361 * @return The string with named parameters replaced. 362 */ 363 static CString NamedFormat(const CString& sFormat, 364 const MCString& msValues); 365 366 /** Produces a random string. 367 * @param uLength The length of the resulting string. 368 * @return A random string. 369 */ 370 static CString RandomString(unsigned int uLength); 371 372 /** @return The MD5 hash of this string. */ 373 CString MD5() const; 374 /** @return The SHA256 hash of this string. */ 375 CString SHA256() const; 376 377 /** Treat this string as base64-encoded data and decode it. 378 * @param sRet String to which the result of the decode is safed. 379 * @return The length of the resulting string. 380 */ 381 unsigned long Base64Decode(CString& sRet) const; 382 /** Treat this string as base64-encoded data and decode it. 383 * The result is saved in this CString instance. 384 * @return The length of the resulting string. 385 */ 386 unsigned long Base64Decode(); 387 /** Treat this string as base64-encoded data and decode it. 388 * @return The decoded string. 389 */ 390 CString Base64Decode_n() const; 391 /** Base64-encode the current string. 392 * @param sRet String where the result is saved. 393 * @param uWrap A boolean(!?!) that decides if the result should be 394 * wrapped after everywhere 57 characters. 395 * @return true unless this code is buggy. 396 * @todo WTF @ uWrap. 397 * @todo This only returns false if some formula we use was wrong?! 398 */ 399 bool Base64Encode(CString& sRet, unsigned int uWrap = 0) const; 400 /** Base64-encode the current string. 401 * This string is overwritten with the result of the encode. 402 * @todo return value and param are as with Base64Encode() from above. 403 */ 404 bool Base64Encode(unsigned int uWrap = 0); 405 /** Base64-encode the current string 406 * @todo uWrap is as broken as Base64Encode()'s uWrap. 407 * @return The encoded string. 408 */ 409 CString Base64Encode_n(unsigned int uWrap = 0) const; 410 411 #ifdef HAVE_LIBSSL 412 CString Encrypt_n(const CString& sPass, const CString& sIvec = "") const; 413 CString Decrypt_n(const CString& sPass, const CString& sIvec = "") const; 414 void Encrypt(const CString& sPass, const CString& sIvec = ""); 415 void Decrypt(const CString& sPass, const CString& sIvec = ""); 416 void Crypt(const CString& sPass, bool bEncrypt, const CString& sIvec = ""); 417 #endif 418 419 /** Pretty-print a percent value. 420 * @param d The percent value. This should be in range 0-100. 421 * @return The "pretty" string. 422 */ 423 static CString ToPercent(double d); 424 /** Pretty-print a number of bytes. 425 * @param d The number of bytes. 426 * @return A string describing the number of bytes. 427 */ 428 static CString ToByteStr(unsigned long long d); 429 /** Pretty-print a time span. 430 * @param s Number of seconds to print. 431 * @return A string like "4w 6d 4h 3m 58s". 432 */ 433 static CString ToTimeStr(unsigned long s); 434 435 /** @return True if this string is not "false". */ 436 bool ToBool() const; 437 /** @return The numerical value of this string similar to atoi(). */ 438 short ToShort() const; 439 /** @return The numerical value of this string similar to atoi(). */ 440 unsigned short ToUShort() const; 441 /** @return The numerical value of this string similar to atoi(). */ 442 int ToInt() const; 443 /** @return The numerical value of this string similar to atoi(). */ 444 long ToLong() const; 445 /** @return The numerical value of this string similar to atoi(). */ 446 unsigned int ToUInt() const; 447 /** @return The numerical value of this string similar to atoi(). */ 448 unsigned long ToULong() const; 449 /** @return The numerical value of this string similar to atoi(). */ 450 unsigned long long ToULongLong() const; 451 /** @return The numerical value of this string similar to atoi(). */ 452 long long ToLongLong() const; 453 /** @return The numerical value of this string similar to atoi(). */ 454 double ToDouble() const; 455 456 /** Trim this string. All leading/trailing occurrences of characters from 457 * s are removed. 458 * @param s A list of characters that should be trimmed. 459 * @return true if this string was modified. 460 */ 461 bool Trim(const CString& s = " \t\r\n"); 462 /** Trim this string. All leading occurrences of characters from s are 463 * removed. 464 * @param s A list of characters that should be trimmed. 465 * @return true if this string was modified. 466 */ 467 bool TrimLeft(const CString& s = " \t\r\n"); 468 /** Trim this string. All trailing occurrences of characters from s are 469 * removed. 470 * @param s A list of characters that should be trimmed. 471 * @return true if this string was modified. 472 */ 473 bool TrimRight(const CString& s = " \t\r\n"); 474 /** Trim this string. All leading/trailing occurrences of characters from 475 * s are removed. This CString instance is not modified. 476 * @param s A list of characters that should be trimmed. 477 * @return The trimmed string. 478 */ 479 CString Trim_n(const CString& s = " \t\r\n") const; 480 /** Trim this string. All leading occurrences of characters from s are 481 * removed. This CString instance is not modified. 482 * @param s A list of characters that should be trimmed. 483 * @return The trimmed string. 484 */ 485 CString TrimLeft_n(const CString& s = " \t\r\n") const; 486 /** Trim this string. All trailing occurrences of characters from s are 487 * removed. This CString instance is not modified. 488 * @param s A list of characters that should be trimmed. 489 * @return The trimmed string. 490 */ 491 CString TrimRight_n(const CString& s = " \t\r\n") const; 492 493 /** Trim a given prefix. 494 * @param sPrefix The prefix that should be removed. 495 * @return True if this string was modified. 496 */ 497 bool TrimPrefix(const CString& sPrefix = ":"); 498 /** Trim a given suffix. 499 * @param sSuffix The suffix that should be removed. 500 * @return True if this string was modified. 501 */ 502 bool TrimSuffix(const CString& sSuffix); 503 /** Trim a given prefix. 504 * @param sPrefix The prefix that should be removed. 505 * @return A copy of this string without the prefix. 506 */ 507 CString TrimPrefix_n(const CString& sPrefix = ":") const; 508 /** Trim a given suffix. 509 * @param sSuffix The suffix that should be removed. 510 * @return A copy of this string without the prefix. 511 */ 512 CString TrimSuffix_n(const CString& sSuffix) const; 513 514 /** Find the position of the given substring. 515 * @param s The substring to search for. 516 * @param cs CaseSensitive if you want the comparison to be case 517 * sensitive, CaseInsensitive (default) otherwise. 518 * @return The position of the substring if found, CString::npos otherwise. 519 */ 520 size_t Find(const CString& s, CaseSensitivity cs = CaseInsensitive) const; 521 /** Check whether the string starts with a given prefix. 522 * @param sPrefix The prefix. 523 * @param cs CaseSensitive if you want the comparison to be case 524 * sensitive, CaseInsensitive (default) otherwise. 525 * @return True if the string starts with prefix, false otherwise. 526 */ 527 bool StartsWith(const CString& sPrefix, 528 CaseSensitivity cs = CaseInsensitive) const; 529 /** Check whether the string ends with a given suffix. 530 * @param sSuffix The suffix. 531 * @param cs CaseSensitive if you want the comparison to be case 532 * sensitive, CaseInsensitive (default) otherwise. 533 * @return True if the string ends with suffix, false otherwise. 534 */ 535 bool EndsWith(const CString& sSuffix, 536 CaseSensitivity cs = CaseInsensitive) const; 537 /** 538 * Check whether the string contains a given string. 539 * @param s The string to search. 540 * @param bCaseSensitive Whether the search is case sensitive. 541 * @return True if this string contains the other string, falser otherwise. 542 */ 543 bool Contains(const CString& s, CaseSensitivity cs = CaseInsensitive) const; 544 545 /** Remove characters from the beginning of this string. 546 * @param uLen The number of characters to remove. 547 * @return true if this string was modified. 548 */ 549 bool LeftChomp(size_type uLen = 1); 550 /** Remove characters from the end of this string. 551 * @param uLen The number of characters to remove. 552 * @return true if this string was modified. 553 */ 554 bool RightChomp(size_type uLen = 1); 555 /** Remove characters from the beginning of this string. 556 * This string object isn't modified. 557 * @param uLen The number of characters to remove. 558 * @return The result of the conversion. 559 */ 560 CString LeftChomp_n(size_type uLen = 1) const; 561 /** Remove characters from the end of this string. 562 * This string object isn't modified. 563 * @param uLen The number of characters to remove. 564 * @return The result of the conversion. 565 */ 566 CString RightChomp_n(size_type uLen = 1) const; 567 /** Remove controls characters from this string. 568 * Controls characters are color codes, and those in C0 set 569 * See https://en.wikipedia.org/wiki/C0_and_C1_control_codes 570 * @return The result of the conversion. 571 */ 572 CString& StripControls(); 573 /** Remove controls characters from this string. 574 * Controls characters are color codes, and those in C0 set 575 * See https://en.wikipedia.org/wiki/C0_and_C1_control_codes 576 * This string object isn't modified. 577 * @return The result of the conversion. 578 */ 579 CString StripControls_n() const; 580 581 private: 582 protected: 583 unsigned char* strnchr(const unsigned char* src, unsigned char c, 584 unsigned int iMaxBytes, 585 unsigned char* pFill = nullptr, 586 unsigned int* piCount = nullptr) const; 587 }; 588 589 /** 590 * @brief A dictionary for strings. 591 * @todo Replace with "using MCString = std::map<CString, CString>;" in ZNC 2.0 592 * 593 * This class maps strings to other strings. 594 */ 595 class MCString : public std::map<CString, CString> { 596 public: 597 /** Construct an empty MCString. */ MCString()598 MCString() : std::map<CString, CString>() {} 599 /** Construct a MCString using an initializer list eg. MCString m = { {"key1", "val1"}, {"key2", "val2"} }; */ MCString(std::initializer_list<std::pair<const CString,CString>> list)600 MCString(std::initializer_list<std::pair<const CString, CString>> list) 601 : std::map<CString, CString>(list) {} 602 /** Destruct this MCString. */ ~MCString()603 virtual ~MCString() { clear(); } 604 605 /** A static instance of an empty map. */ 606 static const MCString EmptyMap; 607 608 /** Status codes that can be returned by WriteToDisk() and 609 * ReadFromDisk(). */ 610 enum status_t { 611 /// No errors. 612 MCS_SUCCESS = 0, 613 /// Opening the file failed. 614 MCS_EOPEN = 1, 615 /// Writing to the file failed. 616 MCS_EWRITE = 2, 617 /// WriteFilter() failed. 618 MCS_EWRITEFIL = 3, 619 /// ReadFilter() failed. 620 MCS_EREADFIL = 4 621 }; 622 623 /** Write this map to a file. 624 * @param sPath The file name to write to. 625 * @param iMode The mode for the file. 626 * @return The result of the operation. 627 * @see WriteFilter. 628 */ 629 enum status_t WriteToDisk(const CString& sPath, mode_t iMode = 0644) const; 630 /** Read a map from a file. 631 * @param sPath The file name to read from. 632 * @return The result of the operation. 633 * @see ReadFilter. 634 */ 635 enum status_t ReadFromDisk(const CString& sPath); 636 637 /** Filter used while writing this map. This function is called by 638 * WriteToDisk() for each pair that is going to be written. This 639 * function has the chance to modify the data that will be written. 640 * @param sKey The key that will be written. Can be modified. 641 * @param sValue The value that will be written. Can be modified. 642 * @return true unless WriteToDisk() should fail with MCS_EWRITEFIL. 643 */ WriteFilter(CString & sKey,CString & sValue)644 virtual bool WriteFilter(CString& sKey, CString& sValue) const { 645 return true; 646 } 647 /** Filter used while reading this map. This function is called by 648 * ReadFromDisk() for each pair that is beging read. This function has 649 * the chance to modify the data that is being read. 650 * @param sKey The key that was read. Can be modified. 651 * @param sValue The value that was read. Can be modified. 652 * @return true unless ReadFromDisk() should fail with MCS_EWRITEFIL. 653 */ ReadFilter(CString & sKey,CString & sValue)654 virtual bool ReadFilter(CString& sKey, CString& sValue) const { 655 return true; 656 } 657 658 /** Encode a value so that it can safely be parsed by ReadFromDisk(). 659 * This is an internal function. 660 */ 661 virtual CString& Encode(CString& sValue) const; 662 /** Undo the effects of Encode(). This is an internal function. */ 663 virtual CString& Decode(CString& sValue) const; 664 }; 665 666 namespace std { 667 template <> 668 struct hash<CString> : hash<std::string> {}; 669 } 670 671 // Make translateable messages easy to write: 672 // t_f("Foo is {1}")(foo) 673 class CInlineFormatMessage { 674 public: 675 explicit CInlineFormatMessage(const CString& sFormat) 676 : m_sFormat(sFormat) {} 677 explicit CInlineFormatMessage(CString&& sFormat) 678 : m_sFormat(std::move(sFormat)) {} 679 680 template <typename... Args> 681 CString operator()(const Args&... args) const { 682 MCString values; 683 apply(values, 1, args...); 684 return CString::NamedFormat(m_sFormat, values); 685 } 686 687 private: 688 template <typename Arg, typename... Rest> 689 void apply(MCString& values, int index, const Arg& arg, 690 const Rest&... rest) const { 691 values[CString(index)] = CString(arg); 692 apply(values, index + 1, rest...); 693 } 694 695 void apply(MCString& values, int index) const {} 696 697 CString m_sFormat; 698 }; 699 700 // For gtest 701 #ifdef GTEST_FAIL 702 inline void PrintTo(const CString& s, std::ostream* os) { 703 *os << '"' << s.Escape_n(CString::EDEBUG) << '"'; 704 } 705 #endif 706 707 #endif // !ZNCSTRING_H 708