crn_dynamic_string.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. // File: crn_dynamic_string.cpp
  2. // See Copyright Notice and license at the end of inc/crnlib.h
  3. #include "crn_core.h"
  4. #include "crn_strutils.h"
  5. namespace crnlib
  6. {
  7. dynamic_string g_empty_dynamic_string;
  8. dynamic_string::dynamic_string(eVarArg dummy, const char* p, ...) :
  9. m_buf_size(0), m_len(0), m_pStr(NULL)
  10. {
  11. dummy;
  12. CRNLIB_ASSERT(p);
  13. va_list args;
  14. va_start(args, p);
  15. format_args(p, args);
  16. va_end(args);
  17. }
  18. dynamic_string::dynamic_string(const char* p) :
  19. m_buf_size(0), m_len(0), m_pStr(NULL)
  20. {
  21. CRNLIB_ASSERT(p);
  22. set(p);
  23. }
  24. dynamic_string::dynamic_string(const char* p, uint len) :
  25. m_buf_size(0), m_len(0), m_pStr(NULL)
  26. {
  27. CRNLIB_ASSERT(p);
  28. set_from_buf(p, len);
  29. }
  30. dynamic_string::dynamic_string(const dynamic_string& other) :
  31. m_buf_size(0), m_len(0), m_pStr(NULL)
  32. {
  33. set(other);
  34. }
  35. void dynamic_string::clear()
  36. {
  37. check();
  38. if (m_pStr)
  39. {
  40. crnlib_delete_array(m_pStr);
  41. m_pStr = NULL;
  42. m_len = 0;
  43. m_buf_size = 0;
  44. }
  45. }
  46. void dynamic_string::empty()
  47. {
  48. truncate(0);
  49. }
  50. void dynamic_string::optimize()
  51. {
  52. if (!m_len)
  53. clear();
  54. else
  55. {
  56. uint min_buf_size = math::next_pow2((uint)m_len + 1);
  57. if (m_buf_size > min_buf_size)
  58. {
  59. char* p = crnlib_new_array<char>(min_buf_size);
  60. memcpy(p, m_pStr, m_len + 1);
  61. crnlib_delete_array(m_pStr);
  62. m_pStr = p;
  63. m_buf_size = static_cast<uint16>(min_buf_size);
  64. check();
  65. }
  66. }
  67. }
  68. int dynamic_string::compare(const char* p, bool case_sensitive) const
  69. {
  70. CRNLIB_ASSERT(p);
  71. const int result = (case_sensitive ? strcmp : crn_stricmp)(get_ptr_priv(), p);
  72. if (result < 0)
  73. return -1;
  74. else if (result > 0)
  75. return 1;
  76. return 0;
  77. }
  78. int dynamic_string::compare(const dynamic_string& rhs, bool case_sensitive) const
  79. {
  80. return compare(rhs.get_ptr_priv(), case_sensitive);
  81. }
  82. dynamic_string& dynamic_string::set(const char* p, uint max_len)
  83. {
  84. CRNLIB_ASSERT(p);
  85. const uint len = math::minimum<uint>(max_len, static_cast<uint>(strlen(p)));
  86. CRNLIB_ASSERT(len < cUINT16_MAX);
  87. if ((!len) || (len >= cUINT16_MAX))
  88. clear();
  89. else if ((m_pStr) && (p >= m_pStr) && (p < (m_pStr + m_buf_size)))
  90. {
  91. if (m_pStr != p)
  92. memmove(m_pStr, p, len);
  93. m_pStr[len] = '\0';
  94. m_len = static_cast<uint16>(len);
  95. }
  96. else if (ensure_buf(len, false))
  97. {
  98. m_len = static_cast<uint16>(len);
  99. memcpy(m_pStr, p, m_len + 1);
  100. }
  101. check();
  102. return *this;
  103. }
  104. dynamic_string& dynamic_string::set(const dynamic_string& other, uint max_len)
  105. {
  106. if (this == &other)
  107. {
  108. if (max_len < m_len)
  109. {
  110. m_pStr[max_len] = '\0';
  111. m_len = static_cast<uint16>(max_len);
  112. }
  113. }
  114. else
  115. {
  116. const uint len = math::minimum<uint>(max_len, other.m_len);
  117. if (!len)
  118. clear();
  119. else if (ensure_buf(len, false))
  120. {
  121. m_len = static_cast<uint16>(len);
  122. memcpy(m_pStr, other.get_ptr_priv(), m_len);
  123. m_pStr[len] = '\0';
  124. }
  125. }
  126. check();
  127. return *this;
  128. }
  129. bool dynamic_string::set_len(uint new_len, char fill_char)
  130. {
  131. if ((new_len >= cUINT16_MAX) || (!fill_char))
  132. {
  133. CRNLIB_ASSERT(0);
  134. return false;
  135. }
  136. uint cur_len = m_len;
  137. if (ensure_buf(new_len, true))
  138. {
  139. if (new_len > cur_len)
  140. memset(m_pStr + cur_len, fill_char, new_len - cur_len);
  141. m_pStr[new_len] = 0;
  142. m_len = static_cast<uint16>(new_len);
  143. check();
  144. }
  145. return true;
  146. }
  147. dynamic_string& dynamic_string::set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_chars, uint len_in_chars)
  148. {
  149. CRNLIB_ASSERT(buf_size_in_chars <= cUINT16_MAX);
  150. CRNLIB_ASSERT(math::is_power_of_2(buf_size_in_chars) || (buf_size_in_chars == cUINT16_MAX));
  151. CRNLIB_ASSERT((len_in_chars + 1) <= buf_size_in_chars);
  152. clear();
  153. m_pStr = pBuf;
  154. m_buf_size = static_cast<uint16>(buf_size_in_chars);
  155. m_len = static_cast<uint16>(len_in_chars);
  156. check();
  157. return *this;
  158. }
  159. dynamic_string& dynamic_string::set_from_buf(const void* pBuf, uint buf_size)
  160. {
  161. CRNLIB_ASSERT(pBuf);
  162. if (buf_size >= cUINT16_MAX)
  163. {
  164. clear();
  165. return *this;
  166. }
  167. #ifdef CRNLIB_BUILD_DEBUG
  168. if ((buf_size) && (memchr(pBuf, 0, buf_size) != NULL))
  169. {
  170. CRNLIB_ASSERT(0);
  171. clear();
  172. return *this;
  173. }
  174. #endif
  175. if (ensure_buf(buf_size, false))
  176. {
  177. if (buf_size)
  178. memcpy(m_pStr, pBuf, buf_size);
  179. m_pStr[buf_size] = 0;
  180. m_len = static_cast<uint16>(buf_size);
  181. check();
  182. }
  183. return *this;
  184. }
  185. dynamic_string& dynamic_string::set_char(uint index, char c)
  186. {
  187. CRNLIB_ASSERT(index <= m_len);
  188. if (!c)
  189. truncate(index);
  190. else if (index < m_len)
  191. {
  192. m_pStr[index] = c;
  193. check();
  194. }
  195. else if (index == m_len)
  196. append_char(c);
  197. return *this;
  198. }
  199. dynamic_string& dynamic_string::append_char(char c)
  200. {
  201. if (ensure_buf(m_len + 1))
  202. {
  203. m_pStr[m_len] = c;
  204. m_pStr[m_len + 1] = '\0';
  205. m_len++;
  206. check();
  207. }
  208. return *this;
  209. }
  210. dynamic_string& dynamic_string::truncate(uint new_len)
  211. {
  212. if (new_len < m_len)
  213. {
  214. m_pStr[new_len] = '\0';
  215. m_len = static_cast<uint16>(new_len);
  216. check();
  217. }
  218. return *this;
  219. }
  220. dynamic_string& dynamic_string::tolower()
  221. {
  222. if (m_len)
  223. {
  224. #ifdef _MSC_VER
  225. _strlwr_s(get_ptr_priv(), m_buf_size);
  226. #else
  227. strlwr(get_ptr_priv());
  228. #endif
  229. }
  230. return *this;
  231. }
  232. dynamic_string& dynamic_string::toupper()
  233. {
  234. if (m_len)
  235. {
  236. #ifdef _MSC_VER
  237. _strupr_s(get_ptr_priv(), m_buf_size);
  238. #else
  239. strupr(get_ptr_priv());
  240. #endif
  241. }
  242. return *this;
  243. }
  244. dynamic_string& dynamic_string::append(const char* p)
  245. {
  246. CRNLIB_ASSERT(p);
  247. uint len = static_cast<uint>(strlen(p));
  248. uint new_total_len = m_len + len;
  249. if ((new_total_len) && ensure_buf(new_total_len))
  250. {
  251. memcpy(m_pStr + m_len, p, len + 1);
  252. m_len = static_cast<uint16>(m_len + len);
  253. check();
  254. }
  255. return *this;
  256. }
  257. dynamic_string& dynamic_string::append(const dynamic_string& other)
  258. {
  259. uint len = other.m_len;
  260. uint new_total_len = m_len + len;
  261. if ((new_total_len) && ensure_buf(new_total_len))
  262. {
  263. memcpy(m_pStr + m_len, other.get_ptr_priv(), len + 1);
  264. m_len = static_cast<uint16>(m_len + len);
  265. check();
  266. }
  267. return *this;
  268. }
  269. dynamic_string operator+ (const char* p, const dynamic_string& a)
  270. {
  271. return dynamic_string(p).append(a);
  272. }
  273. dynamic_string operator+ (const dynamic_string& a, const char* p)
  274. {
  275. return dynamic_string(a).append(p);
  276. }
  277. dynamic_string operator+ (const dynamic_string& a, const dynamic_string& b)
  278. {
  279. return dynamic_string(a).append(b);
  280. }
  281. dynamic_string& dynamic_string::format_args(const char* p, va_list args)
  282. {
  283. CRNLIB_ASSERT(p);
  284. const uint cBufSize = 4096;
  285. char buf[cBufSize];
  286. #ifdef _MSC_VER
  287. int l = vsnprintf_s(buf, cBufSize, _TRUNCATE, p, args);
  288. #else
  289. int l = vsnprintf(buf, cBufSize, p, args);
  290. #endif
  291. if (l <= 0)
  292. clear();
  293. else if (ensure_buf(l, false))
  294. {
  295. memcpy(m_pStr, buf, l + 1);
  296. m_len = static_cast<uint16>(l);
  297. check();
  298. }
  299. return *this;
  300. }
  301. dynamic_string& dynamic_string::format(const char* p, ...)
  302. {
  303. CRNLIB_ASSERT(p);
  304. va_list args;
  305. va_start(args, p);
  306. format_args(p, args);
  307. va_end(args);
  308. return *this;
  309. }
  310. dynamic_string& dynamic_string::crop(uint start, uint len)
  311. {
  312. if (start >= m_len)
  313. {
  314. clear();
  315. return *this;
  316. }
  317. len = math::minimum<uint>(len, m_len - start);
  318. if (start)
  319. memmove(get_ptr_priv(), get_ptr_priv() + start, len);
  320. m_pStr[len] = '\0';
  321. m_len = static_cast<uint16>(len);
  322. check();
  323. return *this;
  324. }
  325. dynamic_string& dynamic_string::substring(uint start, uint end)
  326. {
  327. CRNLIB_ASSERT(start <= end);
  328. if (start > end)
  329. return *this;
  330. return crop(start, end - start);
  331. }
  332. dynamic_string& dynamic_string::left(uint len)
  333. {
  334. return substring(0, len);
  335. }
  336. dynamic_string& dynamic_string::mid(uint start, uint len)
  337. {
  338. return crop(start, len);
  339. }
  340. dynamic_string& dynamic_string::right(uint start)
  341. {
  342. return substring(start, get_len());
  343. }
  344. dynamic_string& dynamic_string::tail(uint num)
  345. {
  346. return substring(math::maximum<int>(static_cast<int>(get_len()) - static_cast<int>(num), 0), get_len());
  347. }
  348. dynamic_string& dynamic_string::unquote()
  349. {
  350. if (m_len >= 2)
  351. {
  352. if ( ((*this)[0] == '\"') && ((*this)[m_len - 1] == '\"') )
  353. {
  354. return mid(1, m_len - 2);
  355. }
  356. }
  357. return *this;
  358. }
  359. int dynamic_string::find_left(const char* p, bool case_sensitive) const
  360. {
  361. CRNLIB_ASSERT(p);
  362. const int p_len = (int)strlen(p);
  363. for (int i = 0; i <= (m_len - p_len); i++)
  364. if ((case_sensitive ? strncmp : _strnicmp)(p, &m_pStr[i], p_len) == 0)
  365. return i;
  366. return -1;
  367. }
  368. bool dynamic_string::contains(const char* p, bool case_sensitive) const
  369. {
  370. return find_left(p, case_sensitive) >= 0;
  371. }
  372. uint dynamic_string::count_char(char c) const
  373. {
  374. uint count = 0;
  375. for (uint i = 0; i < m_len; i++)
  376. if (m_pStr[i] == c)
  377. count++;
  378. return count;
  379. }
  380. int dynamic_string::find_left(char c) const
  381. {
  382. for (uint i = 0; i < m_len; i++)
  383. if (m_pStr[i] == c)
  384. return i;
  385. return -1;
  386. }
  387. int dynamic_string::find_right(char c) const
  388. {
  389. for (int i = (int)m_len - 1; i >= 0; i--)
  390. if (m_pStr[i] == c)
  391. return i;
  392. return -1;
  393. }
  394. int dynamic_string::find_right(const char* p, bool case_sensitive) const
  395. {
  396. CRNLIB_ASSERT(p);
  397. const int p_len = (int)strlen(p);
  398. for (int i = m_len - p_len; i >= 0; i--)
  399. if ((case_sensitive ? strncmp : _strnicmp)(p, &m_pStr[i], p_len) == 0)
  400. return i;
  401. return -1;
  402. }
  403. dynamic_string& dynamic_string::trim()
  404. {
  405. int s, e;
  406. for (s = 0; s < (int)m_len; s++)
  407. if (!isspace(m_pStr[s]))
  408. break;
  409. for (e = m_len - 1; e > s; e--)
  410. if (!isspace(m_pStr[e]))
  411. break;
  412. return crop(s, e - s + 1);
  413. }
  414. dynamic_string& dynamic_string::trim_crlf()
  415. {
  416. int s = 0, e;
  417. for (e = m_len - 1; e > s; e--)
  418. if ((m_pStr[e] != 13) && (m_pStr[e] != 10))
  419. break;
  420. return crop(s, e - s + 1);
  421. }
  422. dynamic_string& dynamic_string::remap(int from_char, int to_char)
  423. {
  424. for (uint i = 0; i < m_len; i++)
  425. if (m_pStr[i] == from_char)
  426. m_pStr[i] = (char)to_char;
  427. return *this;
  428. }
  429. #ifdef CRNLIB_BUILD_DEBUG
  430. void dynamic_string::check() const
  431. {
  432. if (!m_pStr)
  433. {
  434. CRNLIB_ASSERT(!m_buf_size && !m_len);
  435. }
  436. else
  437. {
  438. CRNLIB_ASSERT(m_buf_size);
  439. CRNLIB_ASSERT((m_buf_size == cUINT16_MAX) || math::is_power_of_2((uint32)m_buf_size));
  440. CRNLIB_ASSERT(m_len < m_buf_size);
  441. CRNLIB_ASSERT(!m_pStr[m_len]);
  442. #if CRNLIB_SLOW_STRING_LEN_CHECKS
  443. CRNLIB_ASSERT(strlen(m_pStr) == m_len);
  444. #endif
  445. }
  446. }
  447. #endif
  448. bool dynamic_string::ensure_buf(uint len, bool preserve_contents)
  449. {
  450. uint buf_size_needed = len + 1;
  451. CRNLIB_ASSERT(buf_size_needed <= cUINT16_MAX);
  452. if (buf_size_needed <= cUINT16_MAX)
  453. {
  454. if (buf_size_needed > m_buf_size)
  455. expand_buf(buf_size_needed, preserve_contents);
  456. }
  457. return m_buf_size >= buf_size_needed;
  458. }
  459. bool dynamic_string::expand_buf(uint new_buf_size, bool preserve_contents)
  460. {
  461. new_buf_size = math::minimum<uint>(cUINT16_MAX, math::next_pow2(math::maximum<uint>(m_buf_size, new_buf_size)));
  462. if (new_buf_size != m_buf_size)
  463. {
  464. char* p = crnlib_new_array<char>(new_buf_size);
  465. if (preserve_contents)
  466. memcpy(p, get_ptr_priv(), m_len + 1);
  467. crnlib_delete_array(m_pStr);
  468. m_pStr = p;
  469. m_buf_size = static_cast<uint16>(new_buf_size);
  470. if (preserve_contents)
  471. check();
  472. }
  473. return m_buf_size >= new_buf_size;
  474. }
  475. void dynamic_string::swap(dynamic_string& other)
  476. {
  477. utils::swap(other.m_buf_size, m_buf_size);
  478. utils::swap(other.m_len, m_len);
  479. utils::swap(other.m_pStr, m_pStr);
  480. }
  481. int dynamic_string::serialize(void* pBuf, uint buf_size, bool little_endian) const
  482. {
  483. uint buf_left = buf_size;
  484. //if (m_len > cUINT16_MAX)
  485. // return -1;
  486. CRNLIB_ASSUME(sizeof(m_len) == sizeof(uint16));
  487. if (!utils::write_val((uint16)m_len, pBuf, buf_left, little_endian))
  488. return -1;
  489. if (buf_left < m_len)
  490. return -1;
  491. memcpy(pBuf, get_ptr(), m_len);
  492. buf_left -= m_len;
  493. return buf_size - buf_left;
  494. }
  495. int dynamic_string::deserialize(const void* pBuf, uint buf_size, bool little_endian)
  496. {
  497. uint buf_left = buf_size;
  498. if (buf_left < sizeof(uint16)) return -1;
  499. uint16 l;
  500. if (!utils::read_obj(l, pBuf, buf_left, little_endian))
  501. return -1;
  502. if (buf_left < l)
  503. return -1;
  504. set_from_buf(pBuf, l);
  505. buf_left -= l;
  506. return buf_size - buf_left;
  507. }
  508. void dynamic_string::translate_lf_to_crlf()
  509. {
  510. if (find_left(0x0A) < 0)
  511. return;
  512. dynamic_string tmp;
  513. tmp.ensure_buf(m_len + 2);
  514. // normal sequence is 0x0D 0x0A (CR LF, \r\n)
  515. int prev_char = -1;
  516. for (uint i = 0; i < get_len(); i++)
  517. {
  518. const int cur_char = (*this)[i];
  519. if ((cur_char == 0x0A) && (prev_char != 0x0D))
  520. tmp.append_char(0x0D);
  521. tmp.append_char(cur_char);
  522. prev_char = cur_char;
  523. }
  524. swap(tmp);
  525. }
  526. } // namespace crnlib