/src/icu/source/common/charstr.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
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 <cstdlib>  | 
18  |  |  | 
19  |  | #include "unicode/utypes.h"  | 
20  |  | #include "unicode/putil.h"  | 
21  |  | #include "charstr.h"  | 
22  |  | #include "cmemory.h"  | 
23  |  | #include "cstring.h"  | 
24  |  | #include "uinvchar.h"  | 
25  |  | #include "ustr_imp.h"  | 
26  |  |  | 
27  |  | U_NAMESPACE_BEGIN  | 
28  |  |  | 
29  |  | CharString::CharString(CharString&& src) U_NOEXCEPT  | 
30  | 0  |         : buffer(std::move(src.buffer)), len(src.len) { | 
31  | 0  |     src.len = 0;  // not strictly necessary because we make no guarantees on the source string  | 
32  | 0  | }  | 
33  |  |  | 
34  | 0  | CharString& CharString::operator=(CharString&& src) U_NOEXCEPT { | 
35  | 0  |     buffer = std::move(src.buffer);  | 
36  | 0  |     len = src.len;  | 
37  | 0  |     src.len = 0;  // not strictly necessary because we make no guarantees on the source string  | 
38  | 0  |     return *this;  | 
39  | 0  | }  | 
40  |  |  | 
41  | 0  | char *CharString::cloneData(UErrorCode &errorCode) const { | 
42  | 0  |     if (U_FAILURE(errorCode)) { return nullptr; } | 
43  | 0  |     char *p = static_cast<char *>(uprv_malloc(len + 1));  | 
44  | 0  |     if (p == nullptr) { | 
45  | 0  |         errorCode = U_MEMORY_ALLOCATION_ERROR;  | 
46  | 0  |         return nullptr;  | 
47  | 0  |     }  | 
48  | 0  |     uprv_memcpy(p, buffer.getAlias(), len + 1);  | 
49  | 0  |     return p;  | 
50  | 0  | }  | 
51  |  |  | 
52  | 0  | int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const { | 
53  | 0  |     if (U_FAILURE(errorCode)) { return len; } | 
54  | 0  |     if (capacity < 0 || (capacity > 0 && dest == nullptr)) { | 
55  | 0  |         errorCode = U_ILLEGAL_ARGUMENT_ERROR;  | 
56  | 0  |         return len;  | 
57  | 0  |     }  | 
58  | 0  |     const char *src = buffer.getAlias();  | 
59  | 0  |     if (0 < len && len <= capacity && src != dest) { | 
60  | 0  |         uprv_memcpy(dest, src, len);  | 
61  | 0  |     }  | 
62  | 0  |     return u_terminateChars(dest, capacity, len, &errorCode);  | 
63  | 0  | }  | 
64  |  |  | 
65  | 0  | CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) { | 
66  | 0  |     if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) { | 
67  | 0  |         len=s.len;  | 
68  | 0  |         uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);  | 
69  | 0  |     }  | 
70  | 0  |     return *this;  | 
71  | 0  | }  | 
72  |  |  | 
73  | 0  | int32_t CharString::lastIndexOf(char c) const { | 
74  | 0  |     for(int32_t i=len; i>0;) { | 
75  | 0  |         if(buffer[--i]==c) { | 
76  | 0  |             return i;  | 
77  | 0  |         }  | 
78  | 0  |     }  | 
79  | 0  |     return -1;  | 
80  | 0  | }  | 
81  |  |  | 
82  | 0  | bool CharString::contains(StringPiece s) const { | 
83  | 0  |     if (s.empty()) { return false; } | 
84  | 0  |     const char *p = buffer.getAlias();  | 
85  | 0  |     int32_t lastStart = len - s.length();  | 
86  | 0  |     for (int32_t i = 0; i <= lastStart; ++i) { | 
87  | 0  |         if (uprv_memcmp(p + i, s.data(), s.length()) == 0) { | 
88  | 0  |             return true;  | 
89  | 0  |         }  | 
90  | 0  |     }  | 
91  | 0  |     return false;  | 
92  | 0  | }  | 
93  |  |  | 
94  | 0  | CharString &CharString::truncate(int32_t newLength) { | 
95  | 0  |     if(newLength<0) { | 
96  | 0  |         newLength=0;  | 
97  | 0  |     }  | 
98  | 0  |     if(newLength<len) { | 
99  | 0  |         buffer[len=newLength]=0;  | 
100  | 0  |     }  | 
101  | 0  |     return *this;  | 
102  | 0  | }  | 
103  |  |  | 
104  | 0  | CharString &CharString::append(char c, UErrorCode &errorCode) { | 
105  | 0  |     if(ensureCapacity(len+2, 0, errorCode)) { | 
106  | 0  |         buffer[len++]=c;  | 
107  | 0  |         buffer[len]=0;  | 
108  | 0  |     }  | 
109  | 0  |     return *this;  | 
110  | 0  | }  | 
111  |  |  | 
112  | 0  | CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) { | 
113  | 0  |     if(U_FAILURE(errorCode)) { | 
114  | 0  |         return *this;  | 
115  | 0  |     }  | 
116  | 0  |     if(sLength<-1 || (s==NULL && sLength!=0)) { | 
117  | 0  |         errorCode=U_ILLEGAL_ARGUMENT_ERROR;  | 
118  | 0  |         return *this;  | 
119  | 0  |     }  | 
120  | 0  |     if(sLength<0) { | 
121  | 0  |         sLength= static_cast<int32_t>(uprv_strlen(s));  | 
122  | 0  |     }  | 
123  | 0  |     if(sLength>0) { | 
124  | 0  |         if(s==(buffer.getAlias()+len)) { | 
125  |  |             // The caller wrote into the getAppendBuffer().  | 
126  | 0  |             if(sLength>=(buffer.getCapacity()-len)) { | 
127  |  |                 // The caller wrote too much.  | 
128  | 0  |                 errorCode=U_INTERNAL_PROGRAM_ERROR;  | 
129  | 0  |             } else { | 
130  | 0  |                 buffer[len+=sLength]=0;  | 
131  | 0  |             }  | 
132  | 0  |         } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&  | 
133  | 0  |                   sLength>=(buffer.getCapacity()-len)  | 
134  | 0  |         ) { | 
135  |  |             // (Part of) this string is appended to itself which requires reallocation,  | 
136  |  |             // so we have to make a copy of the substring and append that.  | 
137  | 0  |             return append(CharString(s, sLength, errorCode), errorCode);  | 
138  | 0  |         } else if(ensureCapacity(len+sLength+1, 0, errorCode)) { | 
139  | 0  |             uprv_memcpy(buffer.getAlias()+len, s, sLength);  | 
140  | 0  |             buffer[len+=sLength]=0;  | 
141  | 0  |         }  | 
142  | 0  |     }  | 
143  | 0  |     return *this;  | 
144  | 0  | }  | 
145  |  |  | 
146  | 0  | CharString &CharString::appendNumber(int32_t number, UErrorCode &status) { | 
147  | 0  |     if (number < 0) { | 
148  | 0  |         this->append('-', status); | 
149  | 0  |         if (U_FAILURE(status)) { | 
150  | 0  |             return *this;  | 
151  | 0  |         }  | 
152  | 0  |     }  | 
153  |  |  | 
154  | 0  |     if (number == 0) { | 
155  | 0  |         this->append('0', status); | 
156  | 0  |         return *this;  | 
157  | 0  |     }  | 
158  |  |  | 
159  | 0  |     int32_t numLen = 0;  | 
160  | 0  |     while (number != 0) { | 
161  | 0  |         int32_t residue = number % 10;  | 
162  | 0  |         number /= 10;  | 
163  | 0  |         this->append(std::abs(residue) + '0', status);  | 
164  | 0  |         numLen++;  | 
165  | 0  |         if (U_FAILURE(status)) { | 
166  | 0  |             return *this;  | 
167  | 0  |         }  | 
168  | 0  |     }  | 
169  |  |  | 
170  | 0  |     int32_t start = this->length() - numLen, end = this->length() - 1;  | 
171  | 0  |     while(start < end) { | 
172  | 0  |         std::swap(this->data()[start++], this->data()[end--]);  | 
173  | 0  |     }  | 
174  |  | 
  | 
175  | 0  |     return *this;  | 
176  | 0  | }  | 
177  |  |  | 
178  |  | char *CharString::getAppendBuffer(int32_t minCapacity,  | 
179  |  |                                   int32_t desiredCapacityHint,  | 
180  |  |                                   int32_t &resultCapacity,  | 
181  | 0  |                                   UErrorCode &errorCode) { | 
182  | 0  |     if(U_FAILURE(errorCode)) { | 
183  | 0  |         resultCapacity=0;  | 
184  | 0  |         return NULL;  | 
185  | 0  |     }  | 
186  | 0  |     int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL  | 
187  | 0  |     if(appendCapacity>=minCapacity) { | 
188  | 0  |         resultCapacity=appendCapacity;  | 
189  | 0  |         return buffer.getAlias()+len;  | 
190  | 0  |     }  | 
191  | 0  |     if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) { | 
192  | 0  |         resultCapacity=buffer.getCapacity()-len-1;  | 
193  | 0  |         return buffer.getAlias()+len;  | 
194  | 0  |     }  | 
195  | 0  |     resultCapacity=0;  | 
196  | 0  |     return NULL;  | 
197  | 0  | }  | 
198  |  |  | 
199  | 0  | CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) { | 
200  | 0  |     return appendInvariantChars(s.getBuffer(), s.length(), errorCode);  | 
201  | 0  | }  | 
202  |  |  | 
203  | 0  | CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) { | 
204  | 0  |     if(U_FAILURE(errorCode)) { | 
205  | 0  |         return *this;  | 
206  | 0  |     }  | 
207  | 0  |     if (!uprv_isInvariantUString(uchars, ucharsLen)) { | 
208  | 0  |         errorCode = U_INVARIANT_CONVERSION_ERROR;  | 
209  | 0  |         return *this;  | 
210  | 0  |     }  | 
211  | 0  |     if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) { | 
212  | 0  |         u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);  | 
213  | 0  |         len += ucharsLen;  | 
214  | 0  |         buffer[len] = 0;  | 
215  | 0  |     }  | 
216  | 0  |     return *this;  | 
217  | 0  | }  | 
218  |  |  | 
219  |  | UBool CharString::ensureCapacity(int32_t capacity,  | 
220  |  |                                  int32_t desiredCapacityHint,  | 
221  | 0  |                                  UErrorCode &errorCode) { | 
222  | 0  |     if(U_FAILURE(errorCode)) { | 
223  | 0  |         return FALSE;  | 
224  | 0  |     }  | 
225  | 0  |     if(capacity>buffer.getCapacity()) { | 
226  | 0  |         if(desiredCapacityHint==0) { | 
227  | 0  |             desiredCapacityHint=capacity+buffer.getCapacity();  | 
228  | 0  |         }  | 
229  | 0  |         if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&  | 
230  | 0  |             buffer.resize(capacity, len+1)==NULL  | 
231  | 0  |         ) { | 
232  | 0  |             errorCode=U_MEMORY_ALLOCATION_ERROR;  | 
233  | 0  |             return FALSE;  | 
234  | 0  |         }  | 
235  | 0  |     }  | 
236  | 0  |     return TRUE;  | 
237  | 0  | }  | 
238  |  |  | 
239  | 0  | CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) { | 
240  | 0  |     if(U_FAILURE(errorCode)) { | 
241  | 0  |         return *this;  | 
242  | 0  |     }  | 
243  | 0  |     if(s.length()==0) { | 
244  | 0  |         return *this;  | 
245  | 0  |     }  | 
246  | 0  |     char c;  | 
247  | 0  |     if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) { | 
248  | 0  |         append(getDirSepChar(), errorCode);  | 
249  | 0  |     }  | 
250  | 0  |     append(s, errorCode);  | 
251  | 0  |     return *this;  | 
252  | 0  | }  | 
253  |  |  | 
254  | 0  | CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) { | 
255  | 0  |     char c;  | 
256  | 0  |     if(U_SUCCESS(errorCode) && len>0 &&  | 
257  | 0  |             (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) { | 
258  | 0  |         append(getDirSepChar(), errorCode);  | 
259  | 0  |     }  | 
260  | 0  |     return *this;  | 
261  | 0  | }  | 
262  |  |  | 
263  | 0  | char CharString::getDirSepChar() const { | 
264  | 0  |     char dirSepChar = U_FILE_SEP_CHAR;  | 
265  |  | #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)  | 
266  |  |     // We may need to return a different directory separator when building for Cygwin or MSYS2.  | 
267  |  |     if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))  | 
268  |  |         dirSepChar = U_FILE_ALT_SEP_CHAR;  | 
269  |  | #endif  | 
270  | 0  |     return dirSepChar;  | 
271  | 0  | }  | 
272  |  |  | 
273  |  | U_NAMESPACE_END  |