Imported Upstream version 58.1
[platform/upstream/icu.git] / source / common / charstr.cpp
1 // Copyright (C) 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:   US-ASCII
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 "charstr.h"
19 #include "cmemory.h"
20 #include "cstring.h"
21 #include "uinvchar.h"
22
23 U_NAMESPACE_BEGIN
24
25 CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
26     if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
27         len=s.len;
28         uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
29     }
30     return *this;
31 }
32
33 int32_t CharString::lastIndexOf(char c) const {
34     for(int32_t i=len; i>0;) {
35         if(buffer[--i]==c) {
36             return i;
37         }
38     }
39     return -1;
40 }
41
42 CharString &CharString::truncate(int32_t newLength) {
43     if(newLength<0) {
44         newLength=0;
45     }
46     if(newLength<len) {
47         buffer[len=newLength]=0;
48     }
49     return *this;
50 }
51
52 CharString &CharString::append(char c, UErrorCode &errorCode) {
53     if(ensureCapacity(len+2, 0, errorCode)) {
54         buffer[len++]=c;
55         buffer[len]=0;
56     }
57     return *this;
58 }
59
60 CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
61     if(U_FAILURE(errorCode)) {
62         return *this;
63     }
64     if(sLength<-1 || (s==NULL && sLength!=0)) {
65         errorCode=U_ILLEGAL_ARGUMENT_ERROR;
66         return *this;
67     }
68     if(sLength<0) {
69         sLength=uprv_strlen(s);
70     }
71     if(sLength>0) {
72         if(s==(buffer.getAlias()+len)) {
73             // The caller wrote into the getAppendBuffer().
74             if(sLength>=(buffer.getCapacity()-len)) {
75                 // The caller wrote too much.
76                 errorCode=U_INTERNAL_PROGRAM_ERROR;
77             } else {
78                 buffer[len+=sLength]=0;
79             }
80         } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
81                   sLength>=(buffer.getCapacity()-len)
82         ) {
83             // (Part of) this string is appended to itself which requires reallocation,
84             // so we have to make a copy of the substring and append that.
85             return append(CharString(s, sLength, errorCode), errorCode);
86         } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
87             uprv_memcpy(buffer.getAlias()+len, s, sLength);
88             buffer[len+=sLength]=0;
89         }
90     }
91     return *this;
92 }
93
94 char *CharString::getAppendBuffer(int32_t minCapacity,
95                                   int32_t desiredCapacityHint,
96                                   int32_t &resultCapacity,
97                                   UErrorCode &errorCode) {
98     if(U_FAILURE(errorCode)) {
99         resultCapacity=0;
100         return NULL;
101     }
102     int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
103     if(appendCapacity>=minCapacity) {
104         resultCapacity=appendCapacity;
105         return buffer.getAlias()+len;
106     }
107     if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
108         resultCapacity=buffer.getCapacity()-len-1;
109         return buffer.getAlias()+len;
110     }
111     resultCapacity=0;
112     return NULL;
113 }
114
115 CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
116     if(U_FAILURE(errorCode)) {
117         return *this;
118     }
119     if (!uprv_isInvariantUnicodeString(s)) {
120         errorCode = U_INVARIANT_CONVERSION_ERROR;
121         return *this;
122     }
123     if(ensureCapacity(len+s.length()+1, 0, errorCode)) {
124         len+=s.extract(0, 0x7fffffff, buffer.getAlias()+len, buffer.getCapacity()-len, US_INV);
125     }
126     return *this;
127 }
128
129 UBool CharString::ensureCapacity(int32_t capacity,
130                                  int32_t desiredCapacityHint,
131                                  UErrorCode &errorCode) {
132     if(U_FAILURE(errorCode)) {
133         return FALSE;
134     }
135     if(capacity>buffer.getCapacity()) {
136         if(desiredCapacityHint==0) {
137             desiredCapacityHint=capacity+buffer.getCapacity();
138         }
139         if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
140             buffer.resize(capacity, len+1)==NULL
141         ) {
142             errorCode=U_MEMORY_ALLOCATION_ERROR;
143             return FALSE;
144         }
145     }
146     return TRUE;
147 }
148
149 CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
150     if(U_FAILURE(errorCode)) {
151         return *this;
152     }
153     if(s.length()==0) {
154         return *this;
155     }
156     char c;
157     if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
158         append(U_FILE_SEP_CHAR, errorCode);
159     }
160     append(s, errorCode);
161     return *this;
162 }
163
164 CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
165     char c;
166     if(U_SUCCESS(errorCode) && len>0 &&
167             (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
168         append(U_FILE_SEP_CHAR, errorCode);
169     }
170     return *this;
171 }
172
173 U_NAMESPACE_END