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
26namespace OHOS {
27namespace Idl {
28StringBuilder::~StringBuilder()
29{
30    if (buffer_ != nullptr) {
31        free(buffer_);
32    }
33}
34
35StringBuilder &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
48StringBuilder &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
70StringBuilder &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
92StringBuilder &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
130bool 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        if (ret != 0) {
158            Logger::E(TAG, "memcpy_s error ret = %d!", ret);
159            free(newBuffer);
160            return false;
161        }
162    }
163    buffer_ = newBuffer;
164    capacity_ = newSize;
165    return true;
166}
167
168std::string StringBuilder::ToString() const
169{
170    return std::string(buffer_, position_);
171}
172} // namespace Idl
173} // namespace OHOS