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