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