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 <cerrno>
17 #include <cstring>
18 #include <fcntl.h>
19 #include <new>
20 #include <string>
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "buffer_metadata_stream.h"
26 #include "image_log.h"
27 #include "image_utils.h"
28 #include "metadata_stream.h"
29 #include "securec.h"
30
31 #undef LOG_DOMAIN
32 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
33
34 #undef LOG_TAG
35 #define LOG_TAG "BufferMetadataStream"
36
37 namespace OHOS {
38 namespace Media {
BufferMetadataStream()39 BufferMetadataStream::BufferMetadataStream()
40 {
41 buffer_ = nullptr;
42 capacity_ = 0;
43 bufferSize_ = 0;
44 currentOffset_ = 0;
45 memoryMode_ = Dynamic;
46 originData_ = nullptr;
47 }
48
BufferMetadataStream(byte * originData,size_t size,MemoryMode mode,int originalFd,const std::string & originalPath)49 BufferMetadataStream::BufferMetadataStream(byte *originData, size_t size, MemoryMode mode,
50 int originalFd, const std::string &originalPath)
51 {
52 buffer_ = originData;
53 this->originData_ = originData;
54 capacity_ = static_cast<long>(size);
55 bufferSize_ = static_cast<long>(size);
56 currentOffset_ = 0;
57 memoryMode_ = mode;
58 originalFd_ = originalFd;
59 originalPath_ = originalPath;
60 }
61
~BufferMetadataStream()62 BufferMetadataStream::~BufferMetadataStream()
63 {
64 Close();
65 }
66
Write(uint8_t * data,ssize_t size)67 ssize_t BufferMetadataStream::Write(uint8_t *data, ssize_t size)
68 {
69 // Check if the new data will fit into the current buffer
70 if (currentOffset_ + static_cast<long>(size) > capacity_) {
71 if (memoryMode_ == Fix) {
72 IMAGE_LOGE("BufferMetadataStream::Write failed, data size exceeds buffer capacity, "
73 "currentOffset:%{public}ld, size:%{public}ld, capacity:%{public}ld",
74 currentOffset_, static_cast<long>(size), capacity_);
75 return -1;
76 }
77
78 // Calculate the new capacity, ensuring it is a multiple of
79 // BUFFER_IMAGE_STREAM_PAGE_SIZE
80 long newCapacity = CalculateNewCapacity(currentOffset_, size);
81 if (newCapacity > METADATA_STREAM_MAX_CAPACITY) {
82 IMAGE_LOGE("BufferMetadataStream::Write failed, new capacity exceeds maximum capacity, "
83 "newCapacity:%{public}ld, maxCapacity:%{public}d",
84 newCapacity, METADATA_STREAM_MAX_CAPACITY);
85 return -1;
86 }
87
88 // Allocate the new buffer
89 byte *newBuffer = new (std::nothrow) byte[newCapacity];
90
91 // Check if the allocation was successful
92 if (newBuffer == nullptr) {
93 IMAGE_LOGE("BufferMetadataStream::Write failed, unable to allocate new buffer");
94 return -1;
95 }
96
97 // Removed std::fill_n for efficiency. If zero-initialization is needed,
98 // consider doing it manually where necessary.
99 // If there is existing data, copy it to the new buffer
100 if (buffer_ != nullptr) {
101 if (EOK != memcpy_s(newBuffer, newCapacity, buffer_, bufferSize_)) {
102 IMAGE_LOGE("BufferMetadataStream::Write failed, memcpy error");
103 delete[] newBuffer;
104 return -1;
105 }
106
107 // If the old buffer was not externally allocated, delete it
108 if (originData_ != buffer_) {
109 delete[] buffer_;
110 buffer_ = nullptr;
111 }
112 }
113
114 // Update the buffer and capacity
115 buffer_ = newBuffer;
116 capacity_ = newCapacity;
117
118 // Update expansion count
119 if (memoryMode_ == Dynamic) {
120 expandCount_++;
121 }
122 }
123
124 // Copy the new data into the buffer
125 if (data != nullptr) {
126 if (EOK != memcpy_s(buffer_ + currentOffset_, capacity_ - currentOffset_, data, size)) {
127 IMAGE_LOGE("BufferMetadataStream::Write failed, memcpy error");
128 return -1;
129 }
130 }
131
132 // Update the current offset and buffer size
133 currentOffset_ += size;
134 bufferSize_ = std::max(currentOffset_, bufferSize_);
135
136 return size;
137 }
138
Read(uint8_t * buf,ssize_t size)139 ssize_t BufferMetadataStream::Read(uint8_t *buf, ssize_t size)
140 {
141 if (buffer_ == nullptr || currentOffset_ == bufferSize_) {
142 return -1;
143 }
144
145 if (currentOffset_ > bufferSize_) {
146 IMAGE_LOGE("BufferMetadataStream::Read failed, current offset exceeds buffer size, "
147 "currentOffset:%{public}ld, bufferSize:%{public}ld",
148 currentOffset_, bufferSize_);
149 return -1;
150 }
151
152 long bytesToRead = std::min(static_cast<long>(size), bufferSize_ - currentOffset_);
153 if (IsFileSizeChanged()) {
154 return -1;
155 }
156 memcpy_s(buf, size, buffer_ + currentOffset_, bytesToRead);
157 currentOffset_ += bytesToRead;
158 return bytesToRead;
159 }
160
ReadByte()161 int BufferMetadataStream::ReadByte()
162 {
163 if (buffer_ == nullptr) {
164 return -1;
165 }
166 if (currentOffset_ >= bufferSize_) {
167 IMAGE_LOGE("BufferMetadataStream::ReadByte failed, current offset exceeds buffer size, "
168 "currentOffset:%{public}ld, bufferSize:%{public}ld",
169 currentOffset_, bufferSize_);
170 return -1;
171 }
172
173 if (currentOffset_ < bufferSize_) {
174 return buffer_[currentOffset_++];
175 }
176 return -1;
177 }
178
Seek(long offset,SeekPos pos)179 long BufferMetadataStream::Seek(long offset, SeekPos pos)
180 {
181 switch (pos) {
182 case SeekPos::BEGIN:
183 currentOffset_ = offset;
184 break;
185 case SeekPos::CURRENT:
186 currentOffset_ += offset;
187 break;
188 case SeekPos::END:
189 currentOffset_ = bufferSize_ + offset;
190 break;
191 default:
192 return -1;
193 }
194
195 if (currentOffset_ > bufferSize_) {
196 currentOffset_ = bufferSize_;
197 }
198
199 return currentOffset_;
200 }
201
Tell()202 long BufferMetadataStream::Tell()
203 {
204 return currentOffset_;
205 }
206
IsEof()207 bool BufferMetadataStream::IsEof()
208 {
209 return currentOffset_ >= bufferSize_;
210 }
211
IsOpen()212 bool BufferMetadataStream::IsOpen()
213 {
214 return true;
215 }
216
Close()217 void BufferMetadataStream::Close()
218 {
219 if (memoryMode_ == Dynamic && buffer_ != originData_ && buffer_ != nullptr) {
220 delete[] buffer_;
221 buffer_ = nullptr;
222 }
223 currentOffset_ = 0;
224 }
225
Open(OpenMode mode)226 bool BufferMetadataStream::Open(OpenMode mode)
227 {
228 return true;
229 }
230
Flush()231 bool BufferMetadataStream::Flush()
232 {
233 return true;
234 }
235
GetAddr(bool isWriteable)236 byte *BufferMetadataStream::GetAddr(bool isWriteable)
237 {
238 return buffer_;
239 }
240
CopyFrom(MetadataStream & src)241 bool BufferMetadataStream::CopyFrom(MetadataStream &src)
242 {
243 if (!src.IsOpen()) {
244 IMAGE_LOGE("BufferMetadataStream::CopyFrom failed, source stream is not open");
245 return false;
246 }
247 if (src.GetSize() == 0) {
248 return true;
249 }
250 if (memoryMode_ == Fix) {
251 if (src.GetSize() > static_cast<ssize_t>(capacity_)) {
252 // If the memory is fixed and the source size is too large, do not copy the data
253 IMAGE_LOGE("BufferMetadataStream::CopyFrom failed, source size is larger than capacity, "
254 "source size:%{public}zu, capacity:%{public}ld",
255 src.GetSize(), capacity_);
256 return false;
257 }
258 }
259
260 // Clear the current buffer
261 if (memoryMode_ == Dynamic) {
262 if (buffer_ != nullptr && buffer_ != originData_) {
263 delete[] buffer_;
264 buffer_ = nullptr;
265 }
266 ssize_t estimatedSize = ((src.GetSize() + METADATA_STREAM_PAGE_SIZE - 1) / METADATA_STREAM_PAGE_SIZE) *
267 METADATA_STREAM_PAGE_SIZE; // Ensure it is a multiple of 32k
268 buffer_ = new (std::nothrow) byte[estimatedSize];
269 if (buffer_ == nullptr) {
270 IMAGE_LOGE("BufferMetadataStream::CopyFrom failed, insufficient memory for buffer allocation");
271 return false;
272 }
273 capacity_ = estimatedSize;
274 }
275
276 currentOffset_ = 0;
277 bufferSize_ = 0;
278
279 // Read data from the source ImageStream and write it to the current buffer
280 if (!ReadAndWriteData(src)) {
281 return false;
282 }
283 return true;
284 }
285
ReadAndWriteData(MetadataStream & src)286 bool BufferMetadataStream::ReadAndWriteData(MetadataStream &src)
287 {
288 src.Seek(0, SeekPos::BEGIN);
289 ssize_t buffer_size = std::min((ssize_t)METADATA_STREAM_PAGE_SIZE, src.GetSize());
290 if (buffer_size > METADATA_STREAM_PAGE_SIZE) {
291 return false;
292 }
293 byte *tempBuffer = new (std::nothrow) byte[buffer_size];
294 if (tempBuffer == nullptr) {
295 IMAGE_LOGE("BufferMetadataStream::ReadAndWriteData failed, insufficient memory for temporary buffer");
296 return false;
297 }
298 while (!src.IsEof()) {
299 ssize_t bytesRead = src.Read(tempBuffer, buffer_size);
300 if (bytesRead > 0) {
301 if (Write(tempBuffer, bytesRead) == -1) {
302 IMAGE_LOGE("BufferMetadataStream::ReadAndWriteData failed, unable to write to buffer");
303 HandleWriteFailure();
304 delete[] tempBuffer;
305 return false;
306 }
307 }
308 }
309 delete[] tempBuffer;
310 return true;
311 }
312
HandleWriteFailure()313 void BufferMetadataStream::HandleWriteFailure()
314 {
315 if (memoryMode_ == Dynamic && buffer_ != originData_) {
316 delete[] buffer_;
317 buffer_ = nullptr;
318 capacity_ = 0;
319 }
320 bufferSize_ = 0;
321 currentOffset_ = 0;
322 }
323
GetSize()324 ssize_t BufferMetadataStream::GetSize()
325 {
326 return bufferSize_;
327 }
328
Release()329 byte *BufferMetadataStream::Release()
330 {
331 byte *ret = buffer_;
332 buffer_ = nullptr;
333 capacity_ = 0;
334 bufferSize_ = 0;
335 currentOffset_ = 0;
336 return ret;
337 }
338
CalculateNewCapacity(long currentOffset,ssize_t size)339 long BufferMetadataStream::CalculateNewCapacity(long currentOffset, ssize_t size)
340 {
341 long newCapacity;
342 switch (expandCount_) {
343 case INITIAL_EXPANSION:
344 newCapacity =
345 ((currentOffset + size + METADATA_STREAM_INITIAL_CAPACITY - 1) / METADATA_STREAM_INITIAL_CAPACITY) *
346 METADATA_STREAM_INITIAL_CAPACITY;
347 break;
348 case SECOND_EXPANSION:
349 newCapacity =
350 ((currentOffset + size + METADATA_STREAM_CAPACITY_512KB - 1) / METADATA_STREAM_CAPACITY_512KB) *
351 METADATA_STREAM_CAPACITY_512KB;
352 break;
353 case THIRD_EXPANSION:
354 newCapacity = ((currentOffset + size + METADATA_STREAM_CAPACITY_2MB - 1) / METADATA_STREAM_CAPACITY_2MB) *
355 METADATA_STREAM_CAPACITY_2MB;
356 break;
357 case FOURTH_EXPANSION:
358 newCapacity = ((currentOffset + size + METADATA_STREAM_CAPACITY_5MB - 1) / METADATA_STREAM_CAPACITY_5MB) *
359 METADATA_STREAM_CAPACITY_5MB;
360 break;
361 case FIFTH_EXPANSION:
362 newCapacity = ((currentOffset + size + METADATA_STREAM_CAPACITY_15MB - 1) / METADATA_STREAM_CAPACITY_15MB) *
363 METADATA_STREAM_CAPACITY_15MB;
364 break;
365 default:
366 newCapacity = ((currentOffset + size + METADATA_STREAM_CAPACITY_30MB - 1) / METADATA_STREAM_CAPACITY_30MB) *
367 METADATA_STREAM_CAPACITY_30MB;
368 break;
369 }
370 return newCapacity;
371 }
372 } // namespace Media
373 } // namespace OHOS
374