Mercurial > foo_out_sdl
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 }; |
