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