linux-wallpaperengine/src/WallpaperEngine/Assets/CPackage.cpp
Alexis Maiquez a24b1923f6 Cleanup of code:
- 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>
2023-02-03 18:41:51 +01:00

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));
}
}