// This is a private method; ensure FixHeader is called (or used_ is well defined) // beforehand char* STRING::ensure_cstr(inT32 min_capacity) { STRING_HEADER* orig_header = GetHeader(); if (min_capacity <= orig_header->capacity_) return ((char *)this->data_) + sizeof(STRING_HEADER); // if we are going to grow bigger, than double our existing // size, but if that still is not big enough then keep the // requested capacity if (min_capacity < 2 * orig_header->capacity_) min_capacity = 2 * orig_header->capacity_; int alloc = sizeof(STRING_HEADER) + min_capacity; STRING_HEADER* new_header = (STRING_HEADER*)(alloc_string(alloc)); memcpy(&new_header[1], GetCStr(), orig_header->used_); new_header->capacity_ = min_capacity; new_header->used_ = orig_header->used_; // free old memory, then rebind to new memory DiscardData(); data_ = new_header; assert(InvariantOk()); return ((char *)data_) + sizeof(STRING_HEADER); }
void String::Write(Stream *out) const { if (out) { out->Write(GetCStr(), GetLength() + 1); } }
int String::CompareRightNoCase(const char *cstr, size_t count) const { cstr = cstr ? cstr : ""; count = count != -1 ? count : strlen(cstr); size_t off = Math::Min(GetLength(), count); return strnicmp(GetCStr() + GetLength() - off, cstr, count); }
int String::CompareRightNoCase(const char *cstr, int count) const { int cstr_len = cstr ? strlen(cstr) : 0; count = count >= 0 ? count : cstr_len; int from = Math::Max(0, GetLength() - count); return strnicmp(GetCStr() + from, cstr ? cstr : "", count); }
int String::CompareMid(const char *cstr, int from, int count) const { int cstr_len = cstr ? strlen(cstr) : 0; count = count >= 0 ? count : cstr_len; from = Math::Min(from, GetLength()); return strncmp(GetCStr() + from, cstr ? cstr : "", count); }
void STRING::erase_range(inT32 index, int len) { char* this_cstr = GetCStr(); STRING_HEADER* this_header = GetHeader(); memcpy(this_cstr+index, this_cstr+index+len, this_header->used_ - index - len); this_header->used_ -= len; assert(InvariantOk()); }
// Reads from the given file. Returns false in case of error. // If swap is true, assumes a big/little-endian swap is needed. bool STRING::DeSerialize(bool swap, FILE* fp) { inT32 len; if (fread(&len, sizeof(len), 1, fp) != 1) return false; if (swap) ReverseN(&len, sizeof(len)); truncate_at(len); if (fread(GetCStr(), 1, len, fp) != len) return false; return true; }
char* STRING::AllocData(int used, int capacity) { data_ = (STRING_HEADER *)alloc_string(capacity + sizeof(STRING_HEADER)); // header is the metadata for this memory block STRING_HEADER* header = GetHeader(); header->capacity_ = capacity; header->used_ = used; return GetCStr(); }
void STRING::split(const char c, GenericVector<STRING> *splited) { int start_index = 0; for (int i = 0; i < length(); i++) { if ((*this)[i] == c) { if (i != start_index) { (*this)[i] = '\0'; STRING tmp = GetCStr() + start_index; splited->push_back(tmp); (*this)[i] = c; } start_index = i + 1; } } if (length() != start_index) { STRING tmp = GetCStr() + start_index; splited->push_back(tmp); } }
const char* STRING::string() const { const STRING_HEADER* header = GetHeader(); if (header->used_ == 0) return NULL; // mark header length unreliable because tesseract might // cast away the const and mutate the string directly. header->used_ = -1; return GetCStr(); }
BOOL8 STRING::operator!=(const STRING& str) const { FixHeader(); str.FixHeader(); const STRING_HEADER* str_header = str.GetHeader(); const STRING_HEADER* this_header = GetHeader(); int this_used = this_header->used_; int str_used = str_header->used_; return (this_used != str_used) || (memcmp(GetCStr(), str.GetCStr(), this_used) != 0); }
BOOL8 STRING::operator!=(const char* cstr) const { FixHeader(); const STRING_HEADER* this_header = GetHeader(); if (cstr == NULL) return this_header->used_ > 1; // either '\0' or NULL else { inT32 length = strlen(cstr) + 1; return (this_header->used_ != length) || (memcmp(GetCStr(), cstr, length) != 0); } }
void String::WriteCount(Stream *out, size_t count) const { if (out) { size_t str_out_len = Math::Min(count - 1, GetLength()); if (str_out_len > 0) out->Write(GetCStr(), str_out_len); size_t null_out_len = count - str_out_len; if (null_out_len > 0) out->WriteByteCount(0, null_out_len); } }
int Lower(oms::State *state) { oms::StackAPI api(state); if (!api.CheckArgs(1, oms::ValueT_String)) return 0; auto str = api.GetString(0); auto size = str->GetLength(); auto c_str = reinterpret_cast<const unsigned char *>(str->GetCStr()); std::string lower; lower.reserve(size); for (std::size_t i = 0; i < size; ++i) lower.push_back(std::tolower(c_str[i])); api.PushString(lower); return 1; }
int Reverse(oms::State *state) { oms::StackAPI api(state); if (!api.CheckArgs(1, oms::ValueT_String)) return 0; auto str = api.GetString(0); auto size = str->GetLength(); auto c_str = str->GetCStr(); std::string reverse; reverse.reserve(size); for (; size > 0; --size) reverse.push_back(c_str[size - 1]); api.PushString(reverse); return 1; }
STRING STRING::operator+(const char ch) const { STRING result; FixHeader(); const STRING_HEADER* this_header = GetHeader(); int this_used = this_header->used_; char* result_cstr = result.ensure_cstr(this_used + 1); STRING_HEADER* result_header = result.GetHeader(); int result_used = result_header->used_; // copies '\0' but we'll overwrite that memcpy(result_cstr, GetCStr(), this_used); result_cstr[result_used] = ch; // overwrite old '\0' result_cstr[result_used + 1] = '\0'; // append on '\0' ++result_header->used_; assert(InvariantOk()); return result; }
int Sub(oms::State *state) { oms::StackAPI api(state); if (!api.CheckArgs(2, oms::ValueT_String, oms::ValueT_Number, oms::ValueT_Number)) return 0; auto str = api.GetString(0); int size = str->GetLength(); auto c_str = str->GetCStr(); auto start = static_cast<int>(api.GetNumber(1)); auto end = size; auto params = api.GetStackSize(); if (params <= 2) { if (start == 0) { start = 1; } else if (start < 0) { start += size; start = start < 0 ? 1 : start + 1; } } else { start = start == 0 ? 1 : std::abs(start); end = std::abs(static_cast<int>(api.GetNumber(2))); end = std::min(end, size); } std::string sub; for (int i = start; i <= end; ++i) sub.push_back(c_str[i - 1]); api.PushString(sub); return 1; }
String String::Mid(size_t from, size_t count) const { Math::ClampLength((size_t)0, GetLength(), from, count); return count == GetLength() ? *this : String(GetCStr() + from, count); }
String String::Right(size_t count) const { count = Math::Min(count, GetLength()); return count == GetLength() ? *this : String(GetCStr() + GetLength() - count, count); }
// Writes to the given file. Returns false in case of error. bool STRING::Serialize(FILE* fp) const { inT32 len = length(); if (fwrite(&len, sizeof(len), 1, fp) != 1) return false; if (fwrite(GetCStr(), 1, len, fp) != len) return false; return true; }
int String::ToInt() const { return atoi(GetCStr()); }
int String::CompareLeftNoCase(const char *cstr, size_t count) const { cstr = cstr ? cstr : ""; return strnicmp(GetCStr(), cstr, count != -1 ? count : strlen(cstr)); }
int String::CompareMidNoCase(const char *cstr, size_t from, size_t count) const { cstr = cstr ? cstr : ""; from = Math::Min(from, GetLength()); return strnicmp(GetCStr() + from, cstr, count != -1 ? count : strlen(cstr)); }
BOOL8 STRING::contains(const char c) const { return (c != '\0') && (strchr (GetCStr(), c) != NULL); }
int String::CompareNoCase(const char *cstr) const { return stricmp(GetCStr(), cstr ? cstr : ""); }
const char& STRING::operator[](inT32 index) const { return GetCStr()[index]; }
template<class A, class B, class C> wxString BuildPath(const A&a, const B&b, const C&c) { return BuildPath(BuildPath(GetCStr(a), GetCStr(b)), GetCStr(c)); }
template<class A, class B> wxString BuildPath(const A&a, const B&b) { return BuildPathWorker(GetCStr(a), GetCStr(b)); }
// This is const, but is modifying a mutable field // this way it can be used on const or non-const instances. void STRING::FixHeader() const { const STRING_HEADER* header = GetHeader(); if (header->used_ < 0) header->used_ = strlen(GetCStr()) + 1; }
char& STRING::operator[](inT32 index) const { // Code is casting away this const and mutating the string, // so mark used_ as -1 to flag it unreliable. GetHeader()->used_ = -1; return ((char *)GetCStr())[index]; }