Remove tinyxml2 & add pugixml
This commit is contained in:
parent
3ce09fb1b1
commit
c0d1307598
|
|
@ -1,10 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\src\3rd-party\tinyxml2\tinyxml2.h" />
|
<ClInclude Include="..\..\..\src\3rd-party\pugixml\pugixml.hpp" />
|
||||||
|
<ClInclude Include="..\..\..\src\3rd-party\pugixml\pugiconfig.hpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\..\src\3rd-party\tinyxml2\tinyxml2.cpp" />
|
<ClCompile Include="..\..\..\src\3rd-party\pugixml\pugixml.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
|
@ -18,7 +19,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{AB47E875-85E5-4105-A71E-88930EAAB910}</ProjectGuid>
|
<ProjectGuid>{AB47E875-85E5-4105-A71E-88930EAAB910}</ProjectGuid>
|
||||||
<RootNamespace>libtinyxml2</RootNamespace>
|
<RootNamespace>pugixml</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
|
@ -14,7 +14,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kiwano-physics", "kiwano-ph
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd-party", "3rd-party", "{2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd-party", "3rd-party", "{2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtinyxml2", "3rd-party\tinyxml2\libtinyxml2.vcxproj", "{AB47E875-85E5-4105-A71E-88930EAAB910}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pugixml", "3rd-party\pugixml\libpugixml.vcxproj", "{AB47E875-85E5-4105-A71E-88930EAAB910}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libimgui", "3rd-party\imgui\libimgui.vcxproj", "{7FA1E56D-62AC-47D1-97D1-40B302724198}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libimgui", "3rd-party\imgui\libimgui.vcxproj", "{7FA1E56D-62AC-47D1-97D1-40B302724198}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\3rd-party\tinyxml2\libtinyxml2.vcxproj">
|
<ProjectReference Include="..\3rd-party\pugixml\libpugixml.vcxproj">
|
||||||
<Project>{ab47e875-85e5-4105-a71e-88930eaab910}</Project>
|
<Project>{ab47e875-85e5-4105-a71e-88930eaab910}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
* pugixml parser - version 1.10
|
||||||
|
* --------------------------------------------------------
|
||||||
|
* Copyright (C) 2006-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||||
|
* Report bugs and download new versions at https://pugixml.org/
|
||||||
|
*
|
||||||
|
* This library is distributed under the MIT License. See notice at the end
|
||||||
|
* of this file.
|
||||||
|
*
|
||||||
|
* This work is based on the pugxml parser, which is:
|
||||||
|
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HEADER_PUGICONFIG_HPP
|
||||||
|
#define HEADER_PUGICONFIG_HPP
|
||||||
|
|
||||||
|
// Uncomment this to enable wchar_t mode
|
||||||
|
// #define PUGIXML_WCHAR_MODE
|
||||||
|
|
||||||
|
// Uncomment this to enable compact mode
|
||||||
|
// #define PUGIXML_COMPACT
|
||||||
|
|
||||||
|
// Uncomment this to disable XPath
|
||||||
|
// #define PUGIXML_NO_XPATH
|
||||||
|
|
||||||
|
// Uncomment this to disable STL
|
||||||
|
// #define PUGIXML_NO_STL
|
||||||
|
|
||||||
|
// Uncomment this to disable exceptions
|
||||||
|
// #define PUGIXML_NO_EXCEPTIONS
|
||||||
|
|
||||||
|
// Set this to control attributes for public classes/functions, i.e.:
|
||||||
|
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||||
|
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||||
|
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||||
|
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||||
|
|
||||||
|
// Tune these constants to adjust memory-related behavior
|
||||||
|
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||||
|
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||||
|
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
// Uncomment this to switch to header-only version
|
||||||
|
// #define PUGIXML_HEADER_ONLY
|
||||||
|
|
||||||
|
// Uncomment this to enable long long support
|
||||||
|
// #define PUGIXML_HAS_LONG_LONG
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2006-2019 Arseny Kapoulkine
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following
|
||||||
|
* conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,18 +0,0 @@
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the authors be held liable for any
|
|
||||||
damages arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any
|
|
||||||
purpose, including commercial applications, and to alter it and
|
|
||||||
redistribute it freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must
|
|
||||||
not claim that you wrote the original software. If you use this
|
|
||||||
software in a product, an acknowledgment in the product documentation
|
|
||||||
would be appreciated but is not required.
|
|
||||||
|
|
||||||
2. Altered source versions must be plainly marked as such, and
|
|
||||||
must not be misrepresented as being the original software.
|
|
||||||
|
|
||||||
3. This notice may not be removed or altered from any source
|
|
||||||
distribution.
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -28,7 +28,7 @@ namespace kiwano
|
||||||
namespace __resource_cache_01
|
namespace __resource_cache_01
|
||||||
{
|
{
|
||||||
bool LoadJsonData(ResourceCache* loader, Json const& json_data);
|
bool LoadJsonData(ResourceCache* loader, Json const& json_data);
|
||||||
bool LoadXmlData(ResourceCache* loader, const tinyxml2::XMLElement* elem);
|
bool LoadXmlData(ResourceCache* loader, const pugi::xml_node& elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|
@ -38,7 +38,7 @@ namespace kiwano
|
||||||
{ L"0.1", __resource_cache_01::LoadJsonData },
|
{ L"0.1", __resource_cache_01::LoadJsonData },
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<String, Function<bool(ResourceCache*, const tinyxml2::XMLElement*)>> load_xml_funcs = {
|
Map<String, Function<bool(ResourceCache*, const pugi::xml_node&)>> load_xml_funcs = {
|
||||||
{ L"latest", __resource_cache_01::LoadXmlData },
|
{ L"latest", __resource_cache_01::LoadXmlData },
|
||||||
{ L"0.1", __resource_cache_01::LoadXmlData },
|
{ L"0.1", __resource_cache_01::LoadXmlData },
|
||||||
};
|
};
|
||||||
|
|
@ -57,7 +57,7 @@ namespace kiwano
|
||||||
{
|
{
|
||||||
if (!FileSystem::instance().IsFileExists(file_path))
|
if (!FileSystem::instance().IsFileExists(file_path))
|
||||||
{
|
{
|
||||||
KGE_WARN(L"ResourceCache::LoadFromJsonFile failed: File not found.");
|
KGE_ERROR(L"ResourceCache::LoadFromJsonFile failed: File not found.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,12 +74,12 @@ namespace kiwano
|
||||||
}
|
}
|
||||||
catch (std::wifstream::failure& e)
|
catch (std::wifstream::failure& e)
|
||||||
{
|
{
|
||||||
KGE_WARN(L"ResourceCache::LoadFromJsonFile failed: Cannot open file. (%s)", oc::string_to_wide(e.what()).c_str());
|
KGE_ERROR(L"ResourceCache::LoadFromJsonFile failed: Cannot open file. (%s)", oc::string_to_wide(e.what()).c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (oc::json_exception& e)
|
catch (oc::json_exception& e)
|
||||||
{
|
{
|
||||||
KGE_WARN(L"ResourceCache::LoadFromJsonFile failed: Cannot parse to JSON. (%s)", oc::string_to_wide(e.what()).c_str());
|
KGE_ERROR(L"ResourceCache::LoadFromJsonFile failed: Cannot parse to JSON. (%s)", oc::string_to_wide(e.what()).c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return LoadFromJson(json_data);
|
return LoadFromJson(json_data);
|
||||||
|
|
@ -107,7 +107,7 @@ namespace kiwano
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
KGE_WARN(L"ResourceCache::LoadFromJson failed: JSON data is invalid. (%s)", oc::string_to_wide(e.what()).c_str());
|
KGE_ERROR(L"ResourceCache::LoadFromJson failed: JSON data is invalid. (%s)", oc::string_to_wide(e.what()).c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -117,48 +117,35 @@ namespace kiwano
|
||||||
{
|
{
|
||||||
if (!FileSystem::instance().IsFileExists(file_path))
|
if (!FileSystem::instance().IsFileExists(file_path))
|
||||||
{
|
{
|
||||||
KGE_WARN(L"ResourceCache::LoadFromXmlFile failed: File not found.");
|
KGE_ERROR(L"ResourceCache::LoadFromXmlFile failed: File not found.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tinyxml2::XMLDocument doc;
|
pugi::xml_document doc;
|
||||||
std::wifstream ifs;
|
pugi::xml_parse_result result = doc.load_file(file_path.c_str(), pugi::parse_default, pugi::encoding_auto);
|
||||||
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
|
||||||
|
|
||||||
try
|
if (result)
|
||||||
{
|
{
|
||||||
String full_path = FileSystem::instance().GetFullPathForFile(file_path);
|
return LoadFromXml(doc);
|
||||||
ifs.open(full_path.c_str());
|
|
||||||
|
|
||||||
StringStream ss;
|
|
||||||
ss << ifs.rdbuf();
|
|
||||||
|
|
||||||
if (tinyxml2::XML_SUCCESS != doc.Parse(ss.str().c_str()))
|
|
||||||
{
|
|
||||||
KGE_WARN(L"ResourceCache::LoadFromXmlFile failed: %s (%s)",
|
|
||||||
tinyxml2::XMLDocument::ErrorIDToName(doc.ErrorID()), doc.ErrorStr());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (std::wifstream::failure& e)
|
else
|
||||||
{
|
{
|
||||||
KGE_WARN(L"ResourceCache::LoadFromXmlFile failed: Cannot open file. (%s)", oc::string_to_wide(e.what()).c_str());
|
KGE_ERROR(L"XML [%s] parsed with errors: %s", file_path.c_str(), result.description());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoadFromXml(&doc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResourceCache::LoadFromXml(const tinyxml2::XMLDocument* doc)
|
bool ResourceCache::LoadFromXml(const ResourceCache::XmlDocument& doc)
|
||||||
{
|
{
|
||||||
if (doc)
|
if (doc)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (auto root = doc->FirstChildElement(L"resources"))
|
if (pugi::xml_node root = doc.child(L"resources"))
|
||||||
{
|
{
|
||||||
String version;
|
String version;
|
||||||
if (auto ver = root->FirstChildElement(L"version")) version = ver->GetText();
|
if (auto version_node = root.child(L"version"))
|
||||||
|
version = version_node.value();
|
||||||
|
|
||||||
auto load = load_xml_funcs.find(version);
|
auto load = load_xml_funcs.find(version);
|
||||||
if (load != load_xml_funcs.end())
|
if (load != load_xml_funcs.end())
|
||||||
|
|
@ -488,43 +475,43 @@ namespace kiwano
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadXmlData(ResourceCache* loader, const tinyxml2::XMLElement* elem)
|
bool LoadXmlData(ResourceCache* loader, const pugi::xml_node& elem)
|
||||||
{
|
{
|
||||||
GlobalData global_data;
|
GlobalData global_data;
|
||||||
if (auto path = elem->FirstChildElement(L"path"))
|
if (auto path = elem.child(L"path"))
|
||||||
{
|
{
|
||||||
global_data.path = path->GetText();
|
global_data.path = path.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto images = elem->FirstChildElement(L"images"))
|
if (auto images = elem.child(L"images"))
|
||||||
{
|
{
|
||||||
for (auto image = images->FirstChildElement(); image; image = image->NextSiblingElement())
|
for (auto image : images.children())
|
||||||
{
|
{
|
||||||
String id, type, file;
|
String id, type, file;
|
||||||
int rows = 0, cols = 0;
|
int rows = 0, cols = 0;
|
||||||
|
|
||||||
if (auto attr = image->Attribute(L"id")) id.assign(attr); // assign() copies attr content
|
if (auto attr = image.attribute(L"id")) id = attr.value();
|
||||||
if (auto attr = image->Attribute(L"type")) type = attr; // operator=() just holds attr pointer
|
if (auto attr = image.attribute(L"type")) type = attr.value();
|
||||||
if (auto attr = image->Attribute(L"file")) file = attr;
|
if (auto attr = image.attribute(L"file")) file = attr.value();
|
||||||
if (auto attr = image->IntAttribute(L"rows")) rows = attr;
|
if (auto attr = image.attribute(L"rows")) rows = attr.as_int(0);
|
||||||
if (auto attr = image->IntAttribute(L"cols")) cols = attr;
|
if (auto attr = image.attribute(L"cols")) cols = attr.as_int(0);
|
||||||
|
|
||||||
if (rows || cols)
|
if (rows || cols)
|
||||||
{
|
{
|
||||||
float padding_x = 0, padding_y = 0;
|
float padding_x = 0, padding_y = 0;
|
||||||
if (auto attr = image->FloatAttribute(L"padding-x")) padding_x = attr;
|
if (auto attr = image.attribute(L"padding-x")) padding_x = attr.as_float(0.0f);
|
||||||
if (auto attr = image->FloatAttribute(L"padding-y")) padding_y = attr;
|
if (auto attr = image.attribute(L"padding-y")) padding_y = attr.as_float(0.0f);
|
||||||
|
|
||||||
if (!LoadTexturesFromData(loader, &global_data, &id, &file, rows, cols, padding_x, padding_y))
|
if (!LoadTexturesFromData(loader, &global_data, &id, &file, rows, cols, padding_x, padding_y))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.empty() && !image->NoChildren())
|
if (file.empty() && !image.empty())
|
||||||
{
|
{
|
||||||
Vector<const wchar_t*> files_arr;
|
Vector<const wchar_t*> files_arr;
|
||||||
for (auto file = image->FirstChildElement(); file; file = file->NextSiblingElement())
|
for (auto file : image.children())
|
||||||
{
|
{
|
||||||
if (auto path = file->Attribute(L"path"))
|
if (auto path = file.attribute(L"path").value())
|
||||||
{
|
{
|
||||||
files_arr.push_back(path);
|
files_arr.push_back(path);
|
||||||
}
|
}
|
||||||
|
|
@ -540,13 +527,13 @@ namespace kiwano
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto fonts = elem->FirstChildElement(L"fonts"))
|
if (auto fonts = elem.child(L"fonts"))
|
||||||
{
|
{
|
||||||
for (auto font = fonts->FirstChildElement(); font; font = font->NextSiblingElement())
|
for (auto font : fonts.children())
|
||||||
{
|
{
|
||||||
String id, file;
|
String id, file;
|
||||||
if (auto attr = font->Attribute(L"id")) id.assign(attr);
|
if (auto attr = font.attribute(L"id")) id.assign(attr.value());
|
||||||
if (auto attr = font->Attribute(L"file")) file.assign(attr);
|
if (auto attr = font.attribute(L"file")) file.assign(attr.value());
|
||||||
|
|
||||||
if (!LoadFontsFromData(loader, &global_data, &id, &file))
|
if (!LoadFontsFromData(loader, &global_data, &id, &file))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@
|
||||||
#include <kiwano/2d/FrameSequence.h>
|
#include <kiwano/2d/FrameSequence.h>
|
||||||
#include <kiwano/renderer/GifImage.h>
|
#include <kiwano/renderer/GifImage.h>
|
||||||
#include <kiwano/renderer/Font.h>
|
#include <kiwano/renderer/Font.h>
|
||||||
#include <3rd-party/tinyxml2/tinyxml2.h>
|
|
||||||
|
#define PUGIXML_WCHAR_MODE
|
||||||
|
#include <3rd-party/pugixml/pugixml.hpp>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
|
@ -37,6 +39,8 @@ namespace kiwano
|
||||||
friend Singleton<ResourceCache>;
|
friend Singleton<ResourceCache>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using XmlDocument = pugi::xml_document;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 从 JSON 文件加载资源信息
|
/// @brief 从 JSON 文件加载资源信息
|
||||||
/// @param file_path JSON文件路径
|
/// @param file_path JSON文件路径
|
||||||
|
|
@ -55,7 +59,7 @@ namespace kiwano
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 从 XML 文档对象加载资源信息
|
/// @brief 从 XML 文档对象加载资源信息
|
||||||
/// @param doc XML文档对象
|
/// @param doc XML文档对象
|
||||||
bool LoadFromXml(const tinyxml2::XMLDocument* doc);
|
bool LoadFromXml(XmlDocument const& doc);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取资源
|
/// @brief 获取资源
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue