1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "util/string_builder.h"
10
11 #include <cstdlib>
12 #include <cstring>
13
14 #include "securec.h"
15 #include "util/common.h"
16 #include "util/logger.h"
17 #include "util/string_helper.h"
18
19 namespace OHOS {
20 namespace HDI {
~StringBuilder()21 StringBuilder::~StringBuilder()
22 {
23 if (buffer_ != nullptr) {
24 free(buffer_);
25 }
26 }
27
Append(char c)28 StringBuilder &StringBuilder::Append(char c)
29 {
30 if (position_ + 1 >= capacity_) {
31 if (!Grow(1)) {
32 return *this;
33 }
34 }
35
36 if (buffer_ == nullptr) {
37 Logger::E(TAG, "buffer_ is nullptr!");
38 return *this;
39 }
40 buffer_[position_] = c;
41 position_ += 1;
42 return *this;
43 }
44
Append(const char * string)45 StringBuilder &StringBuilder::Append(const char *string)
46 {
47 if (string == nullptr || string[0] == '\0') {
48 return *this;
49 }
50
51 size_t len = strlen(string);
52 if (position_ + len >= capacity_) {
53 if (!Grow(len)) {
54 return *this;
55 }
56 }
57
58 int ret = memcpy_s(buffer_ + position_, capacity_ - position_, string, len);
59 if (ret != 0) {
60 Logger::E(TAG, "memcpy_s error ret = %d!", ret);
61 return *this;
62 }
63 position_ += len;
64 return *this;
65 }
66
Append(const std::string & string)67 StringBuilder &StringBuilder::Append(const std::string &string)
68 {
69 if (string.empty()) {
70 return *this;
71 }
72
73 size_t len = string.size();
74 if (position_ + len >= capacity_) {
75 if (!Grow(len)) {
76 return *this;
77 }
78 }
79
80 int ret = memcpy_s(buffer_ + position_, capacity_ - position_, string.c_str(), len);
81 if (ret != 0) {
82 Logger::E(TAG, "memcpy_s error ret = %d!", ret);
83 return *this;
84 }
85 position_ += len;
86 return *this;
87 }
88
AppendFormat(const char * format,...)89 StringBuilder &StringBuilder::AppendFormat(const char *format, ...)
90 {
91 va_list args;
92 va_list argsCopy;
93
94 va_start(args, format);
95 va_copy(argsCopy, args);
96
97 char buf[StringHelper::lineMaxSize] = {0};
98 int len = vsnprintf_s(buf, StringHelper::lineMaxSize, StringHelper::lineMaxSize - 1, format, args);
99 if (len <= 0) {
100 va_end(args);
101 va_end(argsCopy);
102 return *this;
103 }
104
105 size_t writeSize = static_cast<size_t>(len);
106 if (position_ + writeSize >= capacity_) {
107 if (!Grow(writeSize)) {
108 va_end(args);
109 va_end(argsCopy);
110 return *this;
111 }
112 }
113
114 if (vsnprintf_s(buffer_ + position_, writeSize + 1, writeSize, format, argsCopy) < 0) {
115 va_end(args);
116 va_end(argsCopy);
117 return *this;
118 }
119 position_ += writeSize;
120
121 va_end(args);
122 va_end(argsCopy);
123
124 return *this;
125 }
126
Grow(size_t size)127 bool StringBuilder::Grow(size_t size)
128 {
129 if (capacity_ > StringHelper::maxSize) {
130 Logger::E(TAG, "The StringBuilder is full.");
131 return false;
132 }
133 // 256->the default capacity.
134 size_t newSize = (capacity_ == 0) ? 256 : (capacity_ * 2);
135 if (newSize < capacity_ + size) {
136 newSize = capacity_ + size;
137 }
138 if (newSize > StringHelper::maxSize) {
139 newSize = StringHelper::maxSize;
140 }
141 if (newSize <= capacity_) {
142 return false;
143 }
144
145 char *newBuffer = reinterpret_cast<char *>(calloc(newSize, 1));
146 if (newBuffer == nullptr) {
147 Logger::E(TAG, "Fail to malloc %lu bytes memory.", newSize);
148 return false;
149 }
150
151 if (buffer_ != nullptr) {
152 int ret = memcpy_s(newBuffer, newSize, buffer_, capacity_);
153 if (ret != 0) {
154 Logger::E(TAG, "memcpy_s error ret = %d!", ret);
155 free(newBuffer);
156 return false;
157 }
158 free(buffer_);
159 }
160 buffer_ = newBuffer;
161 capacity_ = newSize;
162 return true;
163 }
164
ToString() const165 std::string StringBuilder::ToString() const
166 {
167 if (buffer_ == nullptr) {
168 Logger::E(TAG, "buffer_ is nullptr");
169 return "";
170 }
171 return std::string(buffer_, position_);
172 }
173 } // namespace HDI
174 } // namespace OHOS