| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
- // File: crn_dynamic_string.cpp
- // See Copyright Notice and license at the end of inc/crnlib.h
- #include "crn_core.h"
- #include "crn_strutils.h"
- namespace crnlib
- {
- dynamic_string g_empty_dynamic_string;
- dynamic_string::dynamic_string(eVarArg dummy, const char* p, ...) :
- m_buf_size(0), m_len(0), m_pStr(NULL)
- {
- dummy;
- CRNLIB_ASSERT(p);
- va_list args;
- va_start(args, p);
- format_args(p, args);
- va_end(args);
- }
- dynamic_string::dynamic_string(const char* p) :
- m_buf_size(0), m_len(0), m_pStr(NULL)
- {
- CRNLIB_ASSERT(p);
- set(p);
- }
- dynamic_string::dynamic_string(const char* p, uint len) :
- m_buf_size(0), m_len(0), m_pStr(NULL)
- {
- CRNLIB_ASSERT(p);
- set_from_buf(p, len);
- }
- dynamic_string::dynamic_string(const dynamic_string& other) :
- m_buf_size(0), m_len(0), m_pStr(NULL)
- {
- set(other);
- }
- void dynamic_string::clear()
- {
- check();
- if (m_pStr)
- {
- crnlib_delete_array(m_pStr);
- m_pStr = NULL;
- m_len = 0;
- m_buf_size = 0;
- }
- }
- void dynamic_string::empty()
- {
- truncate(0);
- }
- void dynamic_string::optimize()
- {
- if (!m_len)
- clear();
- else
- {
- uint min_buf_size = math::next_pow2((uint)m_len + 1);
- if (m_buf_size > min_buf_size)
- {
- char* p = crnlib_new_array<char>(min_buf_size);
- memcpy(p, m_pStr, m_len + 1);
- crnlib_delete_array(m_pStr);
- m_pStr = p;
- m_buf_size = static_cast<uint16>(min_buf_size);
- check();
- }
- }
- }
- int dynamic_string::compare(const char* p, bool case_sensitive) const
- {
- CRNLIB_ASSERT(p);
- const int result = (case_sensitive ? strcmp : crn_stricmp)(get_ptr_priv(), p);
- if (result < 0)
- return -1;
- else if (result > 0)
- return 1;
- return 0;
- }
- int dynamic_string::compare(const dynamic_string& rhs, bool case_sensitive) const
- {
- return compare(rhs.get_ptr_priv(), case_sensitive);
- }
- dynamic_string& dynamic_string::set(const char* p, uint max_len)
- {
- CRNLIB_ASSERT(p);
- const uint len = math::minimum<uint>(max_len, static_cast<uint>(strlen(p)));
- CRNLIB_ASSERT(len < cUINT16_MAX);
- if ((!len) || (len >= cUINT16_MAX))
- clear();
- else if ((m_pStr) && (p >= m_pStr) && (p < (m_pStr + m_buf_size)))
- {
- if (m_pStr != p)
- memmove(m_pStr, p, len);
- m_pStr[len] = '\0';
- m_len = static_cast<uint16>(len);
- }
- else if (ensure_buf(len, false))
- {
- m_len = static_cast<uint16>(len);
- memcpy(m_pStr, p, m_len + 1);
- }
- check();
- return *this;
- }
- dynamic_string& dynamic_string::set(const dynamic_string& other, uint max_len)
- {
- if (this == &other)
- {
- if (max_len < m_len)
- {
- m_pStr[max_len] = '\0';
- m_len = static_cast<uint16>(max_len);
- }
- }
- else
- {
- const uint len = math::minimum<uint>(max_len, other.m_len);
- if (!len)
- clear();
- else if (ensure_buf(len, false))
- {
- m_len = static_cast<uint16>(len);
- memcpy(m_pStr, other.get_ptr_priv(), m_len);
- m_pStr[len] = '\0';
- }
- }
- check();
- return *this;
- }
- bool dynamic_string::set_len(uint new_len, char fill_char)
- {
- if ((new_len >= cUINT16_MAX) || (!fill_char))
- {
- CRNLIB_ASSERT(0);
- return false;
- }
- uint cur_len = m_len;
- if (ensure_buf(new_len, true))
- {
- if (new_len > cur_len)
- memset(m_pStr + cur_len, fill_char, new_len - cur_len);
- m_pStr[new_len] = 0;
- m_len = static_cast<uint16>(new_len);
- check();
- }
- return true;
- }
- dynamic_string& dynamic_string::set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_chars, uint len_in_chars)
- {
- CRNLIB_ASSERT(buf_size_in_chars <= cUINT16_MAX);
- CRNLIB_ASSERT(math::is_power_of_2(buf_size_in_chars) || (buf_size_in_chars == cUINT16_MAX));
- CRNLIB_ASSERT((len_in_chars + 1) <= buf_size_in_chars);
- clear();
- m_pStr = pBuf;
- m_buf_size = static_cast<uint16>(buf_size_in_chars);
- m_len = static_cast<uint16>(len_in_chars);
- check();
- return *this;
- }
- dynamic_string& dynamic_string::set_from_buf(const void* pBuf, uint buf_size)
- {
- CRNLIB_ASSERT(pBuf);
- if (buf_size >= cUINT16_MAX)
- {
- clear();
- return *this;
- }
- #ifdef CRNLIB_BUILD_DEBUG
- if ((buf_size) && (memchr(pBuf, 0, buf_size) != NULL))
- {
- CRNLIB_ASSERT(0);
- clear();
- return *this;
- }
- #endif
- if (ensure_buf(buf_size, false))
- {
- if (buf_size)
- memcpy(m_pStr, pBuf, buf_size);
- m_pStr[buf_size] = 0;
- m_len = static_cast<uint16>(buf_size);
- check();
- }
- return *this;
- }
- dynamic_string& dynamic_string::set_char(uint index, char c)
- {
- CRNLIB_ASSERT(index <= m_len);
- if (!c)
- truncate(index);
- else if (index < m_len)
- {
- m_pStr[index] = c;
- check();
- }
- else if (index == m_len)
- append_char(c);
- return *this;
- }
- dynamic_string& dynamic_string::append_char(char c)
- {
- if (ensure_buf(m_len + 1))
- {
- m_pStr[m_len] = c;
- m_pStr[m_len + 1] = '\0';
- m_len++;
- check();
- }
- return *this;
- }
- dynamic_string& dynamic_string::truncate(uint new_len)
- {
- if (new_len < m_len)
- {
- m_pStr[new_len] = '\0';
- m_len = static_cast<uint16>(new_len);
- check();
- }
- return *this;
- }
- dynamic_string& dynamic_string::tolower()
- {
- if (m_len)
- {
- #ifdef _MSC_VER
- _strlwr_s(get_ptr_priv(), m_buf_size);
- #else
- strlwr(get_ptr_priv());
- #endif
- }
- return *this;
- }
- dynamic_string& dynamic_string::toupper()
- {
- if (m_len)
- {
- #ifdef _MSC_VER
- _strupr_s(get_ptr_priv(), m_buf_size);
- #else
- strupr(get_ptr_priv());
- #endif
- }
- return *this;
- }
- dynamic_string& dynamic_string::append(const char* p)
- {
- CRNLIB_ASSERT(p);
- uint len = static_cast<uint>(strlen(p));
- uint new_total_len = m_len + len;
- if ((new_total_len) && ensure_buf(new_total_len))
- {
- memcpy(m_pStr + m_len, p, len + 1);
- m_len = static_cast<uint16>(m_len + len);
- check();
- }
- return *this;
- }
- dynamic_string& dynamic_string::append(const dynamic_string& other)
- {
- uint len = other.m_len;
- uint new_total_len = m_len + len;
- if ((new_total_len) && ensure_buf(new_total_len))
- {
- memcpy(m_pStr + m_len, other.get_ptr_priv(), len + 1);
- m_len = static_cast<uint16>(m_len + len);
- check();
- }
- return *this;
- }
- dynamic_string operator+ (const char* p, const dynamic_string& a)
- {
- return dynamic_string(p).append(a);
- }
- dynamic_string operator+ (const dynamic_string& a, const char* p)
- {
- return dynamic_string(a).append(p);
- }
- dynamic_string operator+ (const dynamic_string& a, const dynamic_string& b)
- {
- return dynamic_string(a).append(b);
- }
- dynamic_string& dynamic_string::format_args(const char* p, va_list args)
- {
- CRNLIB_ASSERT(p);
- const uint cBufSize = 4096;
- char buf[cBufSize];
- #ifdef _MSC_VER
- int l = vsnprintf_s(buf, cBufSize, _TRUNCATE, p, args);
- #else
- int l = vsnprintf(buf, cBufSize, p, args);
- #endif
- if (l <= 0)
- clear();
- else if (ensure_buf(l, false))
- {
- memcpy(m_pStr, buf, l + 1);
- m_len = static_cast<uint16>(l);
- check();
- }
- return *this;
- }
- dynamic_string& dynamic_string::format(const char* p, ...)
- {
- CRNLIB_ASSERT(p);
- va_list args;
- va_start(args, p);
- format_args(p, args);
- va_end(args);
- return *this;
- }
- dynamic_string& dynamic_string::crop(uint start, uint len)
- {
- if (start >= m_len)
- {
- clear();
- return *this;
- }
- len = math::minimum<uint>(len, m_len - start);
- if (start)
- memmove(get_ptr_priv(), get_ptr_priv() + start, len);
- m_pStr[len] = '\0';
- m_len = static_cast<uint16>(len);
- check();
- return *this;
- }
- dynamic_string& dynamic_string::substring(uint start, uint end)
- {
- CRNLIB_ASSERT(start <= end);
- if (start > end)
- return *this;
- return crop(start, end - start);
- }
- dynamic_string& dynamic_string::left(uint len)
- {
- return substring(0, len);
- }
- dynamic_string& dynamic_string::mid(uint start, uint len)
- {
- return crop(start, len);
- }
- dynamic_string& dynamic_string::right(uint start)
- {
- return substring(start, get_len());
- }
- dynamic_string& dynamic_string::tail(uint num)
- {
- return substring(math::maximum<int>(static_cast<int>(get_len()) - static_cast<int>(num), 0), get_len());
- }
- dynamic_string& dynamic_string::unquote()
- {
- if (m_len >= 2)
- {
- if ( ((*this)[0] == '\"') && ((*this)[m_len - 1] == '\"') )
- {
- return mid(1, m_len - 2);
- }
- }
- return *this;
- }
- int dynamic_string::find_left(const char* p, bool case_sensitive) const
- {
- CRNLIB_ASSERT(p);
- const int p_len = (int)strlen(p);
- for (int i = 0; i <= (m_len - p_len); i++)
- if ((case_sensitive ? strncmp : _strnicmp)(p, &m_pStr[i], p_len) == 0)
- return i;
- return -1;
- }
- bool dynamic_string::contains(const char* p, bool case_sensitive) const
- {
- return find_left(p, case_sensitive) >= 0;
- }
- uint dynamic_string::count_char(char c) const
- {
- uint count = 0;
- for (uint i = 0; i < m_len; i++)
- if (m_pStr[i] == c)
- count++;
- return count;
- }
- int dynamic_string::find_left(char c) const
- {
- for (uint i = 0; i < m_len; i++)
- if (m_pStr[i] == c)
- return i;
- return -1;
- }
- int dynamic_string::find_right(char c) const
- {
- for (int i = (int)m_len - 1; i >= 0; i--)
- if (m_pStr[i] == c)
- return i;
- return -1;
- }
- int dynamic_string::find_right(const char* p, bool case_sensitive) const
- {
- CRNLIB_ASSERT(p);
- const int p_len = (int)strlen(p);
- for (int i = m_len - p_len; i >= 0; i--)
- if ((case_sensitive ? strncmp : _strnicmp)(p, &m_pStr[i], p_len) == 0)
- return i;
- return -1;
- }
- dynamic_string& dynamic_string::trim()
- {
- int s, e;
- for (s = 0; s < (int)m_len; s++)
- if (!isspace(m_pStr[s]))
- break;
- for (e = m_len - 1; e > s; e--)
- if (!isspace(m_pStr[e]))
- break;
- return crop(s, e - s + 1);
- }
- dynamic_string& dynamic_string::trim_crlf()
- {
- int s = 0, e;
- for (e = m_len - 1; e > s; e--)
- if ((m_pStr[e] != 13) && (m_pStr[e] != 10))
- break;
- return crop(s, e - s + 1);
- }
- dynamic_string& dynamic_string::remap(int from_char, int to_char)
- {
- for (uint i = 0; i < m_len; i++)
- if (m_pStr[i] == from_char)
- m_pStr[i] = (char)to_char;
- return *this;
- }
- #ifdef CRNLIB_BUILD_DEBUG
- void dynamic_string::check() const
- {
- if (!m_pStr)
- {
- CRNLIB_ASSERT(!m_buf_size && !m_len);
- }
- else
- {
- CRNLIB_ASSERT(m_buf_size);
- CRNLIB_ASSERT((m_buf_size == cUINT16_MAX) || math::is_power_of_2((uint32)m_buf_size));
- CRNLIB_ASSERT(m_len < m_buf_size);
- CRNLIB_ASSERT(!m_pStr[m_len]);
- #if CRNLIB_SLOW_STRING_LEN_CHECKS
- CRNLIB_ASSERT(strlen(m_pStr) == m_len);
- #endif
- }
- }
- #endif
- bool dynamic_string::ensure_buf(uint len, bool preserve_contents)
- {
- uint buf_size_needed = len + 1;
- CRNLIB_ASSERT(buf_size_needed <= cUINT16_MAX);
- if (buf_size_needed <= cUINT16_MAX)
- {
- if (buf_size_needed > m_buf_size)
- expand_buf(buf_size_needed, preserve_contents);
- }
- return m_buf_size >= buf_size_needed;
- }
- bool dynamic_string::expand_buf(uint new_buf_size, bool preserve_contents)
- {
- new_buf_size = math::minimum<uint>(cUINT16_MAX, math::next_pow2(math::maximum<uint>(m_buf_size, new_buf_size)));
- if (new_buf_size != m_buf_size)
- {
- char* p = crnlib_new_array<char>(new_buf_size);
- if (preserve_contents)
- memcpy(p, get_ptr_priv(), m_len + 1);
- crnlib_delete_array(m_pStr);
- m_pStr = p;
- m_buf_size = static_cast<uint16>(new_buf_size);
- if (preserve_contents)
- check();
- }
- return m_buf_size >= new_buf_size;
- }
- void dynamic_string::swap(dynamic_string& other)
- {
- utils::swap(other.m_buf_size, m_buf_size);
- utils::swap(other.m_len, m_len);
- utils::swap(other.m_pStr, m_pStr);
- }
- int dynamic_string::serialize(void* pBuf, uint buf_size, bool little_endian) const
- {
- uint buf_left = buf_size;
- //if (m_len > cUINT16_MAX)
- // return -1;
- CRNLIB_ASSUME(sizeof(m_len) == sizeof(uint16));
- if (!utils::write_val((uint16)m_len, pBuf, buf_left, little_endian))
- return -1;
- if (buf_left < m_len)
- return -1;
- memcpy(pBuf, get_ptr(), m_len);
- buf_left -= m_len;
- return buf_size - buf_left;
- }
- int dynamic_string::deserialize(const void* pBuf, uint buf_size, bool little_endian)
- {
- uint buf_left = buf_size;
- if (buf_left < sizeof(uint16)) return -1;
- uint16 l;
- if (!utils::read_obj(l, pBuf, buf_left, little_endian))
- return -1;
- if (buf_left < l)
- return -1;
- set_from_buf(pBuf, l);
- buf_left -= l;
- return buf_size - buf_left;
- }
- void dynamic_string::translate_lf_to_crlf()
- {
- if (find_left(0x0A) < 0)
- return;
- dynamic_string tmp;
- tmp.ensure_buf(m_len + 2);
- // normal sequence is 0x0D 0x0A (CR LF, \r\n)
- int prev_char = -1;
- for (uint i = 0; i < get_len(); i++)
- {
- const int cur_char = (*this)[i];
- if ((cur_char == 0x0A) && (prev_char != 0x0D))
- tmp.append_char(0x0D);
- tmp.append_char(cur_char);
- prev_char = cur_char;
- }
- swap(tmp);
- }
- } // namespace crnlib
|