171 lines
5.8 KiB
C++
171 lines
5.8 KiB
C++
// Copyright (c) 2023 Dominic Masters
|
|
//
|
|
// This software is released under the MIT License.
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
#include "AssetLoader.hpp"
|
|
#include "util/mathutils.hpp"
|
|
|
|
using namespace Dawn;
|
|
|
|
ssize_t assetLoaderArchiveRead(
|
|
struct archive *archive,
|
|
void *d,
|
|
const void **buffer
|
|
) {
|
|
assertNotNull(archive, "assetArchiveRead: Archive is NULL!");
|
|
assertNotNull(d, "assetArchiveRead: Data is NULL!");
|
|
assertNotNull(buffer, "assetArchiveRead: Buffer is NULL!");
|
|
AssetLoader *loader = (AssetLoader*)d;
|
|
|
|
*buffer = loader->buffer;
|
|
size_t read = fread(
|
|
loader->buffer, 1, ASSET_LOADER_BUFFER_SIZE, loader->assetArchiveFile
|
|
);
|
|
if(ferror(loader->assetArchiveFile)) return ARCHIVE_FATAL;
|
|
return read;
|
|
}
|
|
|
|
int64_t assetLoaderArchiveSeek(
|
|
struct archive *archive,
|
|
void *d,
|
|
int64_t offset,
|
|
int32_t whence
|
|
) {
|
|
assertNotNull(archive, "assetArchiveSeek: Archive is NULL!");
|
|
assertNotNull(d, "assetArchiveSeek: Data is NULL!");
|
|
assertTrue(offset > 0, "assetArchiveSeek: Offset must be greater than 0!");
|
|
AssetLoader *loader = (AssetLoader*)d;
|
|
int32_t ret = fseek(loader->assetArchiveFile, offset, whence);
|
|
assertTrue(ret == 0, "assetArchiveSeek: Failed to seek!");
|
|
return ftell(loader->assetArchiveFile);
|
|
}
|
|
|
|
int32_t assetLoaderArchiveOpen(struct archive *a, void *d) {
|
|
assertNotNull(a, "assetArchiveOpen: Archive is NULL!");
|
|
assertNotNull(d, "assetArchiveOpen: Data is NULL!");
|
|
AssetLoader *loader = (AssetLoader*)d;
|
|
|
|
int32_t ret = fseek(loader->assetArchiveFile, 0, SEEK_SET);
|
|
assertTrue(ret == 0, "assetArchiveOpen: Failed to seek to start of file!");
|
|
return ARCHIVE_OK;
|
|
}
|
|
|
|
int32_t assetLoaderArchiveClose(struct archive *a, void *d) {
|
|
assertNotNull(a, "assetArchiveClose: Archive is NULL!");
|
|
assertNotNull(d, "assetArchiveClose: Data is NULL!");
|
|
return assetLoaderArchiveOpen(a, d);
|
|
}
|
|
|
|
AssetLoader::AssetLoader(std::string fileName) : IAssetLoader(fileName) {}
|
|
|
|
void AssetLoader::open() {
|
|
assertNull(this->assetArchiveFile, "AssetLoader::open: File is already open");
|
|
assertNull(this->assetArchive, "AssetLoader::open: Archive is already open");
|
|
assertNull(this->assetArchiveEntry, "AssetLoader::open: Entry is already open");
|
|
|
|
this->assetArchiveFile = fopen(DAWN_ASSET_LOCATION, "rb");
|
|
assertNotNull(this->assetArchiveFile, "AssetLoader::open: Failed to open file %s", DAWN_ASSET_LOCATION);
|
|
|
|
// Open archive reader
|
|
assetArchive = archive_read_new();
|
|
assertNotNull(assetArchive, "AssetLoader::open: Failed to create archive reader");
|
|
|
|
// Set up the reader
|
|
archive_read_support_format_tar(assetArchive);
|
|
|
|
// Open reader
|
|
archive_read_set_open_callback(assetArchive, &assetLoaderArchiveOpen);
|
|
archive_read_set_read_callback(assetArchive, &assetLoaderArchiveRead);
|
|
archive_read_set_seek_callback(assetArchive, &assetLoaderArchiveSeek);
|
|
archive_read_set_close_callback(assetArchive, &assetLoaderArchiveClose);
|
|
archive_read_set_callback_data(assetArchive, this);
|
|
|
|
int32_t ret = archive_read_open1(assetArchive);
|
|
assertTrue(ret == ARCHIVE_OK, "AssetLoader::open: Failed to open archive!");
|
|
position = 0;
|
|
|
|
// Iterate over each file to find the one for this asset loader.
|
|
while(archive_read_next_header(assetArchive, &assetArchiveEntry) == ARCHIVE_OK) {
|
|
const char_t *headerFile = (char_t*)archive_entry_pathname(assetArchiveEntry);
|
|
if(std::string(headerFile) == this->fileName) return;
|
|
int32_t ret = archive_read_data_skip(assetArchive);
|
|
assertTrue(ret == ARCHIVE_OK, "AssetLoader::open: Failed to skip data!");
|
|
}
|
|
|
|
assertUnreachable("AssetLoader::open: Failed to find file!");
|
|
}
|
|
|
|
int32_t AssetLoader::close() {
|
|
assertNotNull(this->assetArchiveFile, "AssetLoader::close: File is NULL");
|
|
assertNotNull(this->assetArchive, "AssetLoader::close: Archive is NULL!");
|
|
assertNotNull(this->assetArchiveEntry, "AssetLoader::close: Entry is NULL!");
|
|
|
|
// Close the archive
|
|
int32_t ret = archive_read_free(this->assetArchive);
|
|
assertTrue(ret == ARCHIVE_OK, "AssetLoader::close: Failed to close archive!");
|
|
|
|
this->assetArchive = nullptr;
|
|
this->assetArchiveEntry = nullptr;
|
|
|
|
// Close the file
|
|
int32_t res = fclose(this->assetArchiveFile);
|
|
this->assetArchiveFile = nullptr;
|
|
return res;
|
|
}
|
|
|
|
size_t AssetLoader::read(uint8_t *buffer, size_t size) {
|
|
assertNotNull(buffer, "assetArchiveRead: Buffer is NULL!");
|
|
assertTrue(size > 0, "assetArchiveRead: Size must be greater than 0!");
|
|
assertNotNull(this->assetArchive, "assetRead: Archive is NULL!");
|
|
assertNotNull(this->assetArchiveEntry, "assetRead: Entry is NULL!");
|
|
|
|
ssize_t read = archive_read_data(this->assetArchive, buffer, size);
|
|
this->position += read;
|
|
|
|
if(read == ARCHIVE_FATAL) {
|
|
assertUnreachable(archive_error_string(this->assetArchive));
|
|
}
|
|
|
|
assertTrue(read != ARCHIVE_RETRY, "assetRead: Failed to read data (RETRY)!");
|
|
assertTrue(read != ARCHIVE_WARN, "assetRead: Failed to read data (WARN)!");
|
|
|
|
return read;
|
|
}
|
|
|
|
size_t AssetLoader::getSize() {
|
|
assertTrue(this->assetArchiveEntry != nullptr, "AssetLoader::getSize: Entry is NULL!");
|
|
assertTrue(archive_entry_size_is_set(assetArchiveEntry), "assetGetSize: Entry size is not set!");
|
|
return archive_entry_size(assetArchiveEntry);
|
|
}
|
|
|
|
size_t AssetLoader::skip(size_t n) {
|
|
assertTrue(n >= 0, "AssetLoader::skip: Byte count must be greater than 0.");
|
|
|
|
uint8_t dumpBuffer[ASSET_LOADER_BUFFER_SIZE];
|
|
size_t skipped = 0;
|
|
size_t n2, n3;
|
|
while(n != 0) {
|
|
n2 = mathMin<size_t>(n, ASSET_LOADER_BUFFER_SIZE);
|
|
n3 = this->read(dumpBuffer, n2);
|
|
assertTrue(n3 == n2, "AssetLoader::skip: Failed to skip bytes!");
|
|
n -= n3;
|
|
}
|
|
|
|
return skipped;
|
|
}
|
|
|
|
void AssetLoader::rewind() {
|
|
// TODO: See if I can optimize this
|
|
this->close();
|
|
this->open();
|
|
}
|
|
|
|
size_t AssetLoader::getPosition() {
|
|
assertNotNull(this->assetArchiveFile, "AssetLoader::getPosition: File is not open!");
|
|
return this->position;
|
|
}
|
|
|
|
AssetLoader::~AssetLoader() {
|
|
if(this->assetArchiveFile != nullptr) this->close();
|
|
} |