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