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 11 public String8() { 12 this(""); 13 } 14 15 public String8(String value) { 16 mString = new StringBuilder(value); 17 } 18 19 public String8(String8 path) { 20 this(path.string()); 21 } 22 23 public String8(String value, int len) { 24 this(value.substring(0, len)); 25 } 26 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 //} 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 //} 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 */ 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 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 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 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 404 public final String string() { 405 return mString.toString(); 406 } 407 408 @Override 409 public String toString() { 410 return mString.toString(); 411 } 412 413 @Override 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 428 public int hashCode() { 429 return mString != null ? mString.hashCode() : 0; 430 } 431 432 } 433 434 435