159 lines
5.3 KiB
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!");
|
|
} |