|
1
|
1 #pragma once
|
|
|
2
|
|
|
3 #include "titleformat_object.h"
|
|
|
4
|
|
|
5 namespace titleformat_inputtypes {
|
|
|
6 extern const GUID meta, unknown;
|
|
|
7 };
|
|
|
8
|
|
|
9 class NOVTABLE titleformat_text_out {
|
|
|
10 public:
|
|
|
11 virtual void write(const GUID & p_inputtype,const char * p_data,t_size p_data_length = SIZE_MAX) = 0;
|
|
|
12 void write_int(const GUID & p_inputtype,t_int64 val);
|
|
|
13 void write_int_padded(const GUID & p_inputtype,t_int64 val,t_int64 maxval);
|
|
|
14 protected:
|
|
|
15 titleformat_text_out() {}
|
|
|
16 ~titleformat_text_out() {}
|
|
|
17 };
|
|
|
18
|
|
|
19 //! This class allows custom processing of title formatting output, aware of whole substrings being passed, etc.
|
|
|
20 class NOVTABLE titleformat_text_filter {
|
|
|
21 public:
|
|
|
22 virtual void write(const GUID & p_inputtype,pfc::string_receiver & p_out,const char * p_data,t_size p_data_length) = 0;
|
|
|
23 protected:
|
|
|
24 titleformat_text_filter() {}
|
|
|
25 ~titleformat_text_filter() {}
|
|
|
26 };
|
|
|
27
|
|
|
28 class NOVTABLE titleformat_hook_function_params
|
|
|
29 {
|
|
|
30 public:
|
|
|
31 virtual t_size get_param_count() = 0;
|
|
|
32 virtual void get_param(t_size index,const char * & p_string,t_size & p_string_len) = 0;//warning: not a null-terminated string
|
|
|
33
|
|
|
34 //helper
|
|
|
35 t_size get_param_uint(t_size index);
|
|
|
36 };
|
|
|
37
|
|
|
38 class NOVTABLE titleformat_hook
|
|
|
39 {
|
|
|
40 public:
|
|
|
41 virtual bool process_field(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,bool & p_found_flag) = 0;
|
|
|
42 virtual bool process_function(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,titleformat_hook_function_params * p_params,bool & p_found_flag) = 0;
|
|
|
43 };
|
|
|
44
|
|
|
45 //! \since 2.0
|
|
|
46 class NOVTABLE titleformat_object_v2 : public titleformat_object {
|
|
|
47 FB2K_MAKE_SERVICE_INTERFACE(titleformat_object_v2, titleformat_object);
|
|
|
48 public:
|
|
|
49 //! Walk from idx=0 up until returns null.
|
|
|
50 virtual const char* enum_used_fields(size_t idx) = 0;
|
|
|
51 //! Walk from idx=0 up until returns null.
|
|
|
52 virtual const char* enum_used_functions(size_t idx) = 0;
|
|
|
53 //! Returns true if evaluation of this only references fields such as file path, which can be evaluated without accessing actual metadb data.
|
|
|
54 virtual bool requires_metadb_info() = 0;
|
|
|
55 };
|
|
|
56
|
|
|
57 //! Standard service for instantiating titleformat_object. Implemented by the core; do not reimplement.
|
|
|
58 //! To instantiate, use titleformat_compiler::get().
|
|
|
59 class NOVTABLE titleformat_compiler : public service_base {
|
|
|
60 FB2K_MAKE_SERVICE_COREAPI(titleformat_compiler);
|
|
|
61 public:
|
|
|
62 //! Returns false in case of a compilation error.
|
|
|
63 virtual bool compile(titleformat_object::ptr & p_out,const char * p_spec) = 0;
|
|
|
64 //! Helper;
|
|
|
65 void run(titleformat_hook * p_source,pfc::string_base & p_out,const char * p_spec);
|
|
|
66 //! Should never fail, falls back to %filename% in case of failure.
|
|
|
67 void compile_safe(titleformat_object::ptr & p_out,const char * p_spec);
|
|
|
68
|
|
|
69 //! Falls back to p_fallback in case of failure.
|
|
|
70 void compile_safe_ex(titleformat_object::ptr & p_out,const char * p_spec,const char * p_fallback = "<ERROR>");
|
|
|
71
|
|
|
72 //! Crashes when script can't be compiled. For use with hardcoded scripts only.
|
|
|
73 void compile_force(titleformat_object::ptr & p_out,const char * p_spec) {if (!compile(p_out,p_spec)) uBugCheck();}
|
|
|
74
|
|
|
75 titleformat_object::ptr compile(const char* spec);
|
|
|
76 titleformat_object::ptr compile_force(const char* spec);
|
|
|
77 titleformat_object::ptr compile_fallback(const char* spec, const char* fallback);
|
|
|
78
|
|
|
79
|
|
|
80 static void remove_color_marks(const char * src,pfc::string_base & out);//helper
|
|
|
81 static void remove_forbidden_chars(titleformat_text_out * p_out,const GUID & p_inputtype,const char * p_source,t_size p_source_len,const char * p_forbidden_chars);
|
|
|
82 static void remove_forbidden_chars_string_append(pfc::string_receiver & p_out,const char * p_source,t_size p_source_len,const char * p_forbidden_chars);
|
|
|
83 static void remove_forbidden_chars_string(pfc::string_base & p_out,const char * p_source,t_size p_source_len,const char * p_forbidden_chars);
|
|
|
84 };
|
|
|
85
|
|
|
86 // \since 2.0
|
|
|
87 class NOVTABLE titleformat_compiler_v2 : public titleformat_compiler {
|
|
|
88 FB2K_MAKE_SERVICE_COREAPI_EXTENSION(titleformat_compiler_v2, titleformat_compiler);
|
|
|
89 public:
|
|
|
90 virtual titleformat_object::ptr concat(pfc::list_base_const_t<titleformat_object::ptr> const&) = 0;
|
|
|
91 };
|
|
|
92
|
|
|
93
|
|
|
94 class titleformat_object_wrapper {
|
|
|
95 public:
|
|
|
96 titleformat_object_wrapper(const char * p_script) {
|
|
|
97 titleformat_compiler::get()->compile_force(m_script,p_script);
|
|
|
98 }
|
|
|
99
|
|
|
100 operator const service_ptr_t<titleformat_object> &() const {return m_script;}
|
|
|
101
|
|
|
102 private:
|
|
|
103 service_ptr_t<titleformat_object> m_script;
|
|
|
104 };
|
|
|
105
|
|
|
106
|
|
|
107 //helpers
|
|
|
108
|
|
|
109
|
|
|
110 class titleformat_text_out_impl_filter_chars : public titleformat_text_out
|
|
|
111 {
|
|
|
112 public:
|
|
|
113 inline titleformat_text_out_impl_filter_chars(titleformat_text_out * p_chain,const char * p_restricted_chars)
|
|
|
114 : m_chain(p_chain), m_restricted_chars(p_restricted_chars) {}
|
|
|
115 void write(const GUID & p_inputtype,const char * p_data,t_size p_data_length);
|
|
|
116 private:
|
|
|
117 titleformat_text_out * m_chain;
|
|
|
118 const char * m_restricted_chars;
|
|
|
119 };
|
|
|
120
|
|
|
121 class titleformat_text_out_impl_string : public titleformat_text_out {
|
|
|
122 public:
|
|
|
123 titleformat_text_out_impl_string(pfc::string_receiver & p_string) : m_string(p_string) {}
|
|
|
124 void write(const GUID &,const char * p_data,t_size p_data_length) override {m_string.add_string(p_data,p_data_length);}
|
|
|
125 private:
|
|
|
126 pfc::string_receiver & m_string;
|
|
|
127 };
|
|
|
128
|
|
|
129 class titleformat_common_methods : public service_base {
|
|
|
130 public:
|
|
|
131 virtual bool process_field(const file_info & p_info,const playable_location & p_location,titleformat_text_out * p_out,const char * p_name,t_size p_name_length,bool & p_found_flag) = 0;
|
|
|
132 virtual bool process_function(const file_info & p_info,const playable_location & p_location,titleformat_text_out * p_out,const char * p_name,t_size p_name_length,titleformat_hook_function_params * p_params,bool & p_found_flag) = 0;
|
|
|
133 virtual bool remap_meta(const file_info & p_info,t_size & p_index, const char * p_name, t_size p_name_length) = 0;
|
|
|
134
|
|
|
135 FB2K_MAKE_SERVICE_COREAPI(titleformat_common_methods);
|
|
|
136 };
|
|
|
137
|
|
|
138 class titleformat_hook_impl_file_info : public titleformat_hook
|
|
|
139 {
|
|
|
140 public:
|
|
|
141 titleformat_hook_impl_file_info(const playable_location & p_location,const file_info * p_info) : m_info(p_info), m_location(p_location) {}//caller must ensure that referenced file_info object is alive as long as the titleformat_hook_impl_file_info instance
|
|
|
142 bool process_field(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,bool & p_found_flag);
|
|
|
143 bool process_function(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,titleformat_hook_function_params * p_params,bool & p_found_flag);
|
|
|
144 protected:
|
|
|
145 bool remap_meta(t_size & p_index, const char * p_name, t_size p_name_length) {return m_api->remap_meta(*m_info,p_index,p_name,p_name_length);}
|
|
|
146 const file_info * m_info;
|
|
|
147 private:
|
|
|
148 const playable_location & m_location;
|
|
|
149 const titleformat_common_methods::ptr m_api = titleformat_common_methods::get();
|
|
|
150 };
|
|
|
151
|
|
|
152 class titleformat_hook_impl_splitter : public titleformat_hook {
|
|
|
153 public:
|
|
|
154 inline titleformat_hook_impl_splitter(titleformat_hook * p_hook1,titleformat_hook * p_hook2) : m_hook1(p_hook1), m_hook2(p_hook2) {}
|
|
|
155 bool process_field(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,bool & p_found_flag);
|
|
|
156 bool process_function(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,titleformat_hook_function_params * p_params,bool & p_found_flag);
|
|
|
157 private:
|
|
|
158 titleformat_hook * m_hook1, * m_hook2;
|
|
|
159 };
|
|
|
160
|
|
|
161 class titleformat_text_filter_impl_reserved_chars : public titleformat_text_filter {
|
|
|
162 public:
|
|
|
163 titleformat_text_filter_impl_reserved_chars(const char * p_reserved_chars) : m_reserved_chars(p_reserved_chars) {}
|
|
|
164 void write(const GUID & p_inputtype,pfc::string_receiver & p_out,const char * p_data,t_size p_data_length) override;
|
|
|
165 private:
|
|
|
166 const char * m_reserved_chars;
|
|
|
167 };
|
|
|
168
|
|
|
169 class titleformat_text_filter_impl_filename_chars : public titleformat_text_filter {
|
|
|
170 public:
|
|
|
171 void write(const GUID & p_inputType,pfc::string_receiver & p_out,const char * p_data,t_size p_dataLength) override;
|
|
|
172 };
|
|
|
173
|
|
|
174 class titleformat_text_filter_nontext_chars : public titleformat_text_filter {
|
|
|
175 public:
|
|
|
176 inline static bool isReserved(char c) { return c >= 0 && c < 0x20; }
|
|
|
177 void write(const GUID & p_inputtype,pfc::string_receiver & p_out,const char * p_data,t_size p_data_length) override;
|
|
|
178 };
|
|
|
179
|
|
|
180
|
|
|
181
|
|
|
182
|
|
|
183
|
|
|
184
|
|
|
185
|
|
|
186 class titleformat_hook_impl_list : public titleformat_hook {
|
|
|
187 public:
|
|
|
188 titleformat_hook_impl_list(t_size p_index /* zero-based! */,t_size p_total) : m_index(p_index), m_total(p_total) {}
|
|
|
189
|
|
|
190 bool process_field(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,bool & p_found_flag) override {
|
|
|
191 if (
|
|
|
192 pfc::stricmp_ascii_ex(p_name,p_name_length,"list_index",SIZE_MAX) == 0
|
|
|
193 ) {
|
|
|
194 p_out->write_int_padded(titleformat_inputtypes::unknown,m_index+1, m_total);
|
|
|
195 p_found_flag = true; return true;
|
|
|
196 } else if (
|
|
|
197 pfc::stricmp_ascii_ex(p_name,p_name_length,"list_total",SIZE_MAX) == 0
|
|
|
198 ) {
|
|
|
199 p_out->write_int(titleformat_inputtypes::unknown,m_total);
|
|
|
200 p_found_flag = true; return true;
|
|
|
201 } else {
|
|
|
202 p_found_flag = false; return false;
|
|
|
203 }
|
|
|
204 }
|
|
|
205
|
|
|
206 bool process_function(titleformat_text_out *,const char *,t_size,titleformat_hook_function_params *,bool &) override {return false;}
|
|
|
207
|
|
|
208 private:
|
|
|
209 t_size m_index, m_total;
|
|
|
210 };
|
|
|
211
|
|
|
212 class string_formatter_tf : public pfc::string_base {
|
|
|
213 [[noreturn]] static void verboten() { FB2K_BugCheck(); }
|
|
|
214 public:
|
|
|
215 string_formatter_tf(titleformat_text_out * out, const GUID & inputType = titleformat_inputtypes::meta) : m_out(out), m_inputType(inputType) {}
|
|
|
216
|
|
|
217 const char * get_ptr() const override {
|
|
|
218 verboten();
|
|
|
219 }
|
|
|
220 void add_string(const char * p_string,t_size p_length) override {
|
|
|
221 m_out->write(m_inputType,p_string,p_length);
|
|
|
222 }
|
|
|
223 void set_string(const char *,t_size) override {
|
|
|
224 verboten();
|
|
|
225 }
|
|
|
226 void truncate(t_size) override {
|
|
|
227 verboten();
|
|
|
228 }
|
|
|
229 t_size get_length() const override {
|
|
|
230 verboten();
|
|
|
231 }
|
|
|
232 char * lock_buffer(t_size) override {
|
|
|
233 verboten();
|
|
|
234 }
|
|
|
235 void unlock_buffer() override {
|
|
|
236 verboten();
|
|
|
237 }
|
|
|
238
|
|
|
239 private:
|
|
|
240 titleformat_text_out * const m_out;
|
|
|
241 const GUID m_inputType;
|
|
|
242 };
|
|
|
243
|
|
|
244
|
|
|
245 class titleformat_object_cache {
|
|
|
246 public:
|
|
|
247 titleformat_object_cache(const char * pattern) : m_pattern(pattern) {}
|
|
|
248 operator titleformat_object::ptr() {
|
|
|
249 PFC_ASSERT(core_api::assert_main_thread());
|
|
|
250 if (m_obj.is_empty()) {
|
|
|
251 titleformat_compiler::get()->compile_force(m_obj, m_pattern);
|
|
|
252 }
|
|
|
253 return m_obj;
|
|
|
254 }
|
|
|
255 private:
|
|
|
256 const char * const m_pattern;
|
|
|
257 titleformat_object::ptr m_obj;
|
|
|
258 };
|
|
|
259
|
|
|
260
|
|
|
261 class titleformat_patterns {
|
|
|
262 public:
|
|
|
263 static const char * patternAlbumSplit();
|
|
|
264 static const char * patternSortTracks();
|
|
|
265 };
|