• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 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 #define HST_LOG_TAG "FileSourcePlugin"
17 
18 #include "file_source_plugin.h"
19 #include <sys/stat.h>
20 #include "common/log.h"
21 
22 namespace OHOS {
23 namespace Media {
24 namespace Plugins {
25 namespace FileSource {
26 namespace {
GetFileSize(const std::string & fileName)27 size_t GetFileSize(const std::string& fileName)
28 {
29     size_t fileSize = 0;
30     if (!fileName.empty()) {
31         struct stat fileStatus {};
32         if (stat(fileName.c_str(), &fileStatus) == 0) {
33             fileSize = static_cast<size_t>(fileStatus.st_size);
34         }
35     }
36     return fileSize;
37 }
38 }
FileSourcePluginCreator(const std::string & name)39 std::shared_ptr<SourcePlugin> FileSourcePluginCreator(const std::string& name)
40 {
41     return std::make_shared<FileSourcePlugin>(name);
42 }
43 
FileSourceRegister(const std::shared_ptr<Register> & reg)44 Status FileSourceRegister(const std::shared_ptr<Register>& reg)
45 {
46     SourcePluginDef definition;
47     definition.name = "FileSource";
48     definition.description = "File source";
49     definition.rank = 100; // 100: max rank
50     Capability capability;
51     capability.AppendFixedKey<std::vector<ProtocolType>>(Tag::MEDIA_PROTOCOL_TYPE, {ProtocolType::FILE});
52     definition.AddInCaps(capability);
53     auto func = [](const std::string& name) -> std::shared_ptr<SourcePlugin> {
54         return std::make_shared<FileSourcePlugin>(name);
55     };
56     definition.SetCreator(func);
57     return reg->AddPlugin(definition);
58 }
59 
__anon128870440302null60 PLUGIN_DEFINITION(FileSource, LicenseType::APACHE_V2, FileSourceRegister, [] {});
61 
Alloc(size_t size)62 void* FileSourceAllocator::Alloc(size_t size)
63 {
64     if (size == 0) {
65         MEDIA_LOG_E("Invalid zero size");
66         return nullptr;
67     }
68     return static_cast<void*>(new (std::nothrow) uint8_t[size]);
69 }
70 
Free(void * ptr)71 void FileSourceAllocator::Free(void* ptr) // NOLINT: void*
72 {
73     if (ptr != nullptr) {
74         delete[](uint8_t*) ptr;
75     }
76 }
77 
FileSourcePlugin(std::string name)78 FileSourcePlugin::FileSourcePlugin(std::string name)
79     : SourcePlugin(std::move(name)), fp_(nullptr), fileSize_(0), seekable_(Seekable::SEEKABLE), position_(0)
80 {
81     MEDIA_LOG_D("IN");
82 }
83 
~FileSourcePlugin()84 FileSourcePlugin::~FileSourcePlugin()
85 {
86     MEDIA_LOG_D("IN");
87     if (fp_) {
88         std::fclose(fp_);
89         fp_ = nullptr;
90     }
91 }
92 
Init()93 Status FileSourcePlugin::Init()
94 {
95     MEDIA_LOG_D("IN");
96     mAllocator_ = std::make_shared<FileSourceAllocator>();
97     return Status::OK;
98 }
99 
Deinit()100 Status FileSourcePlugin::Deinit()
101 {
102     MEDIA_LOG_D("IN");
103     CloseFile();
104     return Status::OK;
105 }
106 
Prepare()107 Status FileSourcePlugin::Prepare()
108 {
109     MEDIA_LOG_D("IN");
110     return Status::OK;
111 }
112 
Reset()113 Status FileSourcePlugin::Reset()
114 {
115     MEDIA_LOG_D("IN");
116     CloseFile();
117     return Status::OK;
118 }
119 
GetParameter(std::shared_ptr<Meta> & meta)120 Status FileSourcePlugin::GetParameter(std::shared_ptr<Meta> &meta)
121 {
122     MEDIA_LOG_D("IN");
123     return Status::ERROR_UNIMPLEMENTED;
124 }
125 
SetParameter(const std::shared_ptr<Meta> & meta)126 Status FileSourcePlugin::SetParameter(const std::shared_ptr<Meta> &meta)
127 {
128     MEDIA_LOG_D("IN");
129     return Status::ERROR_UNIMPLEMENTED;
130 }
131 
GetAllocator()132 std::shared_ptr<Allocator> FileSourcePlugin::GetAllocator()
133 {
134     MEDIA_LOG_D("IN");
135     return mAllocator_;
136 }
137 
SetCallback(Callback * cb)138 Status FileSourcePlugin::SetCallback(Callback* cb)
139 {
140     MEDIA_LOG_D("IN");
141     return Status::ERROR_UNIMPLEMENTED;
142 }
143 
SetSource(std::shared_ptr<MediaSource> source)144 Status FileSourcePlugin::SetSource(std::shared_ptr<MediaSource> source)
145 {
146     MEDIA_LOG_D("IN");
147     auto err = ParseFileName(source->GetSourceUri());
148     if (err != Status::OK) {
149         MEDIA_LOG_E("Parse file name from uri fail, uri: " PUBLIC_LOG_S, source->GetSourceUri().c_str());
150         return err;
151     }
152     return OpenFile();
153 }
154 
Read(std::shared_ptr<Buffer> & buffer,uint64_t offset,size_t expectedLen)155 Status FileSourcePlugin::Read(std::shared_ptr<Buffer>& buffer, uint64_t offset, size_t expectedLen)
156 {
157     (void)offset;
158     if (std::feof(fp_) || (fileSize_ == position_)) {
159         MEDIA_LOG_W("It is the end of file!");
160         return Status::END_OF_STREAM;
161     }
162     if (buffer == nullptr) {
163         buffer = std::make_shared<Buffer>();
164     }
165 
166     std::shared_ptr<Memory> bufData;
167 
168     // There is no buffer, so alloc it
169     if (buffer->IsEmpty()) {
170         bufData = buffer->AllocMemory(GetAllocator(), expectedLen);
171     } else {
172         bufData = buffer->GetMemory();
173     }
174     expectedLen = std::min(static_cast<size_t>(fileSize_ - position_), expectedLen);
175     expectedLen = std::min(bufData->GetCapacity(), expectedLen);
176 
177     MEDIA_LOG_DD("buffer position " PUBLIC_LOG_U64 ", expectedLen " PUBLIC_LOG_ZU, position_, expectedLen);
178     auto size = std::fread(bufData->GetWritableAddr(expectedLen), sizeof(char), expectedLen, fp_);
179     bufData->UpdateDataSize(size);
180     position_ += bufData->GetSize();
181     MEDIA_LOG_DD("position_: " PUBLIC_LOG_U64 ", readSize: " PUBLIC_LOG_ZU, position_, bufData->GetSize());
182     return Status::OK;
183 }
184 
GetSize(uint64_t & size)185 Status FileSourcePlugin::GetSize(uint64_t& size)
186 {
187     MEDIA_LOG_DD("IN");
188     if (!fp_) {
189         MEDIA_LOG_E("Need call SetSource() to open file first");
190         return Status::ERROR_WRONG_STATE;
191     }
192     size = fileSize_;
193     MEDIA_LOG_DD("FileSize_: " PUBLIC_LOG_U64, size);
194     return Status::OK;
195 }
196 
GetSeekable()197 Seekable FileSourcePlugin::GetSeekable()
198 {
199     MEDIA_LOG_DD("IN");
200     return seekable_;
201 }
202 
SeekTo(uint64_t offset)203 Status FileSourcePlugin::SeekTo(uint64_t offset)
204 {
205     if (!fp_ || (offset > fileSize_) || (position_ == offset)) {
206         MEDIA_LOG_E("Invalid operation");
207         return Status::ERROR_WRONG_STATE;
208     }
209     std::clearerr(fp_);
210     if (std::fseek(fp_, static_cast<long int>(offset), SEEK_SET) != 0) {
211         std::clearerr(fp_);
212         (void)std::fseek(fp_, static_cast<long int>(position_), SEEK_SET);
213         MEDIA_LOG_E("Seek to " PUBLIC_LOG_U64, offset);
214         return Status::ERROR_UNKNOWN;
215     }
216     position_ = offset;
217     if (std::feof(fp_)) {
218         MEDIA_LOG_I("It is the end of file!");
219     }
220     MEDIA_LOG_D("seek to position_: " PUBLIC_LOG_U64 " success", position_);
221     return Status::OK;
222 }
223 
ParseFileName(const std::string & uri)224 Status FileSourcePlugin::ParseFileName(const std::string& uri)
225 {
226     if (uri.empty()) {
227         MEDIA_LOG_E("uri is empty");
228         return Status::ERROR_INVALID_PARAMETER;
229     }
230     MEDIA_LOG_D("uri: " PUBLIC_LOG_S, uri.c_str());
231     if (uri.find("file:/") != std::string::npos) {
232         if (uri.find('#') != std::string::npos) {
233             MEDIA_LOG_E("Invalid file uri format: " PUBLIC_LOG_S, uri.c_str());
234             return Status::ERROR_INVALID_PARAMETER;
235         }
236         auto pos = uri.find("file:");
237         if (pos == std::string::npos) {
238             MEDIA_LOG_E("Invalid file uri format: " PUBLIC_LOG_S, uri.c_str());
239             return Status::ERROR_INVALID_PARAMETER;
240         }
241         pos += 5; // 5: offset
242         if (uri.find("///", pos) != std::string::npos) {
243             pos += 2; // 2: offset
244         } else if (uri.find("//", pos) != std::string::npos) {
245             pos += 2;                 // 2: offset
246             pos = uri.find('/', pos); // skip host name
247             if (pos == std::string::npos) {
248                 MEDIA_LOG_E("Invalid file uri format: " PUBLIC_LOG_S, uri.c_str());
249                 return Status::ERROR_INVALID_PARAMETER;
250             }
251             pos++;
252         }
253         fileName_ = uri.substr(pos);
254     } else {
255         fileName_ = uri;
256     }
257     MEDIA_LOG_D("fileName_: " PUBLIC_LOG_S, fileName_.c_str());
258     return Status::OK;
259 }
260 
CheckFileStat()261 Status FileSourcePlugin::CheckFileStat()
262 {
263     struct stat fileStat;
264     if (stat(fileName_.c_str(), &fileStat) < 0) {
265         MEDIA_LOG_E("Cannot get info from " PUBLIC_LOG_S, fileName_.c_str());
266         return Status::ERROR_NOT_EXISTED;
267     }
268     if (S_ISDIR(fileStat.st_mode)) {
269         MEDIA_LOG_E(PUBLIC_LOG_S " is directory", fileName_.c_str());
270         return Status::ERROR_UNSUPPORTED_FORMAT;
271     }
272     if (S_ISSOCK(fileStat.st_mode)) {
273         MEDIA_LOG_E(PUBLIC_LOG_S " is a socket", fileName_.c_str());
274         return Status::ERROR_UNSUPPORTED_FORMAT;
275     }
276     return Status::OK;
277 }
278 
OpenFile()279 Status FileSourcePlugin::OpenFile()
280 {
281     MEDIA_LOG_D("IN");
282     auto ret = CheckFileStat();
283     if (ret != Status::OK) {
284         CloseFile();
285         return ret;
286     }
287     CloseFile();
288     fp_ = std::fopen(fileName_.c_str(), "rb");
289     if (fp_ == nullptr) {
290         MEDIA_LOG_E("Fail to load file from " PUBLIC_LOG_S, fileName_.c_str());
291         return Status::ERROR_UNKNOWN;
292     }
293     fileSize_ = GetFileSize(fileName_);
294     position_ = 0;
295     MEDIA_LOG_D("FileName_: " PUBLIC_LOG_S ", fileSize_: " PUBLIC_LOG_U64, fileName_.c_str(), fileSize_);
296     return Status::OK;
297 }
298 
CloseFile()299 void FileSourcePlugin::CloseFile()
300 {
301     if (fp_) {
302         MEDIA_LOG_I("close file");
303         std::fclose(fp_);
304         fp_ = nullptr;
305     }
306 }
307 } // namespace FileSource
308 } // namespace Plugin
309 } // namespace Media
310 } // namespace OHOS
311