libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
fileformatfactory.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
13#include <promeki/namespace.h>
14#include <promeki/string.h>
15#include <promeki/stringlist.h>
16#include <promeki/list.h>
17#include <promeki/result.h>
18#include <promeki/logger.h>
19#include <promeki/util.h>
20#include <promeki/uniqueptr.h>
21
22PROMEKI_NAMESPACE_BEGIN
23
24class IODevice;
25
51template <typename Product> class FileFormatFactory {
52 public:
59 struct Context {
60 int operation = 0;
61 String filename;
62 String formatHint;
63 IODevice *device = nullptr;
64 };
65
71 static int registerFactory(FileFormatFactory *factory) {
72 if (factory == nullptr) return -1;
73 auto &list = factoryList();
74 int ret = list.size();
75 promekiLog(Logger::LogLevel::Debug, "Registered FileFormatFactory %s", factory->name().cstr());
76 // Adopt the factory so the list owns it; otherwise
77 // every PROMEKI_REGISTER_FILE_FORMAT_FACTORY(new Foo)
78 // would leak a pointer for the lifetime of the process.
79 list.pushToBack(UniquePtr<FileFormatFactory>::takeOwnership(factory));
80 return ret;
81 }
82
91 static const FileFormatFactory *lookup(const Context &ctx) {
92 auto &list = factoryList();
93 for (const auto &f : list) {
94 if (f->canDoOperation(ctx)) return f.get();
95 }
96 return nullptr;
97 }
98
100 FileFormatFactory() = default;
101
103 virtual ~FileFormatFactory() {}
104
109 String name() const { return _name; }
110
115 const StringList &extensions() const { return _exts; }
116
122 bool isExtensionSupported(const String &filename) const {
123 size_t dot = filename.rfind('.');
124 if (dot == String::npos || dot + 1 >= filename.size()) return false;
125 String ext = filename.mid(dot + 1).toLower();
126 for (const auto &item : _exts) {
127 if (ext == item) return true;
128 }
129 return false;
130 }
131
137 bool isHintSupported(const String &hint) const {
138 String lower = hint.toLower();
139 for (const auto &item : _exts) {
140 if (lower == item) return true;
141 }
142 return false;
143 }
144
153 virtual bool canDoOperation(const Context &ctx) const { return false; }
154
162 virtual Result<Product> createForOperation(const Context &ctx) const {
163 return makeError<Product>(Error::NotImplemented);
164 }
165
166 protected:
167 String _name;
168 StringList _exts;
169
170 private:
171 static List<UniquePtr<FileFormatFactory>> &factoryList() {
172 static List<UniquePtr<FileFormatFactory>> list;
173 return list;
174 }
175};
176
182#define PROMEKI_REGISTER_FILE_FORMAT_FACTORY(product, name) \
183 [[maybe_unused]] static int PROMEKI_CONCAT(__promeki_fff_, PROMEKI_UNIQUE_ID) = \
184 FileFormatFactory<product>::registerFactory(new name);
185
186PROMEKI_NAMESPACE_END
187
188#endif // PROMEKI_ENABLE_CORE