Dawn/src/dawn/asset/asset.c

159 lines
5.3 KiB
C

/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset.h"
#include "assetarchive.h"
#include "assert/assert.h"
#include "util/math.h"
void assetInit() {
// TODO: Works on Windows? path sep probs wrong.
// const char_t *assetFilename = "dawn.tar";
// char_t *assetPath = malloc(sizeof(char_t) * (
// strlen(SYSTEM.executableDirectory) + strlen(assetFilename) + 1
// ));
// sprintf(assetPath, "%s/%s", SYSTEM.executableDirectory, assetFilename);
char_t *assetPath = "/home/yourwishes/htdocs/Dawn/build/dawn.tar";
ASSET_FILE = fopen(assetPath, "rb");
// free(assetPath);
assertNotNull(ASSET_FILE, "assetInit: Failed to open asset file!");
ASSET_ARCHIVE = NULL;
ASSET_ENTRY = NULL;
}
size_t assetReadUntil(uint8_t *buffer, const char_t c, const size_t maxLength) {
if(buffer == NULL) {
assertTrue(
maxLength == -1, "If no buffer is provided, maxLength must be -1."
);
uint8_t tBuffer[1];
size_t read = 0;
while(assetRead(tBuffer, 1) == 1 && (char_t)tBuffer[0] != c) read++;
return read;
} else {
size_t read = 0;
while(read < maxLength) {
// TODO: Read more than 1 char at a time.
read += assetRead(buffer + read, 1);
if((char_t)buffer[read-1] == c) return read - 1;
}
return -1;
}
}
void assetOpen(const char_t *path) {
assertNull(ASSET_ARCHIVE, "assetOpenFile: Archive is not NULL!");
assertNull(ASSET_ENTRY, "assetOpenFile: Entry is not NULL!");
assertStringValid(path, 1024, "assetOpenFile: Path is not valid!");
// Store path
strcpy(ASSET_PATH_CURRENT, path);
// Prepare data
ASSET_ARCHIVE = archive_read_new();
assertNotNull(ASSET_ARCHIVE, "assetOpenFile: Failed to create archive!");
// Set up the reader
// archive_read_support_filter_bzip2(ASSET_ARCHIVE);
archive_read_support_format_tar(ASSET_ARCHIVE);
// Open reader
archive_read_set_open_callback(ASSET_ARCHIVE, &assetArchiveOpen);
archive_read_set_read_callback(ASSET_ARCHIVE, &assetArchiveRead);
archive_read_set_seek_callback(ASSET_ARCHIVE, &assetArchiveSeek);
archive_read_set_close_callback(ASSET_ARCHIVE, &assetArchiveOpen);
archive_read_set_callback_data(ASSET_ARCHIVE, ASSET_ARCHIVE_BUFFER);
int32_t ret = archive_read_open1(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetOpenFile: Failed to open archive!");
// Iterate over each file.
while(archive_read_next_header(ASSET_ARCHIVE, &ASSET_ENTRY) == ARCHIVE_OK) {
const char_t *headerFile = (char_t*)archive_entry_pathname(ASSET_ENTRY);
if(strcmp(headerFile, ASSET_PATH_CURRENT) == 0) return;
int32_t ret = archive_read_data_skip(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetOpenFile: Failed to skip data!");
}
assertUnreachable("assetOpenFile: Failed to find file!");
}
size_t assetGetSize() {
assertNotNull(ASSET_ARCHIVE, "assetGetSize: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetGetSize: Entry is NULL!");
assertTrue(
archive_entry_size_is_set(ASSET_ENTRY),
"assetGetSize: Entry size is not set!"
);
size_t n = archive_entry_size(ASSET_ENTRY);
// Remnant when get size was doing some incorrect stuff.
// char_t path[2048];
// sprintf(
// path, "/home/yourwishes/htdocs/dusk/build/assets/%s", ASSET_PATH_CURRENT
// );
// FILE *temp = fopen(path, "rb");
// assertNotNull(temp, "assetGetSize: Failed to open temp file!");
// fseek(temp, 0, SEEK_END);
// size_t size = ftell(temp);
// assertTrue(size == n, "assetGetSize: Size is not equal!");
// fclose(temp);
return n;
}
size_t assetRead(uint8_t *buffer, size_t bufferSize) {
assertNotNull(ASSET_ARCHIVE, "assetRead: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetRead: Entry is NULL!");
assertNotNull(buffer, "assetRead: Buffer is NULL!");
assertTrue(bufferSize > 0, "assetRead: Buffer size must be greater than 0!");
ssize_t read = archive_read_data(ASSET_ARCHIVE, buffer, bufferSize);
if(read == ARCHIVE_FATAL) {
assertUnreachable(archive_error_string(ASSET_ARCHIVE));
}
assertTrue(read != ARCHIVE_RETRY, "assetRead: Failed to read data (RETRY)!");
assertTrue(read != ARCHIVE_WARN, "assetRead: Failed to read data (WARN)!");
return read;
}
void assetSkip(const size_t length) {
assertNotNull(ASSET_ARCHIVE, "assetSkip: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetSkip: Entry is NULL!");
assertTrue(length > 0, "assetSkip: Length must be greater than 0!");
// Asset archive does not support skipping, so we have to read and discard.
uint8_t buffer[1024];
size_t remaining = length;
do {
size_t toRead = mathMin(remaining, 1024);
size_t read = assetRead(buffer, toRead);
assertTrue(read == toRead, "assetSkip: Failed to skip data! (overskip?)");
remaining -= read;
} while(remaining > 0);
}
void assetClose() {
assertNotNull(ASSET_ARCHIVE, "assetClose: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetClose: Entry is NULL!");
int32_t ret = archive_read_free(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetClose: Failed to close archive!");
ASSET_ARCHIVE = NULL;
ASSET_ENTRY = NULL;
}
void assetDispose() {
assertNull(ASSET_ARCHIVE, "assetDestroy: Archive is not NULL!");
assertNull(ASSET_ENTRY, "assetDestroy: Entry is not NULL!");
int32_t result = fclose(ASSET_FILE);
assertTrue(result == 0, "assetDestroy: Failed to close asset file!");
}