1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5* Copyright (C) 2010-2015, International Business Machines
6* Corporation and others. All Rights Reserved.
7*******************************************************************************
8* file name: charstr.cpp
9* encoding: UTF-8
10* tab size: 8 (not used)
11* indentation:4
12*
13* created on: 2010may19
14* created by: Markus W. Scherer
15*/
16
17#include "unicode/utypes.h"
18#include "unicode/putil.h"
19#include "charstr.h"
20#include "cmemory.h"
21#include "cstring.h"
22#include "uinvchar.h"
23
24U_NAMESPACE_BEGIN
25
26CharString::CharString(CharString&& src) U_NOEXCEPT
27 : buffer(std::move(src.buffer)), len(src.len) {
28 src.len = 0; // not strictly necessary because we make no guarantees on the source string
29}
30
31CharString& CharString::operator=(CharString&& src) U_NOEXCEPT {
32 buffer = std::move(src.buffer);
33 len = src.len;
34 src.len = 0; // not strictly necessary because we make no guarantees on the source string
35 return *this;
36}
37
38char *CharString::cloneData(UErrorCode &errorCode) const {
39 if (U_FAILURE(errorCode)) { return nullptr; }
40 char *p = static_cast<char *>(uprv_malloc(len + 1));
41 if (p == nullptr) {
42 errorCode = U_MEMORY_ALLOCATION_ERROR;
43 return nullptr;
44 }
45 uprv_memcpy(p, buffer.getAlias(), len + 1);
46 return p;
47}
48
49CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
50 if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
51 len=s.len;
52 uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
53 }
54 return *this;
55}
56
57int32_t CharString::lastIndexOf(char c) const {
58 for(int32_t i=len; i>0;) {
59 if(buffer[--i]==c) {
60 return i;
61 }
62 }
63 return -1;
64}
65
66bool CharString::contains(StringPiece s) const {
67 if (s.empty()) { return false; }
68 const char *p = buffer.getAlias();
69 int32_t lastStart = len - s.length();
70 for (int32_t i = 0; i <= lastStart; ++i) {
71 if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
72 return true;
73 }
74 }
75 return false;
76}
77
78CharString &CharString::truncate(int32_t newLength) {
79 if(newLength<0) {
80 newLength=0;
81 }
82 if(newLength<len) {
83 buffer[len=newLength]=0;
84 }
85 return *this;
86}
87
88CharString &CharString::append(char c, UErrorCode &errorCode) {
89 if(ensureCapacity(len+2, 0, errorCode)) {
90 buffer[len++]=c;
91 buffer[len]=0;
92 }
93 return *this;
94}
95
96CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
97 if(U_FAILURE(errorCode)) {
98 return *this;
99 }
100 if(sLength<-1 || (s==NULL && sLength!=0)) {
101 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
102 return *this;
103 }
104 if(sLength<0) {
105 sLength= static_cast<int32_t>(uprv_strlen(s));
106 }
107 if(sLength>0) {
108 if(s==(buffer.getAlias()+len)) {
109 // The caller wrote into the getAppendBuffer().
110 if(sLength>=(buffer.getCapacity()-len)) {
111 // The caller wrote too much.
112 errorCode=U_INTERNAL_PROGRAM_ERROR;
113 } else {
114 buffer[len+=sLength]=0;
115 }
116 } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
117 sLength>=(buffer.getCapacity()-len)
118 ) {
119 // (Part of) this string is appended to itself which requires reallocation,
120 // so we have to make a copy of the substring and append that.
121 return append(CharString(s, sLength, errorCode), errorCode);
122 } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
123 uprv_memcpy(buffer.getAlias()+len, s, sLength);
124 buffer[len+=sLength]=0;
125 }
126 }
127 return *this;
128}
129
130char *CharString::getAppendBuffer(int32_t minCapacity,
131 int32_t desiredCapacityHint,
132 int32_t &resultCapacity,
133 UErrorCode &errorCode) {
134 if(U_FAILURE(errorCode)) {
135 resultCapacity=0;
136 return NULL;
137 }
138 int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL
139 if(appendCapacity>=minCapacity) {
140 resultCapacity=appendCapacity;
141 return buffer.getAlias()+len;
142 }
143 if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
144 resultCapacity=buffer.getCapacity()-len-1;
145 return buffer.getAlias()+len;
146 }
147 resultCapacity=0;
148 return NULL;
149}
150
151CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
152 return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
153}
154
155CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
156 if(U_FAILURE(errorCode)) {
157 return *this;
158 }
159 if (!uprv_isInvariantUString(uchars, ucharsLen)) {
160 errorCode = U_INVARIANT_CONVERSION_ERROR;
161 return *this;
162 }
163 if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
164 u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
165 len += ucharsLen;
166 buffer[len] = 0;
167 }
168 return *this;
169}
170
171UBool CharString::ensureCapacity(int32_t capacity,
172 int32_t desiredCapacityHint,
173 UErrorCode &errorCode) {
174 if(U_FAILURE(errorCode)) {
175 return FALSE;
176 }
177 if(capacity>buffer.getCapacity()) {
178 if(desiredCapacityHint==0) {
179 desiredCapacityHint=capacity+buffer.getCapacity();
180 }
181 if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
182 buffer.resize(capacity, len+1)==NULL
183 ) {
184 errorCode=U_MEMORY_ALLOCATION_ERROR;
185 return FALSE;
186 }
187 }
188 return TRUE;
189}
190
191CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
192 if(U_FAILURE(errorCode)) {
193 return *this;
194 }
195 if(s.length()==0) {
196 return *this;
197 }
198 char c;
199 if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
200 append(U_FILE_SEP_CHAR, errorCode);
201 }
202 append(s, errorCode);
203 return *this;
204}
205
206CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
207 char c;
208 if(U_SUCCESS(errorCode) && len>0 &&
209 (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
210 append(U_FILE_SEP_CHAR, errorCode);
211 }
212 return *this;
213}
214
215U_NAMESPACE_END
216