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