1 package org.robolectric.res.android;
2
3 import java.io.File;
4
5 // transliterated from https://android.googlesource.com/platform/system/core/+/android-9.0.0_r12/libutils/String8.cpp
6 // and https://android.googlesource.com/platform/system/core/+/android-9.0.0_r12/include/utils/String8.h
7 public class String8 {
8
9 private StringBuilder mString;
10
String8()11 public String8() {
12 this("");
13 }
14
String8(String value)15 public String8(String value) {
16 mString = new StringBuilder(value);
17 }
18
String8(String8 path)19 public String8(String8 path) {
20 this(path.string());
21 }
22
String8(String value, int len)23 public String8(String value, int len) {
24 this(value.substring(0, len));
25 }
26
length()27 int length() {
28 return mString.length();
29 }
30 //String8 String8::format(const char* fmt, ...)
31 //{
32 // va_list args;
33 // va_start(args, fmt);
34 // String8 result(formatV(fmt, args));
35 // va_end(args);
36 // return result;
37 //}
38 //String8 String8::formatV(const char* fmt, va_list args)
39 //{
40 // String8 result;
41 // result.appendFormatV(fmt, args);
42 // return result;
43 //}
44 //void String8::clear() {
45 // SharedBuffer::bufferFromData(mString)->release();
46 // mString = getEmptyString();
47 //}
48 //void String8::setTo(const String8& other)
49 //{
50 // SharedBuffer::bufferFromData(other.mString)->acquire();
51 // SharedBuffer::bufferFromData(mString)->release();
52 // mString = other.mString;
53 //}
54 //status_t String8::setTo(const char* other)
55 //{
56 // const char *newString = allocFromUTF8(other, strlen(other));
57 // SharedBuffer::bufferFromData(mString)->release();
58 // mString = newString;
59 // if (mString) return NO_ERROR;
60 // mString = getEmptyString();
61 // return NO_MEMORY;
62 //}
63 //status_t String8::setTo(const char* other, size_t len)
64 //{
65 // const char *newString = allocFromUTF8(other, len);
66 // SharedBuffer::bufferFromData(mString)->release();
67 // mString = newString;
68 // if (mString) return NO_ERROR;
69 // mString = getEmptyString();
70 // return NO_MEMORY;
71 //}
72 //status_t String8::setTo(const char16_t* other, size_t len)
73 //{
74 // const char *newString = allocFromUTF16(other, len);
75 // SharedBuffer::bufferFromData(mString)->release();
76 // mString = newString;
77 // if (mString) return NO_ERROR;
78 // mString = getEmptyString();
79 // return NO_MEMORY;
80 //}
81 //status_t String8::setTo(const char32_t* other, size_t len)
82 //{
83 // const char *newString = allocFromUTF32(other, len);
84 // SharedBuffer::bufferFromData(mString)->release();
85 // mString = newString;
86 // if (mString) return NO_ERROR;
87 // mString = getEmptyString();
88 // return NO_MEMORY;
89 //}
90 //status_t String8::append(const String8& other)
91 //{
92 // const size_t otherLen = other.bytes();
93 // if (bytes() == 0) {
94 // setTo(other);
95 // return NO_ERROR;
96 // } else if (otherLen == 0) {
97 // return NO_ERROR;
98 // }
99 // return real_append(other.string(), otherLen);
100 //}
append(final String other)101 public String8 append(final String other) {
102 mString.append(other);
103 return this;
104 }
105 //status_t String8::append(const char* other, size_t otherLen)
106 //{
107 // if (bytes() == 0) {
108 // return setTo(other, otherLen);
109 // } else if (otherLen == 0) {
110 // return NO_ERROR;
111 // }
112 // return real_append(other, otherLen);
113 //}
114 //status_t String8::appendFormat(const char* fmt, ...)
115 //{
116 // va_list args;
117 // va_start(args, fmt);
118 // status_t result = appendFormatV(fmt, args);
119 // va_end(args);
120 // return result;
121 //}
122 //status_t String8::appendFormatV(const char* fmt, va_list args)
123 //{
124 // int n, result = NO_ERROR;
125 // va_list tmp_args;
126 // /* args is undefined after vsnprintf.
127 // * So we need a copy here to avoid the
128 // * second vsnprintf access undefined args.
129 // */
130 // va_copy(tmp_args, args);
131 // n = vsnprintf(NULL, 0, fmt, tmp_args);
132 // va_end(tmp_args);
133 // if (n != 0) {
134 // size_t oldLength = length();
135 // char* buf = lockBuffer(oldLength + n);
136 // if (buf) {
137 // vsnprintf(buf + oldLength, n + 1, fmt, args);
138 // } else {
139 // result = NO_MEMORY;
140 // }
141 // }
142 // return result;
143 //}
144 //status_t String8::real_append(const char* other, size_t otherLen)
145 //{
146 // const size_t myLen = bytes();
147 //
148 // SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
149 // ->editResize(myLen+otherLen+1);
150 // if (buf) {
151 // char* str = (char*)buf->data();
152 // mString = str;
153 // str += myLen;
154 // memcpy(str, other, otherLen);
155 // str[otherLen] = '\0';
156 // return NO_ERROR;
157 // }
158 // return NO_MEMORY;
159 //}
160 //char* String8::lockBuffer(size_t size)
161 //{
162 // SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
163 // ->editResize(size+1);
164 // if (buf) {
165 // char* str = (char*)buf->data();
166 // mString = str;
167 // return str;
168 // }
169 // return NULL;
170 //}
171 //void String8::unlockBuffer()
172 //{
173 // unlockBuffer(strlen(mString));
174 //}
175 //status_t String8::unlockBuffer(size_t size)
176 //{
177 // if (size != this->size()) {
178 // SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
179 // ->editResize(size+1);
180 // if (! buf) {
181 // return NO_MEMORY;
182 // }
183 // char* str = (char*)buf->data();
184 // str[size] = 0;
185 // mString = str;
186 // }
187 // return NO_ERROR;
188 //}
189 //ssize_t String8::find(const char* other, size_t start) const
190 //{
191 // size_t len = size();
192 // if (start >= len) {
193 // return -1;
194 // }
195 // const char* s = mString+start;
196 // const char* p = strstr(s, other);
197 // return p ? p-mString : -1;
198 //}
199 //bool String8::removeAll(const char* other) {
200 // ssize_t index = find(other);
201 // if (index < 0) return false;
202 // char* buf = lockBuffer(size());
203 // if (!buf) return false; // out of memory
204 // size_t skip = strlen(other);
205 // size_t len = size();
206 // size_t tail = index;
207 // while (size_t(index) < len) {
208 // ssize_t next = find(other, index + skip);
209 // if (next < 0) {
210 // next = len;
211 // }
212 // memmove(buf + tail, buf + index + skip, next - index - skip);
213 // tail += next - index - skip;
214 // index = next;
215 // }
216 // unlockBuffer(tail);
217 // return true;
218 //}
219 //void String8::toLower()
220 //{
221 // toLower(0, size());
222 //}
223 //void String8::toLower(size_t start, size_t length)
224 //{
225 // const size_t len = size();
226 // if (start >= len) {
227 // return;
228 // }
229 // if (start+length > len) {
230 // length = len-start;
231 // }
232 // char* buf = lockBuffer(len);
233 // buf += start;
234 // while (length > 0) {
235 // *buf = tolower(*buf);
236 // buf++;
237 // length--;
238 // }
239 // unlockBuffer(len);
240 //}
241 //void String8::toUpper()
242 //{
243 // toUpper(0, size());
244 //}
245 //void String8::toUpper(size_t start, size_t length)
246 //{
247 // const size_t len = size();
248 // if (start >= len) {
249 // return;
250 // }
251 // if (start+length > len) {
252 // length = len-start;
253 // }
254 // char* buf = lockBuffer(len);
255 // buf += start;
256 // while (length > 0) {
257 // *buf = toupper(*buf);
258 // buf++;
259 // length--;
260 // }
261 // unlockBuffer(len);
262 //}
263 //size_t String8::getUtf32Length() const
264 //{
265 // return utf8_to_utf32_length(mString, length());
266 //}
267 //int32_t String8::getUtf32At(size_t index, size_t *next_index) const
268 //{
269 // return utf32_from_utf8_at(mString, length(), index, next_index);
270 //}
271 //void String8::getUtf32(char32_t* dst) const
272 //{
273 // utf8_to_utf32(mString, length(), dst);
274 //}
275 //// ---------------------------------------------------------------------------
276 //// Path functions
277 //void String8::setPathName(const char* name)
278 //{
279 // setPathName(name, strlen(name));
280 //}
281 //void String8::setPathName(const char* name, size_t len)
282 //{
283 // char* buf = lockBuffer(len);
284 // memcpy(buf, name, len);
285 // // remove trailing path separator, if present
286 // if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
287 // len--;
288 // buf[len] = '\0';
289 // unlockBuffer(len);
290 //}
getPathLeaf()291 String8 getPathLeaf() {
292 final int cp;
293 final String buf = mString.toString();
294 cp = buf.lastIndexOf(File.separatorChar);
295 if (cp == -1) {
296 return new String8(this);
297 } else {
298 return new String8(buf.substring(cp + 1));
299 }
300 }
301 //String8 String8::getPathDir(void) const
302 //{
303 // const char* cp;
304 // const char*const str = mString;
305 // cp = strrchr(str, OS_PATH_SEPARATOR);
306 // if (cp == NULL)
307 // return String8("");
308 // else
309 // return String8(str, cp - str);
310 //}
311 //String8 String8::walkPath(String8* outRemains) const
312 //{
313 // const char* cp;
314 // const char*const str = mString;
315 // const char* buf = str;
316 // cp = strchr(buf, OS_PATH_SEPARATOR);
317 // if (cp == buf) {
318 // // don't include a leading '/'.
319 // buf = buf+1;
320 // cp = strchr(buf, OS_PATH_SEPARATOR);
321 // }
322 // if (cp == NULL) {
323 // String8 res = buf != str ? String8(buf) : *this;
324 // if (outRemains) *outRemains = String8("");
325 // return res;
326 // }
327 // String8 res(buf, cp-buf);
328 // if (outRemains) *outRemains = String8(cp+1);
329 // return res;
330 //}
331
332 /*
333 * Helper function for finding the start of an extension in a pathname.
334 *
335 * Returns a index inside mString, or -1 if no extension was found.
336 */
find_extension()337 private int find_extension()
338 {
339 int lastSlashIndex;
340
341 final StringBuilder str = mString;
342 // only look at the filename
343 lastSlashIndex = str.lastIndexOf(File.pathSeparator);
344 if (lastSlashIndex == -1) {
345 lastSlashIndex = 0;
346 } else {
347 lastSlashIndex++;
348 }
349 // find the last dot
350 return str.lastIndexOf(".", lastSlashIndex);
351 }
352
getPathExtension()353 public String getPathExtension()
354 {
355 int extIndex;
356 extIndex = find_extension();
357 if (extIndex != -1) {
358 return mString.substring(extIndex);
359 }
360 else {
361 return "";
362 }
363 }
364
getBasePath()365 String8 getBasePath() {
366 int extIndex;
367 extIndex = find_extension();
368 if (extIndex == -1) {
369 return new String8(this);
370 } else {
371 return new String8(mString.substring(extIndex));
372 }
373 }
374
appendPath(String name)375 public String8 appendPath(String name) {
376 if (name.length() == 0) {
377 // nothing to do
378 return this;
379 }
380 if (name.charAt(0) != File.separatorChar) {
381 mString.append(File.separatorChar);
382 }
383 mString.append(name);
384 return this;
385 }
386
387 //String8& String8::convertToResPath()
388 //{
389 //#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
390 // size_t len = length();
391 // if (len > 0) {
392 // char * buf = lockBuffer(len);
393 // for (char * end = buf + len; buf < end; ++buf) {
394 // if (*buf == OS_PATH_SEPARATOR)
395 // *buf = RES_PATH_SEPARATOR;
396 // }
397 // unlockBuffer(len);
398 // }
399 //#endif
400 // return *this;
401 //}
402 //}; // namespace android
403
string()404 public final String string() {
405 return mString.toString();
406 }
407
408 @Override
toString()409 public String toString() {
410 return mString.toString();
411 }
412
413 @Override
equals(Object o)414 public boolean equals(Object o) {
415 if (this == o) {
416 return true;
417 }
418 if (o == null || getClass() != o.getClass()) {
419 return false;
420 }
421
422 String8 string8 = (String8) o;
423
424 return mString != null ? mString.toString().equals(string8.mString.toString()) : string8.mString == null;
425 }
426
427 @Override
hashCode()428 public int hashCode() {
429 return mString != null ? mString.hashCode() : 0;
430 }
431
432 }
433
434
435