• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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