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 "stream_impl.h"
17#include "securec.h"
18
19#include <memory>
20#include <tuple>
21
22using namespace std;
23
24namespace OHOS {
25namespace CJSystemapi {
26namespace FileFs {
27
28std::tuple<int, std::unique_ptr<char[]>, size_t> DecodeString(const std::string& buffer, const std::string& encode)
29{
30    std::unique_ptr<char[]> buf = std::make_unique<char[]>(buffer.length() + 1);
31    if (!buf) {
32        return { ENOMEM, nullptr, 0};
33    }
34
35    for (size_t i = 0; i < buffer.length(); i++) {
36        buf[i] = buffer[i];
37    }
38
39    if (encode == "utf-8") {
40        return make_tuple(SUCCESS_CODE, move(buf), buffer.length());
41    } else {
42        return { EINVAL, nullptr, 0};
43    }
44}
45
46std::tuple<int, size_t> GetActualLen(size_t bufLen, size_t bufOff, int64_t offset, int64_t length)
47{
48    size_t retLen = bufLen - bufOff;
49
50    if (length == 0) {
51        return { SUCCESS_CODE, retLen };
52    }
53
54    if (length < 0 || static_cast<size_t>(length) > retLen) {
55        LOGE("Invalid option length, length: %{public}" PRId64 ", retLen: %{public}zu", length, retLen);
56        return { EINVAL, 0 };
57    }
58    retLen = static_cast<size_t>(length);
59    return { SUCCESS_CODE, retLen };
60}
61
62tuple<int, unique_ptr<char[]>, void *, size_t, int64_t> GetWriteArg(const std::string& buffer, int64_t length,
63    int64_t offset, const std::string& encode)
64{
65    void *buf = nullptr;
66
67    auto [decodeState, bufferGuard, bufLen] = DecodeString(buffer, encode);
68    if (decodeState != SUCCESS_CODE) {
69        LOGE("Illegal write buffer or encoding");
70        return { decodeState, nullptr, nullptr, 0, 0 };
71    } else {
72        buf = bufferGuard.get();
73    }
74    if (bufLen > UINT_MAX) {
75        LOGE("The Size of buffer is too large");
76        return { false, nullptr, nullptr, 0, 0 };
77    }
78
79    auto [lenState, retLen] = GetActualLen(bufLen, 0, offset, length);
80    if (lenState != SUCCESS_CODE) {
81        LOGE("Failed to get actual length");
82        return { lenState, nullptr, nullptr, 0, 0 };
83    }
84
85    if (offset < 0) {
86        LOGE("option.offset shall be positive number");
87        return { EINVAL, nullptr, nullptr, 0, 0 };
88    }
89
90    return { SUCCESS_CODE, move(bufferGuard), buf, retLen, offset };
91}
92
93tuple<int, std::unique_ptr<char[]>, size_t, int64_t> GetReadArg(size_t bufLen, int64_t length, int64_t offset)
94{
95    std::unique_ptr<char[]> buf = std::make_unique<char[]>(bufLen);
96
97    auto [state, retLen] = GetActualLen(bufLen, 0, offset, length);
98    if (state != SUCCESS_CODE) {
99        LOGE("Failed to get actual length");
100        return { EINVAL, nullptr, 0, 0 };
101    }
102
103    if (offset < 0) {
104        LOGE("option.offset shall be positive number");
105        return { EINVAL, nullptr, 0, 0 };
106    }
107
108    return { SUCCESS_CODE, move(buf), retLen, offset };
109}
110
111int StreamImpl::Close()
112{
113    if (!fp_) {
114        LOGE("close false, fp is null");
115        return GetErrorCode(EIO);
116    }
117    fp_.reset();
118    return SUCCESS_CODE;
119}
120
121int StreamImpl::Flush()
122{
123    if (!fp_) {
124        LOGE("flush false, fp is null");
125        return GetErrorCode(EIO);
126    }
127    int ret = fflush(fp_.get());
128    if (ret < 0) {
129        LOGE("Failed to fflush file in the stream, ret: %{public}d", ret);
130        return GetErrorCode(errno);
131    }
132    return SUCCESS_CODE;
133}
134
135tuple<int, int64_t> ReadImpl(std::unique_ptr<char[]> &buf, size_t len, FILE* filp, uint8_t* buffer)
136{
137    size_t actLen = fread(buf.get(), sizeof(char), len, filp);
138    if ((actLen != static_cast<size_t>(len) && !feof(filp)) || ferror(filp)) {
139        LOGE("Invalid buffer size and pointer, actlen: %{public}zu", actLen);
140        return {GetErrorCode(EIO), 0};
141    }
142    if (actLen != 0) {
143        int ret = memcpy_s(buffer, actLen, buf.get(), actLen);
144        if (ret != 0) {
145            return {GetErrorCode(EIO), 0};
146        }
147    }
148    return {SUCCESS_CODE, static_cast<int64_t>(actLen)};
149}
150
151tuple<int, int64_t> StreamImpl::ReadCur(uint8_t* buffer, size_t buLen, int64_t length)
152{
153    if (!fp_) {
154        LOGE("Stream may have been closed");
155        return {GetErrorCode(EIO), 0};
156    }
157
158    FILE *filp = nullptr;
159    filp = fp_.get();
160
161    auto [state, buf, len, offsetResult] = GetReadArg(static_cast<size_t>(buLen), length, 0.0);
162    if (state != SUCCESS_CODE) {
163        LOGE("Failed to resolve buf and options");
164        return {GetErrorCode(state), 0};
165    }
166
167    return ReadImpl(buf, len, filp, buffer);
168}
169
170tuple<int, int64_t> StreamImpl::Read(uint8_t* buffer, size_t buLen, int64_t length, int64_t offset)
171{
172    if (!fp_) {
173        LOGE("Stream may have been closed");
174        return {GetErrorCode(EIO), 0};
175    }
176
177    FILE *filp = nullptr;
178    filp = fp_.get();
179
180    auto [state, buf, len, offsetResult] = GetReadArg(static_cast<size_t>(buLen), length, offset);
181    if (state != SUCCESS_CODE) {
182        LOGE("Failed to resolve buf and options");
183        return {GetErrorCode(state), 0};
184    }
185
186    if (offsetResult >= 0) {
187        int result = fseek(filp, static_cast<long>(offsetResult), SEEK_SET);
188        if (result < 0) {
189            LOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", result);
190            return {GetErrorCode(errno), 0};
191        }
192    }
193    return ReadImpl(buf, len, filp, buffer);
194}
195
196tuple<int, int64_t> StreamImpl::WriteCur(const std::string& buffer, int64_t length, const std::string& encode)
197{
198    FILE *filp = nullptr;
199    filp = fp_.get();
200
201    auto [state, bufGuard, buf, len, offsetResult] =
202        GetWriteArg(buffer, length, 0.0, encode);
203    if (state != SUCCESS_CODE) {
204        LOGE("Failed to resolve buf and options");
205        return {GetErrorCode(state), 0};
206    }
207
208    size_t writeLen = fwrite(buf, 1, len, filp);
209    if ((writeLen == 0) && (writeLen != len)) {
210        LOGE("Failed to fwrite stream");
211        return {GetErrorCode(EIO), 0};
212    }
213    return {SUCCESS_CODE, static_cast<int64_t>(writeLen)};
214}
215
216tuple<int, int64_t> StreamImpl::Write(const std::string& buffer, int64_t length, int64_t offset,
217    const std::string& encode)
218{
219    FILE *filp = nullptr;
220    filp = fp_.get();
221
222    auto [state, bufGuard, buf, len, offsetResult] =
223        GetWriteArg(buffer, length, offset, encode);
224    if (state != SUCCESS_CODE) {
225        LOGE("Failed to resolve buf and options");
226        return {GetErrorCode(state), 0};
227    }
228
229    if (offsetResult >= 0) {
230        int ret = fseek(filp, static_cast<long>(offsetResult), SEEK_SET);
231        if (ret < 0) {
232            LOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
233            return {GetErrorCode(errno), 0};
234        }
235    }
236
237    size_t writeLen = fwrite(buf, 1, len, filp);
238    if ((writeLen == 0) && (writeLen != len)) {
239        LOGE("Failed to fwrite stream");
240        return {GetErrorCode(EIO), 0};
241    }
242    return {SUCCESS_CODE, static_cast<int64_t>(writeLen)};
243}
244
245}
246}
247}