Files
EzUI/sources/Resource.cpp

250 lines
6.6 KiB
C++
Raw Permalink Normal View History

2026-01-24 22:42:46 +08:00
#include "Resource.h"
#include "EzUI.h"
namespace ezui {
//判断文件是否存在
bool DirectoryExists(const UIString& directoryNme) {
DWORD dwAttr = GetFileAttributesW(directoryNme.unicode().c_str());
if (dwAttr == DWORD(-1)) {
return false;
}
if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
{
return true;
}
return false;
}
//寻找指定目录以及目录下的所有文件
void FindFilesRecursively(const std::wstring& path, std::list<std::wstring>* result) {
WIN32_FIND_DATAW findData;
HANDLE findHandle = FindFirstFileW((path + L"/*").c_str(), &findData);
if (findHandle == INVALID_HANDLE_VALUE) {
return;
}
do
{
if (findData.cFileName[0] == L'.') {
continue;
}
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// 如果是目录,递归查找该目录
std::wstring newPath = path + L"/" + findData.cFileName;
FindFilesRecursively(newPath, result);
}
else {
std::wstring newPath = path + L"/" + findData.cFileName;
result->push_back(newPath);
}
} while (FindNextFileW(findHandle, &findData));
FindClose(findHandle);
}
}
namespace ezui {
Resource::ReadStream::ReadStream(HRSRC hRsrc) {
this->m_ptr = (char*)::LoadResource(ezui::__EzUI__HINSTANCE, hRsrc);
this->m_count = ::SizeofResource(ezui::__EzUI__HINSTANCE, hRsrc);
}
Resource::ReadStream::ReadStream(const UIString& fileName) {
this->m_ifs = new std::ifstream(fileName.unicode(), std::ios::binary);
this->m_ifs->seekg(0, std::ios::end);
this->m_count = m_ifs->tellg();
this->m_ifs->seekg(0);
}
void Resource::ReadStream::seekg(std::streampos pos) {
if (m_ifs) {
m_ifs->seekg(pos);
}
else {
this->m_pos = pos;
}
}
void Resource::ReadStream::read(char* buf, std::streamsize count) {
if (m_ifs) {
m_ifs->read(buf, count);
}
else {
::memcpy(buf, m_ptr + m_pos, count);
this->m_pos += count;
}
}
std::streampos Resource::ReadStream::tellg() {
if (m_ifs) {
return m_ifs->tellg();
}
else {
return m_pos;
}
}
const std::streamsize Resource::ReadStream::size() {
return this->m_count;
}
Resource::ReadStream::~ReadStream() {
if (m_ifs) {
delete m_ifs;
}
if (m_ptr) {
::FreeResource((HGLOBAL)m_ptr);
}
}
bool Resource::Package(const UIString& dir, const UIString& outFile, const std::function<void(const UIString&, int, int)>& packCallback) {
if (dir.empty() || !DirectoryExists(dir)) {
std::wstring err = UIString("Error: Invalid directory: \"%s\"\n").format(dir.c_str()).unicode();
OutputDebugStringW(err.c_str());
ASSERT(!"Invalid directory !");
return false;
}
std::list<Entry> items;
std::list<std::wstring> files;
FindFilesRecursively(dir.unicode(), &files);
std::streamsize headOffset = sizeof(std::streamsize);
std::ofstream ofs(outFile.unicode(), std::ios::binary);
ofs.seekp(headOffset);
for (auto& file : files) {
//读取文件大小
std::ifstream ifs(file, std::ios::binary);
ifs.seekg(0, std::ios::end);
auto size = ifs.tellg();
//读取文件
UIString data;
data.resize(size);
ifs.seekg(0);
ifs.read((char*)data.c_str(), size);
//记录文件名称,偏移,大小
Entry item;
item.Name = file;
item.Size = size;
item.Offset = headOffset;
ofs.write(data.c_str(), data.size());
headOffset += data.size();
items.push_back(item);
}
//将偏移文件头偏移信息写入到文件初始位置
ofs.seekp(0);
ofs.write((char*)(&headOffset), sizeof(headOffset));
//设置到文件条目位置
ofs.seekp(headOffset);
//处理路径
UIString root = dir + "/";
root = root.replace("\\", "/");
root = root.replace("//", "/");
if (root[root.size() - 1] == '/') {
root.erase(root.size() - 1, 1);
}
size_t pos = root.rfind("/");
if (pos != std::string::npos) {
root = root.substr(0, pos + 1);
}
int index = 0;
for (auto& item : items) {
//写入文件偏移位置
ofs.write((char*)(&item.Offset), sizeof(headOffset));
//写入文件大小
ofs.write((char*)(&item.Size), sizeof(headOffset));
//文件路径名称
UIString name = item.Name;
name = name.replace("\\", "/");
name = name.replace("//", "/");
name = name.replace(root, "", false);
ofs.write(name.c_str(), name.size() + 1);
if (packCallback) {
packCallback(name, index, items.size());
}
index++;
}
//首位呼应
ofs.write((char*)(&headOffset), sizeof(headOffset));
ofs.flush();
ofs.close();
return ofs.good();
}
void Resource::UnPackage() {
m_isGood = false;
std::list<Entry>& items = (std::list<Entry>&)this->Items;
auto& ifs = *(this->m_rStream);
if (ifs.size() < sizeof(std::streamsize) * 2) {
//不是标准的资源文件 不执行解析
ASSERT(!"error resource");
return;
}
//读取记录文件位置的偏移
ifs.seekg(0);
std::streamsize headOffset;
ifs.read((char*)&headOffset, sizeof(headOffset));
//读取末尾
ifs.seekg(ifs.size() - sizeof(headOffset));
std::streamsize endValue;
ifs.read((char*)&endValue, sizeof(headOffset));
if (headOffset != endValue) {
//不是标准的资源文件 不执行解析
ASSERT(!"error resource");
return;
}
m_isGood = true;
//开始读取文件剩余条目
ifs.seekg(headOffset);
std::streampos endPos = ifs.size() - sizeof(headOffset);
while (ifs.tellg() < endPos)
{
//读取到文件偏移位置
std::streamsize fileOffset;
ifs.read((char*)&fileOffset, sizeof(headOffset));
//读取文件大小
std::streamsize fileSize;
ifs.read((char*)&fileSize, sizeof(headOffset));
//读取文件名称
std::vector<char> buf(32768);
for (int i = 0; i < buf.size(); i++)
{
char ch;
ifs.read((char*)&ch, 1);
buf[i] = ch;
if (ch == 0) {
break;
}
}
Entry item;
item.Offset = fileOffset;
item.Size = fileSize;
item.Name = buf.data();
items.push_back(item);
}
}
Resource::Resource(const UIString& resFile) {
this->m_rStream = new ReadStream(resFile);
this->UnPackage();
}
Resource::Resource(HRSRC hRsrc) {
this->m_rStream = new ReadStream(hRsrc);
this->UnPackage();
}
Resource:: ~Resource() {
if (m_rStream) {
delete m_rStream;
}
}
bool Resource::GetFile(const UIString& fileName, std::string* out) {
for (const auto& it : this->Items) {
if (it.Name == fileName) {
out->resize(it.Size);
m_rStream->seekg(it.Offset);
m_rStream->read((char*)out->c_str(), it.Size);
return true;
}
}
return false;
}
bool Resource::IsGood() {
return m_isGood;
}
void Resource::GetFile(const Entry& item, std::string* out) {
out->resize(item.Size);
m_rStream->seekg(item.Offset);
m_rStream->read((char*)out->c_str(), item.Size);
}
};