#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* 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& 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 items; std::list 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& items = (std::list&)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 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); } };