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
20U_NAMESPACE_BEGIN
21
22CharString &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
30CharString &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
40CharString &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
48CharString &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
82char *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
103CharString &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
110UBool 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
130CharString &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
145U_NAMESPACE_END
146