1/*
2*******************************************************************************
3*
4*   Copyright (C) 1998-2012, International Business Machines
5*   Corporation and others.  All Rights Reserved.
6*
7*******************************************************************************
8*
9* File ustr.c
10*
11* Modification History:
12*
13*   Date        Name        Description
14*   05/28/99    stephen     Creation.
15*******************************************************************************
16*/
17
18#include "ustr.h"
19#include "cmemory.h"
20#include "cstring.h"
21#include "unicode/ustring.h"
22#include "unicode/putil.h"
23#include "unicode/utf16.h"
24
25/* Protos */
26static void ustr_resize(struct UString *s, int32_t len, UErrorCode *status);
27
28/* Macros */
29#define ALLOCATION(minSize) (minSize < 0x80 ? 0x80 : (2 * minSize + 0x80) & ~(0x80 - 1))
30
31U_CFUNC void
32ustr_init(struct UString *s)
33{
34    s->fChars = 0;
35    s->fLength = s->fCapacity = 0;
36}
37
38U_CFUNC void
39ustr_initChars(struct UString *s, const char* source, int32_t length, UErrorCode *status)
40{
41    int i = 0;
42    if (U_FAILURE(*status)) return;
43    s->fChars = 0;
44    s->fLength = s->fCapacity = 0;
45    if (length == -1) {
46        length = (int32_t)uprv_strlen(source);
47    }
48    if(s->fCapacity < length) {
49      ustr_resize(s, ALLOCATION(length), status);
50      if(U_FAILURE(*status)) return;
51    }
52    for (; i < length; i++)
53    {
54      UChar charToAppend;
55      u_charsToUChars(source+i, &charToAppend, 1);
56      ustr_ucat(s, charToAppend, status);
57      /*
58#if U_CHARSET_FAMILY==U_ASCII_FAMILY
59        ustr_ucat(s, (UChar)(uint8_t)(source[i]), status);
60#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
61        ustr_ucat(s, (UChar)asciiFromEbcdic[(uint8_t)(*cs++)], status);
62#else
63#   error U_CHARSET_FAMILY is not valid
64#endif
65      */
66    }
67}
68
69U_CFUNC void
70ustr_deinit(struct UString *s)
71{
72    if (s) {
73        uprv_free(s->fChars);
74        s->fChars = 0;
75        s->fLength = s->fCapacity = 0;
76    }
77}
78
79U_CFUNC void
80ustr_cpy(struct UString *dst,
81     const struct UString *src,
82     UErrorCode *status)
83{
84    if(U_FAILURE(*status) || dst == src)
85        return;
86
87    if(dst->fCapacity < src->fLength) {
88        ustr_resize(dst, ALLOCATION(src->fLength), status);
89        if(U_FAILURE(*status))
90            return;
91    }
92    if(src->fChars == NULL || dst->fChars == NULL){
93        return;
94    }
95    uprv_memcpy(dst->fChars, src->fChars, sizeof(UChar) * src->fLength);
96    dst->fLength = src->fLength;
97    dst->fChars[dst->fLength] = 0x0000;
98}
99
100U_CFUNC void
101ustr_setlen(struct UString *s,
102        int32_t len,
103        UErrorCode *status)
104{
105    if(U_FAILURE(*status))
106        return;
107
108    if(s->fCapacity < (len + 1)) {
109        ustr_resize(s, ALLOCATION(len), status);
110        if(U_FAILURE(*status))
111            return;
112    }
113
114    s->fLength = len;
115    s->fChars[len] = 0x0000;
116}
117
118U_CFUNC void
119ustr_cat(struct UString *dst,
120     const struct UString *src,
121     UErrorCode *status)
122{
123    ustr_ncat(dst, src, src->fLength, status);
124}
125
126U_CFUNC void
127ustr_ncat(struct UString *dst,
128      const struct UString *src,
129      int32_t n,
130      UErrorCode *status)
131{
132    if(U_FAILURE(*status) || dst == src)
133        return;
134
135    if(dst->fCapacity < (dst->fLength + n)) {
136        ustr_resize(dst, ALLOCATION(dst->fLength + n), status);
137        if(U_FAILURE(*status))
138            return;
139    }
140
141    uprv_memcpy(dst->fChars + dst->fLength, src->fChars,
142                sizeof(UChar) * n);
143    dst->fLength += src->fLength;
144    dst->fChars[dst->fLength] = 0x0000;
145}
146
147U_CFUNC void
148ustr_ucat(struct UString *dst,
149      UChar c,
150      UErrorCode *status)
151{
152    if(U_FAILURE(*status))
153        return;
154
155    if(dst->fCapacity < (dst->fLength + 1)) {
156        ustr_resize(dst, ALLOCATION(dst->fLength + 1), status);
157        if(U_FAILURE(*status))
158            return;
159    }
160
161    uprv_memcpy(dst->fChars + dst->fLength, &c,
162        sizeof(UChar) * 1);
163    dst->fLength += 1;
164    dst->fChars[dst->fLength] = 0x0000;
165}
166U_CFUNC void
167ustr_u32cat(struct UString *dst, UChar32 c, UErrorCode *status){
168    if(c > 0x10FFFF){
169        *status = U_ILLEGAL_CHAR_FOUND;
170        return;
171    }
172    if(c >0xFFFF){
173        ustr_ucat(dst, U16_LEAD(c), status);
174        ustr_ucat(dst, U16_TRAIL(c), status);
175    }else{
176        ustr_ucat(dst, (UChar) c, status);
177    }
178}
179U_CFUNC void
180ustr_uscat(struct UString *dst,
181      const UChar* src,int len,
182      UErrorCode *status)
183{
184    if(U_FAILURE(*status))
185        return;
186
187    if(dst->fCapacity < (dst->fLength + len)) {
188        ustr_resize(dst, ALLOCATION(dst->fLength + len), status);
189        if(U_FAILURE(*status))
190            return;
191    }
192
193    uprv_memcpy(dst->fChars + dst->fLength, src,
194        sizeof(UChar) * len);
195    dst->fLength += len;
196    dst->fChars[dst->fLength] = 0x0000;
197}
198
199/* Destroys data in the string */
200static void
201ustr_resize(struct UString *s,
202        int32_t len,
203        UErrorCode *status)
204{
205    if(U_FAILURE(*status))
206        return;
207
208    /* +1 for trailing 0x0000 */
209    s->fChars = (UChar*) uprv_realloc(s->fChars, sizeof(UChar) * (len + 1));
210    if(s->fChars == 0) {
211        *status = U_MEMORY_ALLOCATION_ERROR;
212        s->fLength = s->fCapacity = 0;
213        return;
214    }
215
216    s->fCapacity = len;
217}
218