• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2005 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 __STDC_LIMIT_MACROS
18  #include <stdint.h>
19  
20  #include <utils/String8.h>
21  
22  #include <utils/Compat.h>
23  #include <utils/Log.h>
24  #include <utils/String16.h>
25  
26  #include <ctype.h>
27  
28  #include <string>
29  
30  #include "SharedBuffer.h"
31  
32  /*
33   * Functions outside android is below the namespace android, since they use
34   * functions and constants in android namespace.
35   */
36  
37  // ---------------------------------------------------------------------------
38  
39  namespace android {
40  
41  // Separator used by resource paths. This is not platform dependent contrary
42  // to OS_PATH_SEPARATOR.
43  #define RES_PATH_SEPARATOR '/'
44  
45  static inline char* getEmptyString() {
46      static SharedBuffer* gEmptyStringBuf = [] {
47          SharedBuffer* buf = SharedBuffer::alloc(1);
48          char* str = static_cast<char*>(buf->data());
49          *str = 0;
50          return buf;
51      }();
52  
53      gEmptyStringBuf->acquire();
54      return static_cast<char*>(gEmptyStringBuf->data());
55  }
56  
57  // ---------------------------------------------------------------------------
58  
59  static char* allocFromUTF8(const char* in, size_t len)
60  {
61      if (len > 0) {
62          if (len == SIZE_MAX) {
63              return nullptr;
64          }
65          SharedBuffer* buf = SharedBuffer::alloc(len+1);
66          ALOG_ASSERT(buf, "Unable to allocate shared buffer");
67          if (buf) {
68              char* str = (char*)buf->data();
69              memcpy(str, in, len);
70              str[len] = 0;
71              return str;
72          }
73          return nullptr;
74      }
75  
76      return getEmptyString();
77  }
78  
79  static char* allocFromUTF16(const char16_t* in, size_t len)
80  {
81      if (len == 0) return getEmptyString();
82  
83       // Allow for closing '\0'
84      const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
85      if (resultStrLen < 1) {
86          return getEmptyString();
87      }
88  
89      SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
90      ALOG_ASSERT(buf, "Unable to allocate shared buffer");
91      if (!buf) {
92          return getEmptyString();
93      }
94  
95      char* resultStr = (char*)buf->data();
96      utf16_to_utf8(in, len, resultStr, resultStrLen);
97      return resultStr;
98  }
99  
100  static char* allocFromUTF32(const char32_t* in, size_t len)
101  {
102      if (len == 0) {
103          return getEmptyString();
104      }
105  
106      const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
107      if (resultStrLen < 1) {
108          return getEmptyString();
109      }
110  
111      SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
112      ALOG_ASSERT(buf, "Unable to allocate shared buffer");
113      if (!buf) {
114          return getEmptyString();
115      }
116  
117      char* resultStr = (char*) buf->data();
118      utf32_to_utf8(in, len, resultStr, resultStrLen);
119  
120      return resultStr;
121  }
122  
123  // ---------------------------------------------------------------------------
124  
125  String8::String8()
126      : mString(getEmptyString())
127  {
128  }
129  
130  String8::String8(const String8& o)
131      : mString(o.mString)
132  {
133      SharedBuffer::bufferFromData(mString)->acquire();
134  }
135  
136  String8::String8(const char* o)
137      : mString(allocFromUTF8(o, strlen(o)))
138  {
139      if (mString == nullptr) {
140          mString = getEmptyString();
141      }
142  }
143  
144  String8::String8(const char* o, size_t len)
145      : mString(allocFromUTF8(o, len))
146  {
147      if (mString == nullptr) {
148          mString = getEmptyString();
149      }
150  }
151  
152  String8::String8(const String16& o)
153      : mString(allocFromUTF16(o.string(), o.size()))
154  {
155  }
156  
157  String8::String8(const char16_t* o)
158      : mString(allocFromUTF16(o, strlen16(o)))
159  {
160  }
161  
162  String8::String8(const char16_t* o, size_t len)
163      : mString(allocFromUTF16(o, len))
164  {
165  }
166  
167  String8::String8(const char32_t* o)
168      : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
169  
170  String8::String8(const char32_t* o, size_t len)
171      : mString(allocFromUTF32(o, len))
172  {
173  }
174  
175  String8::~String8()
176  {
177      SharedBuffer::bufferFromData(mString)->release();
178  }
179  
180  size_t String8::length() const
181  {
182      return SharedBuffer::sizeFromData(mString)-1;
183  }
184  
185  String8 String8::format(const char* fmt, ...)
186  {
187      va_list args;
188      va_start(args, fmt);
189  
190      String8 result(formatV(fmt, args));
191  
192      va_end(args);
193      return result;
194  }
195  
196  String8 String8::formatV(const char* fmt, va_list args)
197  {
198      String8 result;
199      result.appendFormatV(fmt, args);
200      return result;
201  }
202  
203  void String8::clear() {
204      SharedBuffer::bufferFromData(mString)->release();
205      mString = getEmptyString();
206  }
207  
208  void String8::setTo(const String8& other)
209  {
210      SharedBuffer::bufferFromData(other.mString)->acquire();
211      SharedBuffer::bufferFromData(mString)->release();
212      mString = other.mString;
213  }
214  
215  status_t String8::setTo(const char* other)
216  {
217      const char *newString = allocFromUTF8(other, strlen(other));
218      SharedBuffer::bufferFromData(mString)->release();
219      mString = newString;
220      if (mString) return OK;
221  
222      mString = getEmptyString();
223      return NO_MEMORY;
224  }
225  
226  status_t String8::setTo(const char* other, size_t len)
227  {
228      const char *newString = allocFromUTF8(other, len);
229      SharedBuffer::bufferFromData(mString)->release();
230      mString = newString;
231      if (mString) return OK;
232  
233      mString = getEmptyString();
234      return NO_MEMORY;
235  }
236  
237  status_t String8::setTo(const char16_t* other, size_t len)
238  {
239      const char *newString = allocFromUTF16(other, len);
240      SharedBuffer::bufferFromData(mString)->release();
241      mString = newString;
242      if (mString) return OK;
243  
244      mString = getEmptyString();
245      return NO_MEMORY;
246  }
247  
248  status_t String8::setTo(const char32_t* other, size_t len)
249  {
250      const char *newString = allocFromUTF32(other, len);
251      SharedBuffer::bufferFromData(mString)->release();
252      mString = newString;
253      if (mString) return OK;
254  
255      mString = getEmptyString();
256      return NO_MEMORY;
257  }
258  
259  status_t String8::append(const String8& other)
260  {
261      const size_t otherLen = other.bytes();
262      if (bytes() == 0) {
263          setTo(other);
264          return OK;
265      } else if (otherLen == 0) {
266          return OK;
267      }
268  
269      return real_append(other.string(), otherLen);
270  }
271  
272  status_t String8::append(const char* other)
273  {
274      return append(other, strlen(other));
275  }
276  
277  status_t String8::append(const char* other, size_t otherLen)
278  {
279      if (bytes() == 0) {
280          return setTo(other, otherLen);
281      } else if (otherLen == 0) {
282          return OK;
283      }
284  
285      return real_append(other, otherLen);
286  }
287  
288  status_t String8::appendFormat(const char* fmt, ...)
289  {
290      va_list args;
291      va_start(args, fmt);
292  
293      status_t result = appendFormatV(fmt, args);
294  
295      va_end(args);
296      return result;
297  }
298  
299  status_t String8::appendFormatV(const char* fmt, va_list args)
300  {
301      int n, result = OK;
302      va_list tmp_args;
303  
304      /* args is undefined after vsnprintf.
305       * So we need a copy here to avoid the
306       * second vsnprintf access undefined args.
307       */
308      va_copy(tmp_args, args);
309      n = vsnprintf(nullptr, 0, fmt, tmp_args);
310      va_end(tmp_args);
311  
312      if (n < 0) return UNKNOWN_ERROR;
313  
314      if (n > 0) {
315          size_t oldLength = length();
316          if (n > std::numeric_limits<size_t>::max() - 1 ||
317              oldLength > std::numeric_limits<size_t>::max() - n - 1) {
318              return NO_MEMORY;
319          }
320          char* buf = lockBuffer(oldLength + n);
321          if (buf) {
322              vsnprintf(buf + oldLength, n + 1, fmt, args);
323          } else {
324              result = NO_MEMORY;
325          }
326      }
327      return result;
328  }
329  
330  status_t String8::real_append(const char* other, size_t otherLen) {
331      const size_t myLen = bytes();
332  
333      SharedBuffer* buf;
334      size_t newLen;
335      if (__builtin_add_overflow(myLen, otherLen, &newLen) ||
336          __builtin_add_overflow(newLen, 1, &newLen) ||
337          (buf = SharedBuffer::bufferFromData(mString)->editResize(newLen)) == nullptr) {
338          return NO_MEMORY;
339      }
340  
341      char* str = (char*)buf->data();
342      mString = str;
343      str += myLen;
344      memcpy(str, other, otherLen);
345      str[otherLen] = '\0';
346      return OK;
347  }
348  
349  char* String8::lockBuffer(size_t size)
350  {
351      SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
352          ->editResize(size+1);
353      if (buf) {
354          char* str = (char*)buf->data();
355          mString = str;
356          return str;
357      }
358      return nullptr;
359  }
360  
361  void String8::unlockBuffer()
362  {
363      unlockBuffer(strlen(mString));
364  }
365  
366  status_t String8::unlockBuffer(size_t size)
367  {
368      if (size != this->size()) {
369          SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
370              ->editResize(size+1);
371          if (! buf) {
372              return NO_MEMORY;
373          }
374  
375          char* str = (char*)buf->data();
376          str[size] = 0;
377          mString = str;
378      }
379  
380      return OK;
381  }
382  
383  ssize_t String8::find(const char* other, size_t start) const
384  {
385      size_t len = size();
386      if (start >= len) {
387          return -1;
388      }
389      const char* s = mString+start;
390      const char* p = strstr(s, other);
391      return p ? p-mString : -1;
392  }
393  
394  bool String8::removeAll(const char* other) {
395      ssize_t index = find(other);
396      if (index < 0) return false;
397  
398      char* buf = lockBuffer(size());
399      if (!buf) return false; // out of memory
400  
401      size_t skip = strlen(other);
402      size_t len = size();
403      size_t tail = index;
404      while (size_t(index) < len) {
405          ssize_t next = find(other, index + skip);
406          if (next < 0) {
407              next = len;
408          }
409  
410          memmove(buf + tail, buf + index + skip, next - index - skip);
411          tail += next - index - skip;
412          index = next;
413      }
414      unlockBuffer(tail);
415      return true;
416  }
417  
418  void String8::toLower()
419  {
420      const size_t length = size();
421      if (length == 0) return;
422  
423      char* buf = lockBuffer(length);
424      for (size_t i = length; i > 0; --i) {
425          *buf = static_cast<char>(tolower(*buf));
426          buf++;
427      }
428      unlockBuffer(length);
429  }
430  
431  // ---------------------------------------------------------------------------
432  // Path functions
433  
434  void String8::setPathName(const char* name)
435  {
436      setPathName(name, strlen(name));
437  }
438  
439  void String8::setPathName(const char* name, size_t len)
440  {
441      char* buf = lockBuffer(len);
442  
443      memcpy(buf, name, len);
444  
445      // remove trailing path separator, if present
446      if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
447          len--;
448  
449      buf[len] = '\0';
450  
451      unlockBuffer(len);
452  }
453  
454  String8 String8::getPathLeaf(void) const
455  {
456      const char* cp;
457      const char*const buf = mString;
458  
459      cp = strrchr(buf, OS_PATH_SEPARATOR);
460      if (cp == nullptr)
461          return String8(*this);
462      else
463          return String8(cp+1);
464  }
465  
466  String8 String8::getPathDir(void) const
467  {
468      const char* cp;
469      const char*const str = mString;
470  
471      cp = strrchr(str, OS_PATH_SEPARATOR);
472      if (cp == nullptr)
473          return String8("");
474      else
475          return String8(str, cp - str);
476  }
477  
478  String8 String8::walkPath(String8* outRemains) const
479  {
480      const char* cp;
481      const char*const str = mString;
482      const char* buf = str;
483  
484      cp = strchr(buf, OS_PATH_SEPARATOR);
485      if (cp == buf) {
486          // don't include a leading '/'.
487          buf = buf+1;
488          cp = strchr(buf, OS_PATH_SEPARATOR);
489      }
490  
491      if (cp == nullptr) {
492          String8 res = buf != str ? String8(buf) : *this;
493          if (outRemains) *outRemains = String8("");
494          return res;
495      }
496  
497      String8 res(buf, cp-buf);
498      if (outRemains) *outRemains = String8(cp+1);
499      return res;
500  }
501  
502  /*
503   * Helper function for finding the start of an extension in a pathname.
504   *
505   * Returns a pointer inside mString, or NULL if no extension was found.
506   */
507  char* String8::find_extension(void) const
508  {
509      const char* lastSlash;
510      const char* lastDot;
511      const char* const str = mString;
512  
513      // only look at the filename
514      lastSlash = strrchr(str, OS_PATH_SEPARATOR);
515      if (lastSlash == nullptr)
516          lastSlash = str;
517      else
518          lastSlash++;
519  
520      // find the last dot
521      lastDot = strrchr(lastSlash, '.');
522      if (lastDot == nullptr)
523          return nullptr;
524  
525      // looks good, ship it
526      return const_cast<char*>(lastDot);
527  }
528  
529  String8 String8::getPathExtension(void) const
530  {
531      char* ext;
532  
533      ext = find_extension();
534      if (ext != nullptr)
535          return String8(ext);
536      else
537          return String8("");
538  }
539  
540  String8 String8::getBasePath(void) const
541  {
542      char* ext;
543      const char* const str = mString;
544  
545      ext = find_extension();
546      if (ext == nullptr)
547          return String8(*this);
548      else
549          return String8(str, ext - str);
550  }
551  
552  String8& String8::appendPath(const char* name)
553  {
554      // TODO: The test below will fail for Win32 paths. Fix later or ignore.
555      if (name[0] != OS_PATH_SEPARATOR) {
556          if (*name == '\0') {
557              // nothing to do
558              return *this;
559          }
560  
561          size_t len = length();
562          if (len == 0) {
563              // no existing filename, just use the new one
564              setPathName(name);
565              return *this;
566          }
567  
568          // make room for oldPath + '/' + newPath
569          int newlen = strlen(name);
570  
571          char* buf = lockBuffer(len+1+newlen);
572  
573          // insert a '/' if needed
574          if (buf[len-1] != OS_PATH_SEPARATOR)
575              buf[len++] = OS_PATH_SEPARATOR;
576  
577          memcpy(buf+len, name, newlen+1);
578          len += newlen;
579  
580          unlockBuffer(len);
581  
582          return *this;
583      } else {
584          setPathName(name);
585          return *this;
586      }
587  }
588  
589  String8& String8::convertToResPath()
590  {
591  #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
592      size_t len = length();
593      if (len > 0) {
594          char * buf = lockBuffer(len);
595          for (char * end = buf + len; buf < end; ++buf) {
596              if (*buf == OS_PATH_SEPARATOR)
597                  *buf = RES_PATH_SEPARATOR;
598          }
599          unlockBuffer(len);
600      }
601  #endif
602      return *this;
603  }
604  
605  }; // namespace android
606