AString.cpp revision 89b2a0ad367cdff5ff4e70036311ecf82921a829
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "AString"
18#include <utils/Log.h>
19
20#include <ctype.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <binder/Parcel.h>
27#include <utils/String8.h>
28#include "ADebug.h"
29#include "AString.h"
30
31namespace android {
32
33// static
34const char *AString::kEmptyString = "";
35
36AString::AString()
37    : mData((char *)kEmptyString),
38      mSize(0),
39      mAllocSize(1) {
40}
41
42AString::AString(const char *s)
43    : mData(NULL),
44      mSize(0),
45      mAllocSize(1) {
46    if (!s) {
47        ALOGW("ctor got NULL, using empty string instead");
48        clear();
49    } else {
50        setTo(s);
51    }
52}
53
54AString::AString(const char *s, size_t size)
55    : mData(NULL),
56      mSize(0),
57      mAllocSize(1) {
58    if (!s) {
59        ALOGW("ctor got NULL, using empty string instead");
60        clear();
61    } else {
62        setTo(s, size);
63    }
64}
65
66AString::AString(const String8 &from)
67    : mData(NULL),
68      mSize(0),
69      mAllocSize(1) {
70    setTo(from.string(), from.length());
71}
72
73AString::AString(const AString &from)
74    : mData(NULL),
75      mSize(0),
76      mAllocSize(1) {
77    setTo(from, 0, from.size());
78}
79
80AString::AString(const AString &from, size_t offset, size_t n)
81    : mData(NULL),
82      mSize(0),
83      mAllocSize(1) {
84    setTo(from, offset, n);
85}
86
87AString::~AString() {
88    clear();
89}
90
91AString &AString::operator=(const AString &from) {
92    if (&from != this) {
93        setTo(from, 0, from.size());
94    }
95
96    return *this;
97}
98
99size_t AString::size() const {
100    return mSize;
101}
102
103const char *AString::c_str() const {
104    return mData;
105}
106
107bool AString::empty() const {
108    return mSize == 0;
109}
110
111void AString::setTo(const char *s) {
112    setTo(s, strlen(s));
113}
114
115void AString::setTo(const char *s, size_t size) {
116    clear();
117    append(s, size);
118}
119
120void AString::setTo(const AString &from, size_t offset, size_t n) {
121    CHECK(&from != this);
122
123    clear();
124    setTo(from.mData + offset, n);
125}
126
127void AString::clear() {
128    if (mData && mData != kEmptyString) {
129        free(mData);
130        mData = NULL;
131    }
132
133    mData = (char *)kEmptyString;
134    mSize = 0;
135    mAllocSize = 1;
136}
137
138size_t AString::hash() const {
139    size_t x = 0;
140    for (size_t i = 0; i < mSize; ++i) {
141        x = (x * 31) + mData[i];
142    }
143
144    return x;
145}
146
147bool AString::operator==(const AString &other) const {
148    return mSize == other.mSize && !memcmp(mData, other.mData, mSize);
149}
150
151void AString::trim() {
152    makeMutable();
153
154    size_t i = 0;
155    while (i < mSize && isspace(mData[i])) {
156        ++i;
157    }
158
159    size_t j = mSize;
160    while (j > i && isspace(mData[j - 1])) {
161        --j;
162    }
163
164    memmove(mData, &mData[i], j - i);
165    mSize = j - i;
166    mData[mSize] = '\0';
167}
168
169void AString::erase(size_t start, size_t n) {
170    CHECK_LT(start, mSize);
171    CHECK_LE(start + n, mSize);
172
173    makeMutable();
174
175    memmove(&mData[start], &mData[start + n], mSize - start - n);
176    mSize -= n;
177    mData[mSize] = '\0';
178}
179
180void AString::makeMutable() {
181    if (mData == kEmptyString) {
182        mData = strdup(kEmptyString);
183    }
184}
185
186void AString::append(const char *s) {
187    append(s, strlen(s));
188}
189
190void AString::append(const char *s, size_t size) {
191    makeMutable();
192
193    if (mSize + size + 1 > mAllocSize) {
194        mAllocSize = (mAllocSize + size + 31) & -32;
195        mData = (char *)realloc(mData, mAllocSize);
196        CHECK(mData != NULL);
197    }
198
199    memcpy(&mData[mSize], s, size);
200    mSize += size;
201    mData[mSize] = '\0';
202}
203
204void AString::append(const AString &from) {
205    append(from.c_str(), from.size());
206}
207
208void AString::append(const AString &from, size_t offset, size_t n) {
209    append(from.c_str() + offset, n);
210}
211
212void AString::append(int x) {
213    char s[16];
214    int result = snprintf(s, sizeof(s), "%d", x);
215    CHECK((result > 0) && ((size_t) result) < sizeof(s));
216    append(s);
217}
218
219void AString::append(unsigned x) {
220    char s[16];
221    int result = snprintf(s, sizeof(s), "%u", x);
222    CHECK((result > 0) && ((size_t) result) < sizeof(s));
223    append(s);
224}
225
226void AString::append(long x) {
227    char s[32];
228    int result = snprintf(s, sizeof(s), "%ld", x);
229    CHECK((result > 0) && ((size_t) result) < sizeof(s));
230    append(s);
231}
232
233void AString::append(unsigned long x) {
234    char s[32];
235    int result = snprintf(s, sizeof(s), "%lu", x);
236    CHECK((result > 0) && ((size_t) result) < sizeof(s));
237    append(s);
238}
239
240void AString::append(long long x) {
241    char s[32];
242    int result = snprintf(s, sizeof(s), "%lld", x);
243    CHECK((result > 0) && ((size_t) result) < sizeof(s));
244    append(s);
245}
246
247void AString::append(unsigned long long x) {
248    char s[32];
249    int result = snprintf(s, sizeof(s), "%llu", x);
250    CHECK((result > 0) && ((size_t) result) < sizeof(s));
251    append(s);
252}
253
254void AString::append(float x) {
255    char s[16];
256    int result = snprintf(s, sizeof(s), "%f", x);
257    CHECK((result > 0) && ((size_t) result) < sizeof(s));
258    append(s);
259}
260
261void AString::append(double x) {
262    char s[16];
263    int result = snprintf(s, sizeof(s), "%f", x);
264    CHECK((result > 0) && ((size_t) result) < sizeof(s));
265    append(s);
266}
267
268void AString::append(void *x) {
269    char s[32];
270    int result = snprintf(s, sizeof(s), "%p", x);
271    CHECK((result > 0) && ((size_t) result) < sizeof(s));
272    append(s);
273}
274
275ssize_t AString::find(const char *substring, size_t start) const {
276    CHECK_LE(start, size());
277
278    const char *match = strstr(mData + start, substring);
279
280    if (match == NULL) {
281        return -1;
282    }
283
284    return match - mData;
285}
286
287void AString::insert(const AString &from, size_t insertionPos) {
288    insert(from.c_str(), from.size(), insertionPos);
289}
290
291void AString::insert(const char *from, size_t size, size_t insertionPos) {
292    CHECK_GE(insertionPos, 0u);
293    CHECK_LE(insertionPos, mSize);
294
295    makeMutable();
296
297    if (mSize + size + 1 > mAllocSize) {
298        mAllocSize = (mAllocSize + size + 31) & -32;
299        mData = (char *)realloc(mData, mAllocSize);
300        CHECK(mData != NULL);
301    }
302
303    memmove(&mData[insertionPos + size],
304            &mData[insertionPos], mSize - insertionPos + 1);
305
306    memcpy(&mData[insertionPos], from, size);
307
308    mSize += size;
309}
310
311bool AString::operator<(const AString &other) const {
312    return compare(other) < 0;
313}
314
315bool AString::operator>(const AString &other) const {
316    return compare(other) > 0;
317}
318
319int AString::compare(const AString &other) const {
320    return strcmp(mData, other.mData);
321}
322
323int AString::compareIgnoreCase(const AString &other) const {
324    return strcasecmp(mData, other.mData);
325}
326
327bool AString::equalsIgnoreCase(const AString &other) const {
328    return compareIgnoreCase(other) == 0;
329}
330
331void AString::tolower() {
332    makeMutable();
333
334    for (size_t i = 0; i < mSize; ++i) {
335        mData[i] = ::tolower(mData[i]);
336    }
337}
338
339bool AString::startsWith(const char *prefix) const {
340    return !strncmp(mData, prefix, strlen(prefix));
341}
342
343bool AString::endsWith(const char *suffix) const {
344    size_t suffixLen = strlen(suffix);
345
346    if (mSize < suffixLen) {
347        return false;
348    }
349
350    return !strcmp(mData + mSize - suffixLen, suffix);
351}
352
353bool AString::startsWithIgnoreCase(const char *prefix) const {
354    return !strncasecmp(mData, prefix, strlen(prefix));
355}
356
357bool AString::endsWithIgnoreCase(const char *suffix) const {
358    size_t suffixLen = strlen(suffix);
359
360    if (mSize < suffixLen) {
361        return false;
362    }
363
364    return !strcasecmp(mData + mSize - suffixLen, suffix);
365}
366
367// static
368AString AString::FromParcel(const Parcel &parcel) {
369    size_t size = static_cast<size_t>(parcel.readInt32());
370    return AString(static_cast<const char *>(parcel.readInplace(size)), size);
371}
372
373status_t AString::writeToParcel(Parcel *parcel) const {
374    CHECK_LE(mSize, static_cast<size_t>(INT32_MAX));
375    status_t err = parcel->writeInt32(mSize);
376    if (err == OK) {
377        err = parcel->write(mData, mSize);
378    }
379    return err;
380}
381
382AString AStringPrintf(const char *format, ...) {
383    va_list ap;
384    va_start(ap, format);
385
386    char *buffer;
387    vasprintf(&buffer, format, ap);
388
389    va_end(ap);
390
391    AString result(buffer);
392
393    free(buffer);
394    buffer = NULL;
395
396    return result;
397}
398
399}  // namespace android
400
401