1/*
2 * Copyright (c) 2022 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 "securec.h"
19
20#include "util/logger.h"
21
22namespace OHOS {
23namespace Idl {
24const char* StringBuilder::TAG = "StringBuilder";
25constexpr int LINE_MAX_SIZE = 1024;
26
27StringBuilder::~StringBuilder()
28{
29    if (buffer_ != nullptr) {
30        free(buffer_);
31    }
32}
33
34StringBuilder& StringBuilder::Append(char c)
35{
36    if (position_ + 1 >= capacity_) {
37        if (!Grow(1)) {
38            return *this;
39        }
40    }
41
42    buffer_[position_] = c;
43    position_ += 1;
44    return *this;
45}
46
47StringBuilder& StringBuilder::Append(const char* string)
48{
49    if (string == nullptr || string[0] == '\0') {
50        return *this;
51    }
52
53    size_t len = strlen(string);
54    if (position_ + len >= capacity_) {
55        if (!Grow(len)) {
56            return *this;
57        }
58    }
59
60    if (memcpy_s(buffer_ + position_, capacity_ - position_, string, len) != EOK) {
61        return *this;
62    }
63    position_ += len;
64    return *this;
65}
66
67StringBuilder& StringBuilder::Append(const String& string)
68{
69    if (string.IsEmpty()) {
70        return *this;
71    }
72
73    size_t len = static_cast<size_t>(string.GetLength());
74    if (position_ + len >= capacity_) {
75        if (!Grow(len)) {
76            return *this;
77        }
78    }
79
80    if (memcpy_s(buffer_ + position_, capacity_ - position_, string.string(), len) != EOK) {
81        return *this;
82    }
83    position_ += len;
84    return *this;
85}
86
87StringBuilder& StringBuilder::AppendFormat(const char* format, ...)
88{
89    va_list args, argsCopy;
90
91    va_start(args, format);
92    va_copy(argsCopy, args);
93
94    char buf[LINE_MAX_SIZE] = {0};
95    int len = vsnprintf_s(buf, LINE_MAX_SIZE, LINE_MAX_SIZE - 1, format, args);
96    if (len <= 0) {
97        va_end(args);
98        va_end(argsCopy);
99        return *this;
100    }
101
102    size_t positionTmp = position_ + static_cast<size_t>(len);
103    if (positionTmp >= capacity_) {
104        if (!Grow(len)) {
105            va_end(args);
106            va_end(argsCopy);
107            return *this;
108        }
109    }
110
111    if (vsnprintf_s(buffer_ + position_, len + 1, len, format, argsCopy) < 0) {
112        va_end(args);
113        va_end(argsCopy);
114        return *this;
115    }
116    position_ += len;
117    va_end(args);
118    va_end(argsCopy);
119
120    return *this;
121}
122
123bool StringBuilder::Grow(size_t size)
124{
125    if (capacity_ > String::MAX_SIZE) {
126        Logger::E(TAG, "The StringBuilder is full.");
127        return false;
128    }
129    // 256->the default capacity.
130    size_t newSize = (capacity_ == 0 ? 256 : capacity_ * 2);
131    if (newSize < capacity_ + size) {
132        newSize = capacity_ + size;
133    }
134    if (newSize > String::MAX_SIZE) {
135        newSize = String::MAX_SIZE;
136    }
137    if (newSize <= capacity_) {
138        return false;
139    }
140
141    char* newBuffer = reinterpret_cast<char*>(calloc(newSize, 1));
142    if (newBuffer == nullptr) {
143        Logger::E(TAG, "Fail to malloc %lu bytes memory.", newSize);
144        return false;
145    }
146
147    if (buffer_ != nullptr) {
148        errno_t ret = memcpy_s(newBuffer, newSize, buffer_, capacity_);
149        if (ret != EOK) {
150            free(newBuffer);
151            newBuffer = nullptr;
152            return false;
153        }
154        free(buffer_);
155    }
156    buffer_ = newBuffer;
157    capacity_ = newSize;
158    return true;
159}
160
161String StringBuilder::ToString() const
162{
163    return String(buffer_, position_);
164}
165}
166}
167