mirror of
https://github.com/Almamu/linux-wallpaperengine.git
synced 2025-07-13 21:02:34 +08:00

- use of auto in some places (more of this to come) - use for loops instead of iterators for most of the loops - extracted glfw/glew code into it's own class - make usage of std::filesystem instead of checking things with old C libraries Signed-off-by: Alexis Maiquez <almamu@almamu.com>
174 lines
4.7 KiB
C++
174 lines
4.7 KiB
C++
#include "common.h"
|
|
#include "CPackage.h"
|
|
#include "CAssetLoadException.h"
|
|
#include "CPackageLoadException.h"
|
|
|
|
#include <utility>
|
|
#include <sstream>
|
|
|
|
using namespace WallpaperEngine::Assets;
|
|
|
|
class CPackageEntry
|
|
{
|
|
public:
|
|
CPackageEntry (std::string filename, uint32_t offset, uint32_t length) :
|
|
filename (std::move(filename)),
|
|
offset (offset),
|
|
length (length) { }
|
|
|
|
std::string filename;
|
|
uint32_t offset;
|
|
uint32_t length;
|
|
};
|
|
|
|
CPackage::CPackage (std::filesystem::path path) :
|
|
m_path (std::move(path)),
|
|
m_contents ()
|
|
{
|
|
this->init ();
|
|
}
|
|
|
|
CPackage::~CPackage()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
const void* CPackage::readFile (std::string filename, uint32_t* length) const
|
|
{
|
|
auto it = this->m_contents.find (filename);
|
|
|
|
if (it == this->m_contents.end ())
|
|
throw CAssetLoadException(filename, "Cannot find the file in the package");
|
|
|
|
// set file length if required
|
|
if (length != nullptr)
|
|
*length = (*it).second.length;
|
|
|
|
return (*it).second.address;
|
|
}
|
|
|
|
void CPackage::init ()
|
|
{
|
|
FILE* fp = fopen (this->m_path.c_str (), "rb+");
|
|
|
|
if (fp == nullptr)
|
|
throw CPackageLoadException (this->m_path, std::to_string (errno));
|
|
|
|
// first validate header
|
|
this->validateHeader (fp);
|
|
// header is okay, load everything into memory
|
|
this->loadFiles (fp);
|
|
|
|
fclose (fp);
|
|
}
|
|
|
|
char* CPackage::readSizedString (FILE* fp)
|
|
{
|
|
unsigned int length = 0;
|
|
|
|
if (fread (&length, sizeof (unsigned int), 1, fp) != 1)
|
|
sLog.exception ("Cannot read sized string length on file ", this->m_path);
|
|
|
|
// account for 0 termination of the string
|
|
length ++;
|
|
|
|
char* pointer = new char [length];
|
|
memset (pointer, 0, length);
|
|
|
|
// read only the string bytes so the last one in the memory is 0
|
|
length --;
|
|
|
|
// read data from file
|
|
if (fread (pointer, sizeof (char), length, fp) != length)
|
|
sLog.exception ("Not enough bytes to read string of length ", length, " on file ", this->m_path);
|
|
|
|
return pointer;
|
|
}
|
|
|
|
uint32_t CPackage::readInteger (FILE* fp)
|
|
{
|
|
uint32_t output;
|
|
|
|
if (fread (&output, sizeof (uint32_t), 1, fp) != 1)
|
|
sLog.exception ("Not enough bytes to read an integer from file ", this->m_path);
|
|
|
|
return output;
|
|
}
|
|
|
|
void CPackage::validateHeader (FILE* fp)
|
|
{
|
|
char* pointer = this->readSizedString (fp);
|
|
|
|
// finally validate the header version
|
|
if (strcmp ("PKGV0001", pointer) != 0 &&
|
|
strcmp ("PKGV0002", pointer) != 0 &&
|
|
strcmp ("PKGV0003", pointer) != 0 &&
|
|
strcmp ("PKGV0004", pointer) != 0 &&
|
|
strcmp ("PKGV0005", pointer) != 0 &&
|
|
strcmp ("PKGV0006", pointer) != 0 &&
|
|
strcmp ("PKGV0007", pointer) != 0 &&
|
|
strcmp ("PKGV0008", pointer) != 0 &&
|
|
strcmp ("PKGV0009", pointer) != 0 &&
|
|
strcmp ("PKGV0010", pointer) != 0 &&
|
|
strcmp ("PKGV0012", pointer) != 0 &&
|
|
strcmp ("PKGV0013", pointer) != 0 &&
|
|
strcmp ("PKGV0014", pointer) != 0 &&
|
|
strcmp ("PKGV0015", pointer) != 0 &&
|
|
strcmp ("PKGV0016", pointer) != 0 &&
|
|
strcmp ("PKGV0017", pointer) != 0 &&
|
|
strcmp ("PKGV0018", pointer) != 0)
|
|
{
|
|
std::stringstream msg;
|
|
msg << "Unsupported package version: " << pointer;
|
|
delete[] pointer;
|
|
throw std::runtime_error (msg.str ());
|
|
}
|
|
|
|
// free memory
|
|
delete[] pointer;
|
|
}
|
|
|
|
void CPackage::loadFiles (FILE* fp)
|
|
{
|
|
uint32_t count = this->readInteger (fp);
|
|
std::vector<CPackageEntry> list;
|
|
|
|
for (uint32_t index = 0; index < count; index ++)
|
|
{
|
|
// first read the filename
|
|
char* filename = this->readSizedString (fp);
|
|
uint32_t offset = this->readInteger (fp);
|
|
uint32_t length = this->readInteger (fp);
|
|
|
|
// add the file to the list
|
|
list.emplace_back(filename, offset, length);
|
|
// only free filename, the file's contents are stored in a map for a later use
|
|
delete[] filename;
|
|
}
|
|
|
|
// get current baseOffset, this is where the files start
|
|
long baseOffset = ftell (fp);
|
|
|
|
for (const auto& cur : list)
|
|
{
|
|
long offset = cur.offset + baseOffset;
|
|
|
|
// with all the data we can jump to the offset and read the content
|
|
if (fseek (fp, offset, SEEK_SET) != 0)
|
|
sLog.exception ("Cannot find file ", cur.filename, " from package ", this->m_path);
|
|
|
|
// allocate memory for the file's contents and read it from the file
|
|
char* fileContents = new char [cur.length];
|
|
|
|
if (fread (fileContents, cur.length, 1, fp) != 1)
|
|
{
|
|
delete[] fileContents;
|
|
|
|
sLog.exception ("Cannot read file ", cur.filename, " contents from package ", this->m_path);
|
|
}
|
|
|
|
// add the file to the map
|
|
this->m_contents.insert_or_assign (cur.filename, CFileEntry (fileContents, cur.length));
|
|
}
|
|
} |