1/*
2 * Copyright (c) 2024-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 <cinttypes>
17#include <algorithm>
18#include <mutex>
19#include <stdexcept>
20#include <string>
21
22#include "random_access_file_input.h"
23
24namespace OHOS {
25namespace SignatureTools {
26RandomAccessFileInput::RandomAccessFileInput(RandomAccessFile& file) : file(file),
27    startIndex(0), size(-1)
28{
29}
30
31RandomAccessFileInput::RandomAccessFileInput(RandomAccessFile& file, int64_t offset, int64_t size)
32    : file(file), startIndex(offset), size(size)
33{
34    if (offset < 0) {
35        SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64, offset);
36        return;
37    }
38    if (size < 0) {
39        SIGNATURE_TOOLS_LOGE("out of range: size %" PRId64, size);
40        return;
41    }
42}
43
44int64_t RandomAccessFileInput::Size()
45{
46    if (size == -1) {
47        return file.GetLength();
48    }
49    return size;
50}
51
52bool RandomAccessFileInput::CopyTo(int64_t offset, int size, ByteBuffer& buffer)
53{
54    int64_t srcSize = Size();
55    if (!CheckBoundValid(offset, size, srcSize)) {
56        return false;
57    }
58    if (size == 0) {
59        SIGNATURE_TOOLS_LOGE("Copy size is equal to 0");
60        return false;
61    }
62    if (size > buffer.Remaining()) {
63        SIGNATURE_TOOLS_LOGE("The length size passed in is greater than the reserved length of ByteBuffer");
64        return false;
65    }
66    int64_t offsetInFile = startIndex + offset;
67    int remaining = size;
68    int originalLimit = buffer.GetLimit();
69
70    buffer.SetLimit(buffer.GetPosition() + size);
71    int64_t readSize;
72    while (remaining > 0) {
73        {
74            std::mutex tmpMutex;
75            std::scoped_lock lock(tmpMutex);
76            readSize = file.ReadFileFullyFromOffset(buffer, offsetInFile);
77        }
78        offsetInFile += readSize;
79        remaining -= readSize;
80    }
81    int cap = buffer.GetCapacity();
82    buffer.SetPosition(cap);
83    buffer.SetLimit(originalLimit);
84    return true;
85}
86
87ByteBuffer RandomAccessFileInput::CreateByteBuffer(int64_t offset, int size)
88{
89    ByteBuffer byteBuffer;
90    if (size < 0) {
91        SIGNATURE_TOOLS_LOGE("IndexOutOfBounds: The created ByteBuffer size %d is less than 0", size);
92        return byteBuffer;
93    }
94
95    byteBuffer.SetCapacity(size);
96    if (!CopyTo(offset, size, byteBuffer)) {
97        byteBuffer.SetCapacity(0);
98        return byteBuffer;
99    }
100
101    return byteBuffer.Flip();
102}
103
104DataSource* RandomAccessFileInput::Slice(int64_t offset, int64_t size)
105{
106    int64_t srcSize = Size();
107    if (!CheckBoundValid(offset, size, srcSize)) {
108        return nullptr;
109    }
110    if (offset == 0 && size == srcSize) {
111        SIGNATURE_TOOLS_LOGI("offset: 0, size: %" PRId64 ", it will return itself", size);
112        return new FileDataSource(file, startIndex, size, 0);
113    }
114    return new FileDataSource(file, offset, size, 0);
115}
116
117bool RandomAccessFileInput::CheckBoundValid(int64_t offset, int64_t size, int64_t sourceSize)
118{
119    if (offset < 0) {
120        SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64, offset);
121        return false;
122    }
123    if (size < 0) {
124        SIGNATURE_TOOLS_LOGE("out of range: size %" PRId64, size);
125        return false;
126    }
127    if (offset > sourceSize) {
128        SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64 " is greater than sourceSize %" PRId64,
129            offset, sourceSize);
130        return false;
131    }
132    int64_t endOffset = offset + size;
133    if (endOffset < offset) {
134        SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64 " add size %" PRId64 " is overflow",
135            offset, size);
136        return false;
137    }
138    if (endOffset > sourceSize) {
139        SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64 " add size %" PRId64 " is greater than "
140            "sourceSize %" PRId64, offset, size, sourceSize);
141        return false;
142    }
143    return true;
144}
145} // namespace SignatureTools
146} // namespace OHOS