comparison foosdk/sdk/foobar2000/SDK/titleformat.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
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 };