1/*
2 * Copyright (c) 2021-2023 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 "stream_buffer.h"
17
18#include <algorithm>
19
20namespace OHOS {
21namespace Msdp {
22StreamBuffer::StreamBuffer(const StreamBuffer &buf)
23{
24    Clone(buf);
25}
26
27StreamBuffer &StreamBuffer::operator=(const StreamBuffer &buffer)
28{
29    Clone(buffer);
30    return *this;
31}
32
33void StreamBuffer::Reset()
34{
35    wPos_ = 0;
36    rPos_ = 0;
37    wCount_ = 0;
38    rCount_ = 0;
39    rwErrorStatus_ = ErrorStatus::ERROR_STATUS_OK;
40}
41
42void StreamBuffer::Clean()
43{
44    Reset();
45    errno_t ret = memset_sp(&szBuff_, sizeof(szBuff_), 0, sizeof(szBuff_));
46    if (ret != EOK) {
47        FI_HILOGE("Call memset_s failed");
48        return;
49    }
50}
51
52bool StreamBuffer::SeekReadPos(int32_t n)
53{
54    int32_t pos = rPos_ + n;
55    if (pos < 0 || pos > wPos_) {
56        FI_HILOGE("The position in the calculation is not as expected, pos:%{public}d, [0, %{public}d]",
57            pos, wPos_);
58        return false;
59    }
60    rPos_ = pos;
61    return true;
62}
63
64bool StreamBuffer::Write(const std::string &buf)
65{
66    return Write(buf.c_str(), buf.length() + 1);
67}
68
69bool StreamBuffer::Read(std::string &buf)
70{
71    if (rPos_ == wPos_) {
72        FI_HILOGE("Not enough memory to read, errCode:%{public}d", STREAM_BUF_READ_FAIL);
73        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_READ;
74        return false;
75    }
76    buf = ReadBuf();
77    rPos_ = rPos_ + static_cast<int32_t>(buf.length()) + 1;
78    return (buf.length() > 0);
79}
80
81bool StreamBuffer::Write(const StreamBuffer &buf)
82{
83    return Write(buf.Data(), buf.Size());
84}
85
86bool StreamBuffer::Read(StreamBuffer &buf)
87{
88    return buf.Write(Data(), Size());
89}
90
91bool StreamBuffer::Read(char *buf, size_t size)
92{
93    if (ChkRWError()) {
94        FI_HILOGE("Read and write status is error");
95        return false;
96    }
97    if (buf == nullptr) {
98        FI_HILOGE("Invalid input parameter buf:nullptr, errCode:%{public}d", PARAM_INPUT_INVALID);
99        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_READ;
100        return false;
101    }
102    if (size == 0) {
103        FI_HILOGE("Invalid input parameter size:%{public}zu, errCode:%{public}d", size, PARAM_INPUT_INVALID);
104        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_READ;
105        return false;
106    }
107    if (rPos_ + static_cast<int32_t>(size) > wPos_) {
108        FI_HILOGE("Memory out of bounds on read, errCode:%{public}d", MEM_OUT_OF_BOUNDS);
109        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_READ;
110        return false;
111    }
112    errno_t ret = memcpy_sp(buf, size, ReadBuf(), size);
113    if (ret != EOK) {
114        FI_HILOGE("Failed to call memcpy_sp, errCode:%{public}d", MEMCPY_SEC_FUN_FAIL);
115        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_READ;
116        return false;
117    }
118
119    rCount_ += 1;
120    rPos_ += static_cast<int32_t>(size);
121    return true;
122}
123
124bool StreamBuffer::Write(const char *buf, size_t size)
125{
126    if (ChkRWError()) {
127        FI_HILOGE("Read and write status is error");
128        return false;
129    }
130    if (buf == nullptr) {
131        FI_HILOGE("Invalid input parameter, buf:nullptr, errCode:%{public}d", PARAM_INPUT_INVALID);
132        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_WRITE;
133        return false;
134    }
135    if (size == 0) {
136        FI_HILOGE("Invalid input parameter, size:%{public}zu, errCode:%{public}d", size, PARAM_INPUT_INVALID);
137        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_WRITE;
138        return false;
139    }
140    if (wPos_ + static_cast<int32_t>(size) > MAX_STREAM_BUF_SIZE) {
141        FI_HILOGE("The write length exceeds buffer, wIdx:%{public}d, size:%{public}zu, maxBufSize:%{public}d, "
142            "errCode:%{public}d", wPos_, size, MAX_STREAM_BUF_SIZE, MEM_OUT_OF_BOUNDS);
143        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_WRITE;
144        return false;
145    }
146    errno_t ret = memcpy_sp(&szBuff_[wPos_], GetAvailableBufSize(), buf, size);
147    if (ret != EOK) {
148        FI_HILOGE("Failed to call memcpy_sp, errCode:%{public}d", MEMCPY_SEC_FUN_FAIL);
149        rwErrorStatus_ = ErrorStatus::ERROR_STATUS_WRITE;
150        return false;
151    }
152    wPos_ += static_cast<int32_t>(size);
153    wCount_ += 1;
154    return true;
155}
156
157bool StreamBuffer::empty() const
158{
159    return (rPos_ == wPos_);
160}
161
162size_t StreamBuffer::Size() const
163{
164    return static_cast<size_t>(wPos_);
165}
166
167int32_t StreamBuffer::ResidualSize() const
168{
169    return ((wPos_ <= rPos_) ? 0 : (wPos_ - rPos_));
170}
171
172bool StreamBuffer::ChkRWError() const
173{
174    return (rwErrorStatus_ != ErrorStatus::ERROR_STATUS_OK);
175}
176
177int32_t StreamBuffer::GetAvailableBufSize() const
178{
179    return ((wPos_ >= MAX_STREAM_BUF_SIZE) ? 0 : (MAX_STREAM_BUF_SIZE - wPos_));
180}
181
182const std::string &StreamBuffer::GetErrorStatusRemark() const
183{
184    static const std::vector<std::pair<ErrorStatus, std::string>> remark {
185        { ErrorStatus::ERROR_STATUS_OK, "OK" },
186        { ErrorStatus::ERROR_STATUS_READ, "READ_ERROR" },
187        { ErrorStatus::ERROR_STATUS_WRITE, "WRITE_ERROR" }
188    };
189    static const std::string invalidStatus { "UNKNOWN" };
190
191    auto tIter = std::find_if(remark.cbegin(), remark.cend(),
192        [this](const auto &item) {
193            return (item.first == rwErrorStatus_);
194        });
195    return (tIter != remark.cend() ? tIter->second : invalidStatus);
196}
197
198const char *StreamBuffer::Data() const
199{
200    return &szBuff_[0];
201}
202
203const char *StreamBuffer::ReadBuf() const
204{
205    return &szBuff_[rPos_];
206}
207
208bool StreamBuffer::Clone(const StreamBuffer &buf)
209{
210    Clean();
211    return Write(buf.Data(), buf.Size());
212}
213} // namespace Msdp
214} // namespace OHOS
215