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