#pragma once #include #include #include #include #include #include #include #include #include #include "strcmp.h" #include "dynarr.h" #include "themeinfo.h" #include "nstring.h" #include "filepath.h" class vemanifest { public: enum class TextColor { dark = 0x000000, light = 0xFFFFFF }; vemanifest (): available (false) {} vemanifest (LPCSTR filename): available (false) { create (filename); } vemanifest (const std::string &filename): available (false) { create (filename); } vemanifest (LPCWSTR filename): available (false) { create (filename); } vemanifest (const std::wstring &filename): available (false) { create (filename); } vemanifest (std::ifstream &stream): available (false) { create (stream); } vemanifest (std::fstream &stream): available (false) { create (stream); } vemanifest (FILE *file): available (false) { create (file); } ~vemanifest () { destroy (); } bool create (LPCSTR filename) { destroy (); pugi::xml_parse_result result = doc.load_file (filename); available = result; return available; } bool create (const std::string &filename) { return create (filename.c_str ()); } bool create (LPCWSTR filename) { destroy (); std::wstring ws (filename); std::string s = to_utf8 (ws); pugi::xml_parse_result result = doc.load_file (s.c_str ()); available = result; return available; } bool create (const std::wstring &filename) { return create (filename.c_str ()); } bool create (std::ifstream &stream) { destroy (); std::stringstream buffer; buffer << stream.rdbuf (); std::string content = buffer.str (); pugi::xml_parse_result result = doc.load_string (content.c_str ()); available = result; return available; } bool create (std::fstream &stream) { destroy (); std::stringstream buffer; buffer << stream.rdbuf (); std::string content = buffer.str (); pugi::xml_parse_result result = doc.load_string (content.c_str ()); available = result; return available; } bool create (FILE *file) { destroy (); if (!file) { return false; } fseek (file, 0, SEEK_END); long length = ftell (file); fseek (file, 0, SEEK_SET); std::string content (length, '\0'); fread (&content [0], 1, length, file); pugi::xml_parse_result result = doc.load_string (content.c_str ()); available = result; return available; } void destroy () { if (!available) return; doc.reset (); available = false; } bool valid () const { return available; } std::string display_name (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); return visual ? visual.attribute ("DisplayName").as_string () : ""; } std::wstring display_name (const std::wstring &id = L"App") const { return pugi::as_wide (this->display_name (pugi::as_utf8 (id))); } std::string logo (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); if (!visual) return ""; std::string logo = visual.attribute ("Logo").as_string (); return !logo.empty () ? logo : visual.attribute ("Square150x150Logo").as_string (); } std::wstring logo (const std::wstring &id = L"App") const { return pugi::as_wide (this->logo (pugi::as_utf8 (id))); } std::string small_logo (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); if (!visual) return ""; std::string smallLogo = visual.attribute ("SmallLogo").as_string (); return !smallLogo.empty () ? smallLogo : visual.attribute ("Square70x70Logo").as_string (); } std::wstring small_logo (const std::wstring &id = L"App") const { return pugi::as_wide (this->small_logo (pugi::as_utf8 (id))); } TextColor foreground_text (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); if (!visual) return TextColor::dark; std::string fg = visual.attribute ("ForegroundText").as_string (); return (fg == "light") ? TextColor::light : TextColor::dark; } TextColor foreground_text (const std::wstring &id = L"App") const { return (this->foreground_text (pugi::as_utf8 (id))); } std::string lnk_32x32_logo (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); return visual ? visual.attribute ("Lnk32x32Logo").as_string () : ""; } std::wstring lnk_32x32_logo (const std::wstring &id = L"App") const { return pugi::as_wide (this->lnk_32x32_logo (pugi::as_utf8 (id))); } std::string item_display_logo (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); if (!visual) return ""; std::string itemLogo = visual.attribute ("ItemDisplayLogo").as_string (); if (!itemLogo.empty ()) return itemLogo; itemLogo = visual.attribute ("Lnk32x32Logo").as_string (); return !itemLogo.empty () ? itemLogo : visual.attribute ("Square44x44Logo").as_string (); } std::wstring item_display_logo (const std::wstring &id = L"App") const { return pugi::as_wide (this->item_display_logo (pugi::as_utf8 (id))); } bool show_name_on_tile (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); return visual ? (std::string (visual.attribute ("ShowNameOnSquare150x150Logo").as_string ()) == "on") : false; } bool show_name_on_tile (const std::wstring &id = L"App") const { return (this->show_name_on_tile (pugi::as_utf8 (id))); } std::string background_color (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); return visual ? visual.attribute ("BackgroundColor").as_string () : ""; } std::wstring background_color (const std::wstring &id = L"App") const { return pugi::as_wide (this->background_color (pugi::as_utf8 (id))); } std::string splash_screen_image (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); if (!visual) return ""; pugi::xml_node splash = visual.child ("SplashScreen"); return splash ? splash.attribute ("Image").as_string () : ""; } std::wstring splash_screen_image (const std::wstring &id = L"App") const { return pugi::as_wide (this->splash_screen_image (pugi::as_utf8 (id))); } std::string splash_screen_backgroundcolor (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); if (!visual) return ""; pugi::xml_node splash = visual.child ("SplashScreen"); std::string bg = splash ? splash.attribute ("BackgroundColor").as_string () : ""; return !bg.empty () ? bg : visual.attribute ("BackgroundColor").as_string (); } std::wstring splash_screen_backgroundcolor (const std::wstring &id = L"App") const { return pugi::as_wide (this->splash_screen_backgroundcolor (pugi::as_utf8 (id))); } std::string splash_screen_backgroundcolor_darkmode (const std::string &id = "App") const { pugi::xml_node visual = visual_element_node (id); if (!visual) return ""; pugi::xml_node splash = visual.child ("SplashScreen"); std::string bg = splash ? splash.attribute ("DarkModeBackgroundColor").as_string () : ""; return !bg.empty () ? bg : visual.attribute ("DarkModeBackgroundColor").as_string (); } std::wstring splash_screen_backgroundcolor_darkmode (const std::wstring &id = L"App") const { return pugi::as_wide (this->splash_screen_backgroundcolor_darkmode (pugi::as_utf8 (id))); } bool is_appid_exists (const std::string &id) const { pugi::xml_node root = doc.document_element (); std::string rootName = root.name (); if (rootName == "Applications") { for (pugi::xml_node app : root.children ("Application")) { pugi::xml_attribute attr = app.attribute ("Id"); if (attr && LabelEqual (std::string (attr.value ()), id)) return true; } return pugi::xml_node (); } else if (rootName == "Application") { pugi::xml_attribute attr = root.attribute ("Id"); if (attr && LabelEqual (std::string (attr.value ()), id)) return true; } return false; } bool is_appid_exists (const std::wstring &id) const { return this->is_appid_exists (pugi::as_utf8 (id)); } size_t app_ids (std::vector &output) const { if (!&output) return 0; output.clear (); pugi::xml_node root = doc.document_element (); std::string rootName = root.name (); if (rootName == "Applications") { for (pugi::xml_node app : root.children ("Application")) { pugi::xml_attribute attr = app.attribute ("Id"); if (attr) { LPCSTR lp = attr.value (); if (lp) push_unique (output, std::string (lp)); } } } else if (rootName == "Application") { pugi::xml_attribute attr = root.attribute ("Id"); if (attr) { if (attr) { LPCSTR lp = attr.value (); if (lp) push_unique (output, std::string (lp)); } } } if (!output.size ()) push_unique (output, std::string ("App")); return output.size (); } size_t app_ids (std::vector &output) const { if (!&output) return 0; output.clear (); pugi::xml_node root = doc.document_element (); std::string rootName = root.name (); if (rootName == "Applications") { for (pugi::xml_node app : root.children ("Application")) { pugi::xml_attribute attr = app.attribute ("Id"); if (attr) { LPCSTR lp = attr.value (); if (lp) push_unique (output, pugi::as_wide (lp)); } } } else if (rootName == "Application") { pugi::xml_attribute attr = root.attribute ("Id"); if (attr) { if (attr) { LPCSTR lp = attr.value (); if (lp) push_unique (output, pugi::as_wide (lp)); } } } if (!output.size ()) push_unique (output, std::wstring (L"App")); return output.size (); } private: pugi::xml_document doc; bool available; // 根据 id 查找 VisualElements 节点:若根节点为 ,遍历所有 查找其 节点中属性 Id 等于 id;若根节点为 ,直接返回其 pugi::xml_node visual_element_node (const std::string &id) const { pugi::xml_node root = doc.document_element (); std::string rootName = root.name (); if (rootName == "Applications") { for (pugi::xml_node app : root.children ("Application")) { pugi::xml_attribute attr = app.attribute ("Id"); if (attr && LabelEqual (std::string (attr.value ()), id)) { pugi::xml_node visual = app.child ("VisualElements"); if (visual) return visual; } } return pugi::xml_node (); } else if (rootName == "Application") return root.child ("VisualElements"); return pugi::xml_node (); } std::string to_utf8 (const std::wstring &wstr) const { std::wstring_convert > conv; return conv.to_bytes (wstr); } }; class resxmldoc { private: std::wstring filepath; pugi::xml_document doc; bool available = false; std::string to_utf8 (const std::wstring &wstr) const { std::wstring_convert > conv; return conv.to_bytes (wstr); } public: resxmldoc (const std::wstring &xmlpath) { create (xmlpath); } void destroy () { if (!available) return; doc.reset (); available = false; } ~resxmldoc () { destroy (); } bool create (const std::wstring &xmlpath) { destroy (); std::wstring ws (filepath = xmlpath); std::string s = to_utf8 (ws); pugi::xml_parse_result result = doc.load_file (s.c_str ()); available = result; return available; } std::string get (const std::string &id) const { auto root = doc.first_child (); auto nodes = root.children (); for (auto it : nodes) { if (IsNormalizeStringEquals (std::string (it.attribute ("id").as_string ()), id)) { auto scales = it.children (); std::map s_v; for (auto it_s : scales) { std::string dpi = it_s.attribute ("dpi").as_string (); if (IsNormalizeStringEquals (dpi.c_str (), "default")) { s_v [0] = it_s.text ().get (); } else { try { s_v [it_s.attribute ("dpi").as_int ()] = it_s.text ().get (); } catch (...) {} } } std::vector > existfilepath; { std::vector > vec (s_v.begin (), s_v.end ()); std::sort (vec.begin (), vec.end (), [] (auto &a, auto &b) { return a.second < b.second; }); for (auto &it_ss : vec) { it_ss.second = pugi::as_utf8 (CombinePath (GetFileDirectoryW (filepath), pugi::as_wide (it_ss.second))); if (IsFileExists (pugi::as_wide (it_ss.second))) existfilepath.push_back (it_ss); } } int dpipercent = GetDPI (); for (auto &it_path : existfilepath) { if (it_path.first >= dpipercent) return it_path.second; } if (!existfilepath.empty ()) return existfilepath.at (0).second; return ""; break; } } return ""; } std::wstring get (const std::wstring &id) const { return pugi::as_wide (get (WStringToString (id))); } std::wstring operator [] (const std::wstring &id) const { return get (id); } std::wstring operator [] (const std::wstring &id) { return get (id); } std::string operator [] (const std::string &id) const { return get (id); } std::string operator [] (const std::string &id) { return get (id); } };