1 /*
2 * Copyright (C) 2021 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 "file_source_stream.h"
17
18 #include <unistd.h>
19
20 #include "directory_ex.h"
21 #include "file_packer_stream.h"
22 #include "image_log.h"
23 #include "image_utils.h"
24 #include "media_errors.h"
25
26 #if !defined(_WIN32) && !defined(_APPLE) &&!defined(IOS_PLATFORM) &&!defined(A_PLATFORM)
27 #include <sys/mman.h>
28 #define SUPPORT_MMAP
29 #endif
30
31 #undef LOG_DOMAIN
32 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
33
34 #undef LOG_TAG
35 #define LOG_TAG "FileSourceStream"
36
37 namespace OHOS {
38 namespace Media {
39 using namespace std;
40 using namespace ImagePlugin;
41
FileSourceStream(std::FILE * file,size_t size,size_t offset,size_t original)42 FileSourceStream::FileSourceStream(std::FILE *file, size_t size, size_t offset, size_t original)
43 : filePtr_(file), fileSize_(size), fileOffset_(offset), fileOriginalOffset_(original)
44 {}
45
~FileSourceStream()46 FileSourceStream::~FileSourceStream()
47 {
48 IMAGE_LOGD("[FileSourceStream]destructor enter.");
49 fclose(filePtr_);
50 ResetReadBuffer();
51 }
52
CreateSourceStream(const string & pathName)53 unique_ptr<FileSourceStream> FileSourceStream::CreateSourceStream(const string &pathName)
54 {
55 string realPath;
56 if (!PathToRealPath(pathName, realPath)) {
57 IMAGE_LOGE("[FileSourceStream]input the file path exception, pathName=%{public}s", pathName.c_str());
58 return nullptr;
59 }
60 FILE *filePtr = fopen(realPath.c_str(), "rb");
61 if (filePtr == nullptr) {
62 IMAGE_LOGE("[FileSourceStream]open file fail.");
63 return nullptr;
64 }
65 size_t size = 0;
66 if (!ImageUtils::GetFileSize(realPath, size)) {
67 IMAGE_LOGE("[FileSourceStream]get the file size fail. pathName=%{public}s", pathName.c_str());
68 fclose(filePtr);
69 return nullptr;
70 }
71 int64_t offset = ftell(filePtr);
72 if (offset < 0) {
73 IMAGE_LOGE("[FileSourceStream]get the position fail.");
74 fclose(filePtr);
75 return nullptr;
76 }
77 return (unique_ptr<FileSourceStream>(new FileSourceStream(filePtr, size, offset, offset)));
78 }
79
CreateSourceStream(const int fd)80 unique_ptr<FileSourceStream> FileSourceStream::CreateSourceStream(const int fd)
81 {
82 int dupFd = dup(fd);
83 if (dupFd < 0) {
84 IMAGE_LOGE("[FileSourceStream]Fail to dup fd.");
85 return nullptr;
86 }
87
88 FILE *filePtr = fdopen(dupFd, "rb");
89 if (filePtr == nullptr) {
90 IMAGE_LOGE("[FileSourceStream]open file fail.");
91 return nullptr;
92 }
93 size_t size = 0;
94 if (!ImageUtils::GetFileSize(dupFd, size)) {
95 IMAGE_LOGE("[FileSourceStream]get the file size fail. dupFd=%{public}d", dupFd);
96 fclose(filePtr);
97 return nullptr;
98 }
99
100 int ret = fseek(filePtr, 0, SEEK_SET);
101 if (ret != 0) {
102 IMAGE_LOGE("[FileSourceStream]Go to 0 position fail, ret:%{public}d.", ret);
103 }
104
105 int64_t offset = ftell(filePtr);
106 if (offset < 0) {
107 IMAGE_LOGE("[FileSourceStream]get the position fail.");
108 fclose(filePtr);
109 return nullptr;
110 }
111 return (unique_ptr<FileSourceStream>(new FileSourceStream(filePtr, size, offset, offset)));
112 }
113
CreateSourceStream(const int fd,int32_t offset,int32_t length)114 unique_ptr<FileSourceStream> FileSourceStream::CreateSourceStream(
115 const int fd, int32_t offset, int32_t length)
116 {
117 int dupFd = dup(fd);
118 if (dupFd < 0) {
119 IMAGE_LOGE("[FileSourceStream]Fail to dup fd.");
120 return nullptr;
121 }
122
123 FILE *filePtr = fdopen(dupFd, "rb");
124 if (filePtr == nullptr) {
125 IMAGE_LOGE("[FileSourceStream]open file fail.");
126 return nullptr;
127 }
128
129 int ret = fseek(filePtr, offset, SEEK_SET);
130 if (ret != 0) {
131 IMAGE_LOGE("[FileSourceStream]Go to %{public}d position fail, ret:%{public}d.", offset, ret);
132 return nullptr;
133 }
134 return make_unique<FileSourceStream>(filePtr, length, offset, offset);
135 }
136
Read(uint32_t desiredSize,DataStreamBuffer & outData)137 bool FileSourceStream::Read(uint32_t desiredSize, DataStreamBuffer &outData)
138 {
139 if (desiredSize == 0 || filePtr_ == nullptr) {
140 IMAGE_LOGE("[FileSourceStream]read stream input parameter exception.");
141 return false;
142 }
143 if (!GetData(desiredSize, outData)) {
144 IMAGE_LOGI("[FileSourceStream]read dataStreamBuffer fail.");
145 return false;
146 }
147 fileOffset_ += outData.dataSize;
148 return true;
149 }
150
Peek(uint32_t desiredSize,DataStreamBuffer & outData)151 bool FileSourceStream::Peek(uint32_t desiredSize, DataStreamBuffer &outData)
152 {
153 if (desiredSize == 0 || filePtr_ == nullptr) {
154 IMAGE_LOGE("[FileSourceStream]peek stream input parameter exception.");
155 return false;
156 }
157 if (!GetData(desiredSize, outData)) {
158 IMAGE_LOGI("[FileSourceStream]peek dataStreamBuffer fail, desiredSize:%{public}u", desiredSize);
159 return false;
160 }
161 int ret = fseek(filePtr_, fileOffset_, SEEK_SET);
162 if (ret != 0) {
163 IMAGE_LOGE("[FileSourceStream]go to original position fail, ret:%{public}d.", ret);
164 return false;
165 }
166 return true;
167 }
168
Read(uint32_t desiredSize,uint8_t * outBuffer,uint32_t bufferSize,uint32_t & readSize)169 bool FileSourceStream::Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize)
170 {
171 if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize || desiredSize > fileSize_) {
172 IMAGE_LOGE("[FileSourceStream]input parameter exception, desiredSize:%{public}u,"
173 "bufferSize:%{public}u,fileSize_:%{public}zu.", desiredSize, bufferSize, fileSize_);
174 return false;
175 }
176 if (!GetData(desiredSize, outBuffer, bufferSize, readSize)) {
177 IMAGE_LOGI("[FileSourceStream]read outBuffer fail.");
178 return false;
179 }
180 fileOffset_ += readSize;
181 return true;
182 }
183
Peek(uint32_t desiredSize,uint8_t * outBuffer,uint32_t bufferSize,uint32_t & readSize)184 bool FileSourceStream::Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize)
185 {
186 if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize || desiredSize > fileSize_) {
187 IMAGE_LOGE("[FileSourceStream]input parameter exception, desiredSize:%{public}u,"
188 "bufferSize:%{public}u, fileSize_:%{public}zu.", desiredSize, bufferSize, fileSize_);
189 return false;
190 }
191 if (!GetData(desiredSize, outBuffer, bufferSize, readSize)) {
192 IMAGE_LOGI("[FileSourceStream]peek outBuffer fail.");
193 return false;
194 }
195 int ret = fseek(filePtr_, fileOffset_, SEEK_SET);
196 if (ret != 0) {
197 IMAGE_LOGE("[FileSourceStream]go to original position fail, ret:%{public}d.", ret);
198 return false;
199 }
200 return true;
201 }
202
Seek(uint32_t position)203 bool FileSourceStream::Seek(uint32_t position)
204 {
205 if (position > fileSize_) {
206 IMAGE_LOGE("[FileSourceStream]Seek the position greater than the file size, position:%{public}u.",
207 position);
208 return false;
209 }
210 size_t targetPosition = position + fileOriginalOffset_;
211 fileOffset_ = ((targetPosition < fileSize_) ? targetPosition : fileSize_);
212 int ret = fseek(filePtr_, fileOffset_, SEEK_SET);
213 if (ret != 0) {
214 IMAGE_LOGE("[FileSourceStream]go to offset position fail, ret:%{public}d.", ret);
215 return false;
216 }
217 return true;
218 }
219
Tell()220 uint32_t FileSourceStream::Tell()
221 {
222 return fileOffset_ - fileOriginalOffset_;
223 }
224
GetData(uint32_t desiredSize,uint8_t * outBuffer,uint32_t bufferSize,uint32_t & readSize)225 bool FileSourceStream::GetData(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize)
226 {
227 if (fileSize_ == fileOffset_) {
228 IMAGE_LOGE("[FileSourceStream]read finish, offset:%{public}zu ,dataSize%{public}zu.",
229 fileOffset_, fileSize_);
230 return false;
231 }
232 if (desiredSize > (fileSize_ - fileOffset_)) {
233 desiredSize = fileSize_ - fileOffset_;
234 }
235 size_t bytesRead = fread(outBuffer, sizeof(outBuffer[0]), desiredSize, filePtr_);
236 if (bytesRead < desiredSize) {
237 IMAGE_LOGI("read outBuffer end, bytesRead:%{public}zu, desiredSize:%{public}u, fileSize_:%{public}zu,"
238 "fileOffset_:%{public}zu", bytesRead, desiredSize, fileSize_, fileOffset_);
239 int fRes = ferror(filePtr_);
240 if (fRes) {
241 IMAGE_LOGE("fread failed, ferror:%{public}d", fRes);
242 return false;
243 }
244 }
245 readSize = bytesRead;
246 return true;
247 }
248
GetData(uint32_t desiredSize,DataStreamBuffer & outData)249 bool FileSourceStream::GetData(uint32_t desiredSize, DataStreamBuffer &outData)
250 {
251 if (fileSize_ == fileOffset_) {
252 IMAGE_LOGE("[FileSourceStream]read finish, offset:%{public}zu ,dataSize%{public}zu.",
253 fileOffset_, fileSize_);
254 return false;
255 }
256
257 if (desiredSize == 0 || desiredSize > MALLOC_MAX_LENTH) {
258 IMAGE_LOGE("[FileSourceStream]Invalid value, desiredSize out of size.");
259 return false;
260 }
261
262 ResetReadBuffer();
263 readBuffer_ = static_cast<uint8_t *>(malloc(desiredSize));
264 if (readBuffer_ == nullptr) {
265 IMAGE_LOGE("[FileSourceStream]malloc the desiredSize fail.");
266 return false;
267 }
268 outData.bufferSize = desiredSize;
269 if (desiredSize > (fileSize_ - fileOffset_)) {
270 desiredSize = fileSize_ - fileOffset_;
271 }
272 size_t bytesRead = fread(readBuffer_, sizeof(uint8_t), desiredSize, filePtr_);
273 if (bytesRead < desiredSize) {
274 IMAGE_LOGI("read outBuffer end, bytesRead:%{public}zu, desiredSize:%{public}u, fileSize_:%{public}zu,"
275 "fileOffset_:%{public}zu", bytesRead, desiredSize, fileSize_, fileOffset_);
276 int fRes = ferror(filePtr_);
277 if (fRes) {
278 IMAGE_LOGE("fread failed, ferror:%{public}d", fRes);
279 free(readBuffer_);
280 readBuffer_ = nullptr;
281 return false;
282 }
283 }
284 outData.inputStreamBuffer = static_cast<uint8_t *>(readBuffer_);
285 outData.dataSize = bytesRead;
286 return true;
287 }
288
GetStreamSize()289 size_t FileSourceStream::GetStreamSize()
290 {
291 return fileSize_ - fileOriginalOffset_;
292 }
293
DupFd(FILE * f,int & res)294 static bool DupFd(FILE *f, int &res)
295 {
296 res = fileno(f);
297 if (res < 0) {
298 IMAGE_LOGE("[FileSourceStream]Fail to fileno fd.");
299 return false;
300 }
301 res = dup(res);
302 if (res < 0) {
303 IMAGE_LOGE("[FileSourceStream]Fail to dup fd.");
304 return false;
305 }
306 return true;
307 }
308
GetDataPtr()309 uint8_t *FileSourceStream::GetDataPtr()
310 {
311 if (fileData_ != nullptr) {
312 return fileData_;
313 }
314 #ifdef SUPPORT_MMAP
315 if (!DupFd(filePtr_, mmapFd_)) {
316 return nullptr;
317 }
318 auto mmptr = ::mmap(nullptr, fileSize_, PROT_READ, MAP_SHARED, mmapFd_, 0);
319 if (mmptr == MAP_FAILED) {
320 IMAGE_LOGE("[FileSourceStream] mmap failed, errno:%{public}d", errno);
321 return nullptr;
322 }
323 fileData_ = static_cast<uint8_t*>(mmptr);
324 #endif
325 return fileData_;
326 }
327
GetStreamType()328 uint32_t FileSourceStream::GetStreamType()
329 {
330 return ImagePlugin::FILE_STREAM_TYPE;
331 }
332
ResetReadBuffer()333 void FileSourceStream::ResetReadBuffer()
334 {
335 if (readBuffer_ != nullptr) {
336 free(readBuffer_);
337 readBuffer_ = nullptr;
338 }
339 if (fileData_ != nullptr && !mmapFdPassedOn_) {
340 #ifdef SUPPORT_MMAP
341 ::munmap(fileData_, fileSize_);
342 close(mmapFd_);
343 #endif
344 }
345 fileData_ = nullptr;
346 }
347
ToOutputDataStream()348 OutputDataStream* FileSourceStream::ToOutputDataStream()
349 {
350 int dupFd = -1;
351 if (DupFd(filePtr_, dupFd)) {
352 IMAGE_LOGE("[FileSourceStream] ToOutputDataStream fd failed");
353 return nullptr;
354 }
355 return new (std::nothrow) FilePackerStream(dupFd);
356 }
357
GetMMapFd()358 int FileSourceStream::GetMMapFd()
359 {
360 mmapFdPassedOn_ = true;
361 return mmapFd_;
362 }
363 } // namespace Media
364 } // namespace OHOS
365