1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "util/string_builder.h"
17 
18 #include <cstdlib>
19 #include <cstring>
20 
21 #include "securec.h"
22 #include "util/common.h"
23 #include "util/logger.h"
24 #include "util/string_helper.h"
25 
26 namespace OHOS {
27 namespace Idl {
~StringBuilder()28 StringBuilder::~StringBuilder()
29 {
30     if (buffer_ != nullptr) {
31         free(buffer_);
32     }
33 }
34 
Append(char c)35 StringBuilder &StringBuilder::Append(char c)
36 {
37     if (position_ + 1 >= capacity_) {
38         if (!Grow(1)) {
39             return *this;
40         }
41     }
42 
43     buffer_[position_] = c;
44     position_ += 1;
45     return *this;
46 }
47 
Append(const char * string)48 StringBuilder &StringBuilder::Append(const char *string)
49 {
50     if (string == nullptr || string[0] == '\0') {
51         return *this;
52     }
53 
54     size_t len = strlen(string);
55     if (position_ + len >= capacity_) {
56         if (!Grow(len)) {
57             return *this;
58         }
59     }
60 
61     int ret = memcpy_s(buffer_ + position_, capacity_ - position_, string, len);
62     if (ret != 0) {
63         Logger::E(TAG, "memcpy_s error ret = %d!", ret);
64         return *this;
65     }
66     position_ += len;
67     return *this;
68 }
69 
Append(const std::string & string)70 StringBuilder &StringBuilder::Append(const std::string &string)
71 {
72     if (string.empty()) {
73         return *this;
74     }
75 
76     size_t len = string.size();
77     if (position_ + len >= capacity_) {
78         if (!Grow(len)) {
79             return *this;
80         }
81     }
82 
83     int ret = memcpy_s(buffer_ + position_, capacity_ - position_, string.c_str(), len);
84     if (ret != 0) {
85         Logger::E(TAG, "memcpy_s error ret = %d!", ret);
86         return *this;
87     }
88     position_ += len;
89     return *this;
90 }
91 
AppendFormat(const char * format,...)92 StringBuilder &StringBuilder::AppendFormat(const char *format, ...)
93 {
94     va_list args;
95     va_list argsCopy;
96 
97     va_start(args, format);
98     va_copy(argsCopy, args);
99 
100     char buf[StringHelper::lineMaxSize] = {0};
101     int len = vsnprintf_s(buf, StringHelper::lineMaxSize, StringHelper::lineMaxSize - 1, format, args);
102     if (len <= 0) {
103         va_end(args);
104         va_end(argsCopy);
105         return *this;
106     }
107 
108     size_t writeSize = static_cast<size_t>(len);
109     if (position_ + writeSize >= capacity_) {
110         if (!Grow(writeSize)) {
111             va_end(args);
112             va_end(argsCopy);
113             return *this;
114         }
115     }
116 
117     if (vsnprintf_s(buffer_ + position_, writeSize + 1, writeSize, format, argsCopy) < 0) {
118         va_end(args);
119         va_end(argsCopy);
120         return *this;
121     }
122     position_ += writeSize;
123 
124     va_end(args);
125     va_end(argsCopy);
126 
127     return *this;
128 }
129 
Grow(size_t size)130 bool StringBuilder::Grow(size_t size)
131 {
132     if (capacity_ > StringHelper::maxSize) {
133         Logger::E(TAG, "The StringBuilder is full.");
134         return false;
135     }
136     // 256->the default capacity.
137     size_t newSize = (capacity_ == 0) ? 256 : (capacity_ * 2);
138     if (newSize < capacity_ + size) {
139         newSize = capacity_ + size;
140     }
141     if (newSize > StringHelper::maxSize) {
142         newSize = StringHelper::maxSize;
143     }
144     if (newSize <= capacity_) {
145         return false;
146     }
147 
148     char *newBuffer = reinterpret_cast<char *>(calloc(newSize, 1));
149     if (newBuffer == nullptr) {
150         Logger::E(TAG, "Fail to malloc %lu bytes memory.", newSize);
151         return false;
152     }
153 
154     if (buffer_ != nullptr) {
155         int ret = memcpy_s(newBuffer, newSize, buffer_, capacity_);
156         free(buffer_);
157         buffer_ = nullptr;
158         if (ret != 0) {
159             Logger::E(TAG, "memcpy_s error ret = %d!", ret);
160             free(newBuffer);
161             return false;
162         }
163     }
164     buffer_ = newBuffer;
165     capacity_ = newSize;
166     return true;
167 }
168 
ToString() const169 std::string StringBuilder::ToString() const
170 {
171     if (buffer_ == nullptr) {
172         return "";
173     }
174     return std::string(buffer_, position_);
175 }
176 } // namespace Idl
177 } // namespace OHOS