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