A bit more code cleanup
This commit is contained in:
104
src/file/asset.c
Normal file
104
src/file/asset.c
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Msters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset.h"
|
||||
|
||||
size_t assetRawLoad(char *assetName, uint8_t *buffer) {
|
||||
assetbuffer_t *asset;
|
||||
size_t length, read;
|
||||
|
||||
// Open a buffer.
|
||||
asset = assetBufferOpen(assetName);
|
||||
if(asset == NULL) return 0;
|
||||
|
||||
// Read the count of bytes in the file
|
||||
assetBufferEnd(asset);
|
||||
length = assetBufferGetCurrentPosition(asset);// Get our current position (the end)
|
||||
|
||||
// Are we only reading the size?
|
||||
if(buffer == NULL) {
|
||||
assetBufferClose(asset);
|
||||
return length;
|
||||
}
|
||||
|
||||
// Reset to start
|
||||
assetBufferStart(asset);
|
||||
|
||||
// Read and seal the string.
|
||||
read = assetBufferRead(asset, buffer, length);
|
||||
assetBufferClose(asset); // Close the buffer.
|
||||
|
||||
// Did we read successfully?
|
||||
if(read < length) return 0;
|
||||
return read;
|
||||
}
|
||||
|
||||
char * assetStringLoad(char *assetName) {
|
||||
size_t length;
|
||||
char *string;
|
||||
|
||||
length = assetRawLoad(assetName, NULL);
|
||||
if(length == 0) return NULL;
|
||||
|
||||
string = malloc(length + 1);// +1 for null terminator
|
||||
if(string == NULL) return NULL;
|
||||
|
||||
length = assetRawLoad(assetName, string);
|
||||
if(length == 0) {
|
||||
free(string);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string[length] = '\0';// Null terminate
|
||||
return string;
|
||||
}
|
||||
|
||||
assetbuffer_t * assetBufferOpen(char *assetName) {
|
||||
// Get the directory based on the raw input by creating a new string.
|
||||
FILE *fptr;
|
||||
char filename[512];
|
||||
|
||||
// Prep filename
|
||||
filename[0] = '\0';//Start at null
|
||||
strcat(filename, ASSET_PREFIX);//Add prefix
|
||||
strcat(filename, assetName);//Add body
|
||||
|
||||
printf("Opening up %s\n", filename);
|
||||
|
||||
// Open the file pointer now.
|
||||
fptr = fopen(filename, "rb");
|
||||
if(fptr == NULL) {
|
||||
printf("Error opening %s: %s\n", filename, strerror(errno));
|
||||
return NULL;// File available?
|
||||
}
|
||||
return (assetbuffer_t *)fptr;
|
||||
}
|
||||
|
||||
bool assetBufferClose(assetbuffer_t *buffer) {
|
||||
return fclose((FILE *)buffer);
|
||||
}
|
||||
|
||||
int32_t assetBufferRead(assetbuffer_t *buffer, char *data, size_t size) {
|
||||
return (int32_t)fread(data, 1, size, (FILE *)buffer);
|
||||
}
|
||||
|
||||
int32_t assetBufferEnd(assetbuffer_t *buffer) {
|
||||
// return feof((FILE *)buffer);
|
||||
return fseek((FILE *)buffer, 0, SEEK_END);// Seek to the end
|
||||
}
|
||||
|
||||
int32_t assetBufferStart(assetbuffer_t *buffer) {
|
||||
return fseek((FILE *)buffer, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
int32_t assetBufferSkip(assetbuffer_t *buffer, long n) {
|
||||
return fseek((FILE *)buffer, n, SEEK_CUR);
|
||||
}
|
||||
|
||||
size_t assetBufferGetCurrentPosition(assetbuffer_t *buffer) {
|
||||
return ftell((FILE *)buffer);
|
||||
}
|
90
src/file/asset.h
Normal file
90
src/file/asset.h
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Msters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../display/shader.h"
|
||||
#include "../display/texture.h"
|
||||
#include "../display/font.h"
|
||||
|
||||
#if !defined(ASSET_PREFIX)
|
||||
#error Asset Prefix has not been defined.
|
||||
#endif
|
||||
|
||||
/** Definition of an asset ready to be buffered */
|
||||
typedef FILE assetbuffer_t;
|
||||
|
||||
/**
|
||||
* Buffer an asset from the file system into memory.
|
||||
*
|
||||
* @param assetName Path to the asset to buffer.
|
||||
* @param buffer Place to buffer the data in to, or NULL to simply read the size
|
||||
* @return The length (in bytes) of the file.
|
||||
*/
|
||||
size_t assetRawLoad(char *assetName, uint8_t *buffer);
|
||||
|
||||
/**
|
||||
* Load a string from an asset into memory.
|
||||
*
|
||||
* @param assetName Asset to load
|
||||
* @return A newly loaded string (malloced into existance.)
|
||||
*/
|
||||
char * assetStringLoad(char *assetName);
|
||||
|
||||
/**
|
||||
* Platform-centric method to open a file buffer to an asset.
|
||||
* @param assetName The asset name to open a buffer for.
|
||||
* @return Pointer to a buffer, NULL if unsuccessfuil.
|
||||
*/
|
||||
assetbuffer_t * assetBufferOpen(char *assetName);
|
||||
|
||||
/**
|
||||
* Closes a previously opened asset buffer.
|
||||
* @param buffer Buffer to close.
|
||||
* @return True if successful, otherwise false.
|
||||
*/
|
||||
bool assetBufferClose(assetbuffer_t *buffer);
|
||||
|
||||
/**
|
||||
* Read bytes from buffer.
|
||||
* @param buffer The buffer pointing to an asset.
|
||||
* @param data Pointer to a ubyte array to buffer data into.
|
||||
* @param size Length of the data buffer. Represents how many bytes can be read.
|
||||
* @return The count of bytes read. Complete when less than data array size.
|
||||
*/
|
||||
int32_t assetBufferRead(assetbuffer_t *buffer, char *data, size_t size);
|
||||
|
||||
/**
|
||||
* Skip to the end of the buffer, useful to find the length of the buffer.
|
||||
* @param Buffer The buffer pointing to an asset.
|
||||
* @return How many bytes were skipped
|
||||
*/
|
||||
int32_t assetBufferEnd(assetbuffer_t *buffer);
|
||||
|
||||
/**
|
||||
* Rewinds an asset buffer to the start.
|
||||
*
|
||||
* @param buffer Buffer to rewind
|
||||
* @return 0 if successful, otherwise unsuccessful.
|
||||
*/
|
||||
int32_t assetBufferStart(assetbuffer_t *buffer);
|
||||
|
||||
/**
|
||||
* Method to skip n bytes in the buffer
|
||||
* @param buffer The buffer pointing to an asset.
|
||||
* @param n Count of bytes to skip.
|
||||
* @return 0 if successful, otherwise unsuccessful.
|
||||
*/
|
||||
int32_t assetBufferSkip(assetbuffer_t *buffer, long n);
|
||||
|
||||
/**
|
||||
* Retreive the current byte position within the asset that the head is at.
|
||||
*
|
||||
* @param buffer Buffer to get the position of.
|
||||
* @return Position (in bytes) that the current seek is at.
|
||||
*/
|
||||
size_t assetBufferGetCurrentPosition(assetbuffer_t *buffer);
|
240
src/file/assetmanager.c
Normal file
240
src/file/assetmanager.c
Normal file
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assetmanager.h"
|
||||
|
||||
assetmanagerloaderdefinition_t ASSET_MANAGER_LOADERS[] = {
|
||||
{
|
||||
&_assetManagerLoaderTextureAsync,
|
||||
&_assetManagerLoaderTextureSync,
|
||||
&_assetManagerLoaderTextureDispose
|
||||
},
|
||||
{
|
||||
&_assetManagerLoaderFontAsync,
|
||||
&_assetManagerLoaderFontSync,
|
||||
&_assetManagerLoaderFontDispose
|
||||
},
|
||||
{
|
||||
&_assetManagerLoaderShaderAsync,
|
||||
&_assetManagerLoaderShaderSync,
|
||||
&_assetManagerLoaderShaderDispose
|
||||
},
|
||||
{
|
||||
&_assetManagerLoaderScaledTextureAsync,
|
||||
&_assetManagerLoaderScaledTextureSync,
|
||||
&_assetManagerLoaderScaledTextureDispose
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void assetManagerInit(assetmanager_t *manager) {
|
||||
threadInit(&manager->thread, &_assetManagerThread);
|
||||
manager->thread.user = manager;
|
||||
manager->itemCount = 0;
|
||||
manager->finished = false;
|
||||
manager->holderCount = 0;
|
||||
manager->running = false;
|
||||
}
|
||||
|
||||
float assetManagerProgressGet(assetmanager_t *manager) {
|
||||
float done;
|
||||
uint8_t i;
|
||||
assetmanageritem_t *item;
|
||||
|
||||
done = 0.0f;
|
||||
for(i = 0; i < manager->itemCount; i++) {
|
||||
item = manager->items + i;
|
||||
done += assetManagerItemIsFinished(
|
||||
item, ASSET_MANAGER_LOADERS + item->type
|
||||
) ? 1 : 0;
|
||||
}
|
||||
return done / ((float)manager->itemCount);
|
||||
}
|
||||
|
||||
float assetManagerProgressGetForHolder(
|
||||
assetmanager_t *manager, assetmanagerowner_t hold
|
||||
) {
|
||||
float done;
|
||||
uint8_t i, j, c;
|
||||
assetmanageritem_t *item;
|
||||
done = 0.0f;
|
||||
c = 0x00;
|
||||
for(i = 0; i < manager->itemCount; i++) {
|
||||
//Is this held by this holder?
|
||||
item = manager->items + i;
|
||||
|
||||
for(j = 0; j < item->holderCount; j++) {
|
||||
if(item->holders[j] != hold) continue;
|
||||
c++;
|
||||
done += assetManagerItemIsFinished(
|
||||
item, ASSET_MANAGER_LOADERS + item->type
|
||||
) ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Is this thing even holding any assets to begin with?
|
||||
if(c == 0x00) return 1.0f;
|
||||
return done / (float)c;
|
||||
}
|
||||
|
||||
assetmanagerowner_t assetManagerHolderCreate(assetmanager_t *man) {
|
||||
uint8_t i;
|
||||
|
||||
// Find first available number.
|
||||
for(i = 0; i < 0xFF; i++) {
|
||||
if(arrayFind(
|
||||
sizeof(assetmanagerowner_t), man->holders, man->holderCount, &i
|
||||
) == -1) break;
|
||||
}
|
||||
|
||||
man->holders[man->holderCount++] = i;
|
||||
return i;// No slots left.
|
||||
}
|
||||
|
||||
void assetManagerHolderRelease(assetmanager_t *man, assetmanagerowner_t hold) {
|
||||
int32_t i;
|
||||
uint8_t j;
|
||||
assetmanageritem_t *item;
|
||||
size_t s;
|
||||
|
||||
s = sizeof(assetmanagerowner_t);
|
||||
i = arrayFind(s, man->holders,man->holderCount,&hold);
|
||||
if(i == -1) return;
|
||||
|
||||
arraySplice(sizeof(uint8_t), man->holders, i, 1, man->holderCount);
|
||||
man->holderCount--;
|
||||
|
||||
for(j = 0; j < man->itemCount; j++) {
|
||||
item = man->items + j;
|
||||
i = arrayFind(s, item->holders, item->holderCount, &hold);
|
||||
if(i == -1) continue;
|
||||
arraySplice(s, item->holders, i, 1, item->holderCount);
|
||||
item->holderCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void assetManagerDisposeReleased(assetmanager_t *man) {
|
||||
uint8_t i;
|
||||
assetmanagerloader_t *disp;
|
||||
assetmanageritem_t *item;
|
||||
|
||||
for(i = 0; i < man->itemCount; i++) {
|
||||
item = man->items + i;
|
||||
disp = ASSET_MANAGER_LOADERS[item->type].dispose;
|
||||
if(item->holderCount > 0) continue;
|
||||
if(disp != NULL) disp(item);
|
||||
arraySplice(sizeof(assetmanageritem_t), man->items, i, 1, man->itemCount);
|
||||
man->itemCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void assetManagerDispose(assetmanager_t *man) {
|
||||
uint8_t i;
|
||||
assetmanagerloader_t *disp;
|
||||
assetmanageritem_t *item;
|
||||
|
||||
for(i = 0; i < man->itemCount; i++) {
|
||||
item = man->items + i;
|
||||
disp = ASSET_MANAGER_LOADERS[item->type].dispose;
|
||||
if(item->holderCount > 0) continue;
|
||||
if(disp != NULL) disp(item);
|
||||
}
|
||||
|
||||
man->itemCount = 0;
|
||||
man->holderCount = 0;
|
||||
}
|
||||
|
||||
// Thread Management
|
||||
void assetManagerStart(assetmanager_t *manager) {
|
||||
if(manager->running) return;
|
||||
manager->running = true;
|
||||
threadStart(&manager->thread);
|
||||
}
|
||||
|
||||
int32_t _assetManagerThread(thread_t *thread) {
|
||||
// TODO: Can I allow multiple threads to run?
|
||||
uint8_t i;
|
||||
assetmanager_t *manager;
|
||||
assetmanageritem_t *item;
|
||||
assetmanagerloaderdefinition_t *definition;
|
||||
bool result;
|
||||
manager = thread->user;
|
||||
|
||||
for(i = 0; i < manager->itemCount; i++) {
|
||||
item = manager->items + i;
|
||||
definition = ASSET_MANAGER_LOADERS + item->type;
|
||||
|
||||
// Only bother with ASYNC items
|
||||
if(definition->loadAsync == NULL) continue;
|
||||
|
||||
// Are we already loading, not ready, or already tried to load?
|
||||
if(item->state != ASSET_MANAGER_STATE_PENDING) continue;
|
||||
|
||||
// Begin loading
|
||||
item->state = ASSET_MANAGER_STATE_ASYNC_LOADING;
|
||||
result = definition->loadAsync(item);
|
||||
|
||||
// Finish Loading
|
||||
if(!result) {
|
||||
item->state = ASSET_MANAGER_STATE_ASYNC_ERROR;
|
||||
} else {
|
||||
item->state = ASSET_MANAGER_STATE_ASYNC_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
manager->finished = assetManagerProgressGet(manager) >= 1.0f;
|
||||
manager->running = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void assetManagerUpdate(assetmanager_t *manager) {
|
||||
uint8_t i;
|
||||
assetmanageritem_t *item;
|
||||
assetmanagerloaderdefinition_t *definition;
|
||||
bool result;
|
||||
|
||||
// Autostart
|
||||
if(assetManagerProgressGet(manager) < 1.0f && !manager->running) {
|
||||
assetManagerStart(manager);
|
||||
}
|
||||
|
||||
for(i = 0; i < manager->itemCount; i++) {
|
||||
item = manager->items + i;
|
||||
definition = ASSET_MANAGER_LOADERS + item->type;
|
||||
|
||||
// Update not ready state (Synchronously)
|
||||
if(item->state == ASSET_MANAGER_STATE_NOT_READY) {
|
||||
item->state = ASSET_MANAGER_STATE_PENDING;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If requires ASYNC loading, then confirm it has finished loading.
|
||||
if(definition->loadAsync != NULL) {
|
||||
if(item->state != ASSET_MANAGER_STATE_ASYNC_DONE) continue;
|
||||
} else if(item->state != ASSET_MANAGER_STATE_PENDING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(definition->loadSync == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Begin sync loading
|
||||
item->state = ASSET_MANAGER_STATE_SYNC_LOADING;
|
||||
result = definition->loadSync(item);
|
||||
|
||||
// Finish loading
|
||||
if(!result) {
|
||||
item->state = ASSET_MANAGER_STATE_SYNC_ERROR;
|
||||
} else {
|
||||
item->state = ASSET_MANAGER_STATE_SYNC_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
manager->finished = assetManagerProgressGet(manager) >= 1.0f;
|
||||
}
|
100
src/file/assetmanager.h
Normal file
100
src/file/assetmanager.h
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "types/common.h"
|
||||
#include "loaders/font.h"
|
||||
#include "loaders/scaledtexture.h"
|
||||
#include "loaders/shader.h"
|
||||
#include "loaders/texture.h"
|
||||
#include "asset.h"
|
||||
|
||||
// Constants
|
||||
extern assetmanagerloaderdefinition_t ASSET_MANAGER_LOADERS[];
|
||||
|
||||
/**
|
||||
* Initialize the asset manager
|
||||
*
|
||||
* @param manager Manager to initialize.
|
||||
*/
|
||||
void assetManagerInit(assetmanager_t *manager);
|
||||
|
||||
/**
|
||||
* Gets the progress of the asset manager as a representation of 0-1 as a % that
|
||||
* has loaded.
|
||||
*
|
||||
* @param manager Manager to check the state of.
|
||||
* @return The progress percent as a representation of 0-1
|
||||
*/
|
||||
float assetManagerProgressGet(assetmanager_t *manager);
|
||||
|
||||
/**
|
||||
* Gets the progress of the assets for only those held by a specific holder.
|
||||
*
|
||||
* @param manager Manager to get the progress from
|
||||
* @param hold Holder to get the items progress from.
|
||||
* @return The percentage (0-1) of the loaded assets.
|
||||
*/
|
||||
float assetManagerProgressGetForHolder(
|
||||
assetmanager_t *manager, assetmanagerowner_t hold
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a holder for a given asset manager. Asset holders are kept track of
|
||||
* so that those who requests assets are responsible for those who free them. It
|
||||
* also ensures only the assets that are actually necessary are kept loaded in
|
||||
* memory at all times.
|
||||
*
|
||||
* @param man Asset manager in question
|
||||
* @return An asset manager owner ID.
|
||||
*/
|
||||
assetmanagerowner_t assetManagerHolderCreate(assetmanager_t *man);
|
||||
|
||||
/**
|
||||
* Release a previously reserved asset manager holder. This will (in turn) cause
|
||||
* all of the assets that manager was holding to also be released.
|
||||
*
|
||||
* @param man Asset manager holder to release for.
|
||||
* @param hold Holder to release.
|
||||
*/
|
||||
void assetManagerHolderRelease(assetmanager_t *man, assetmanagerowner_t hold);
|
||||
|
||||
/**
|
||||
* Disposes all assets that are not currently held (released assets). This can
|
||||
* only happen from the main thread due to synchronous assets such as Textures.
|
||||
*
|
||||
* @param man Manager to dispose.
|
||||
*/
|
||||
void assetManagerDisposeReleased(assetmanager_t *man);
|
||||
|
||||
/**
|
||||
* Completely dispose an asset manager. This will also completely dispose all
|
||||
* of the assets that this asset manager is holding.
|
||||
*
|
||||
* @param man Asset manager to dispose
|
||||
*/
|
||||
void assetManagerDispose(assetmanager_t *man);
|
||||
|
||||
/**
|
||||
* Begin asynchronously loading all of the assets
|
||||
*
|
||||
* @param manager Manager to begin async loading.
|
||||
*/
|
||||
void assetManagerStart(assetmanager_t *manager);
|
||||
|
||||
/** Private Thread that is executed asynchronously */
|
||||
int32_t _assetManagerThread(thread_t *thread);
|
||||
|
||||
/**
|
||||
* Synchronously tick the asset manager. Some assets require some form of sync
|
||||
* operations, such as buffering to the GPU, so make sure this is called at a
|
||||
* good time for that task, such as right at the end of a frame.
|
||||
*
|
||||
* @param manager Manager to synchronously tick.
|
||||
*/
|
||||
void assetManagerUpdate(assetmanager_t *manager);
|
223
src/file/csv.c
Normal file
223
src/file/csv.c
Normal file
@ -0,0 +1,223 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "csv.h"
|
||||
|
||||
csvbufferresult_t csvBuffer(
|
||||
assetbuffer_t *asset, csvbuffercallback_t *callback, void *user
|
||||
) {
|
||||
int32_t cellChar, read, i, currentColumnCount;
|
||||
char buffer[CSV_BUFFER_SIZE];
|
||||
char cell[CSV_CELL_SIZE_MAX];
|
||||
char c;
|
||||
bool callbackResponse;
|
||||
bool insideEncapsulation = false;
|
||||
csvbufferresult_t result = {
|
||||
.cellCount = 0,
|
||||
.rowCount = 0,
|
||||
.columnCount = 0
|
||||
};
|
||||
|
||||
// Init the cell Char Index.
|
||||
cellChar = 0;
|
||||
currentColumnCount = 0;
|
||||
|
||||
// Begin buffering.
|
||||
while(true) {
|
||||
// Read n bytes into our buffer
|
||||
read = assetBufferRead(asset, buffer, CSV_BUFFER_SIZE);
|
||||
|
||||
// Now read back those bytes.
|
||||
for(i = 0; i < read; i++) {
|
||||
c = buffer[i];
|
||||
|
||||
// Characters we flat out ignore
|
||||
if(c == '\r') continue;
|
||||
|
||||
// Handle quote marks.
|
||||
if(c == '"') {
|
||||
if(buffer[i+1] == '"') {// "" means a single quote (double-escaped)
|
||||
i++;
|
||||
cell[cellChar++] = c;
|
||||
} else if(insideEncapsulation) {
|
||||
insideEncapsulation = false;
|
||||
} else {
|
||||
insideEncapsulation = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the start of a new cell/row?
|
||||
if(c == '\0' || (!insideEncapsulation && (c == ',' || c == '\n'))) {
|
||||
cell[cellChar] = '\0';// Terminate Cell string
|
||||
|
||||
// Fire off the callback
|
||||
if(callback != NULL) {
|
||||
callbackResponse = callback(asset, user, result.rowCount, currentColumnCount, cell);
|
||||
if(!callbackResponse) return result;
|
||||
}
|
||||
|
||||
// Prepare for next row/cell
|
||||
currentColumnCount++;
|
||||
result.columnCount = mathMax(currentColumnCount, result.columnCount);
|
||||
if(c == '\n') {
|
||||
result.rowCount++;
|
||||
currentColumnCount = 0;
|
||||
}
|
||||
result.cellCount++;// Only count cells with
|
||||
cellChar = 0;
|
||||
continue;// Skip
|
||||
}
|
||||
|
||||
// Add character to the cell.
|
||||
cell[cellChar++] = c;
|
||||
}
|
||||
|
||||
if(read < CSV_BUFFER_SIZE) break;
|
||||
}
|
||||
|
||||
// If this is an empty row we don't count it, otherwise we do.
|
||||
if(currentColumnCount != 0) result.rowCount++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool _csvBufferRowParserCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data
|
||||
) {
|
||||
csvbufferrowdata_t *rowData = (csvbufferrowdata_t *)user;
|
||||
|
||||
// Now did we change rows?
|
||||
if(row != rowData->row) {
|
||||
// Yes we did, let's buffer the previous row.
|
||||
if(rowData->callback != NULL) {
|
||||
if(!rowData->callback(
|
||||
asset, rowData->user, rowData->row, &rowData->rowCurrent
|
||||
)) return false;
|
||||
}
|
||||
// Begin next row
|
||||
rowData->row = row;
|
||||
rowData->rowCurrent.columnCount = 0;
|
||||
}
|
||||
|
||||
// Determine string info for the cell
|
||||
int32_t length = (int32_t)strlen(data);
|
||||
int32_t offset = (column * CSV_CELL_SIZE_MAX);
|
||||
|
||||
// Now copy the string data to the buffer
|
||||
arrayCopy(sizeof(char), data, length + 1, rowData->rowCurrent.data + offset);
|
||||
// Update the pointer to the string
|
||||
rowData->rowCurrent.columns[column] = rowData->rowCurrent.data + offset;
|
||||
rowData->rowCurrent.columnCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
csvbufferresult_t csvBufferRow(
|
||||
assetbuffer_t *asset, csvbufferrowcallback_t *callback, void *user
|
||||
) {
|
||||
csvbufferrowdata_t data;
|
||||
csvbufferresult_t result;
|
||||
data.row = 0;
|
||||
data.user = user;
|
||||
data.callback = callback;
|
||||
data.rowCurrent.columnCount = 0;
|
||||
|
||||
// Perform a per-cell buffer and run the parser callback.
|
||||
result = csvBuffer(asset, &_csvBufferRowParserCallback, &data);
|
||||
|
||||
// Because the buffer may not fire for the last row we handle it here.
|
||||
if(data.rowCurrent.columnCount > 0 && callback != NULL) {
|
||||
if(!callback(asset, user, data.row, &data.rowCurrent)) return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool _csvBufferRowWithHeadersCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
) {
|
||||
csvbufferrowwithheadersdata_t *data = (csvbufferrowwithheadersdata_t *)user;
|
||||
|
||||
// Take the headers for row 0
|
||||
if(row == 0) {
|
||||
csvRowPopulate(csv, &data->headerRow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fire the callback
|
||||
return data->callback(asset, data->user, row, &data->headerRow, csv);
|
||||
}
|
||||
|
||||
csvbufferresult_t csvBufferRowWithHeaders(
|
||||
assetbuffer_t *asset, csvbufferrowwitheaderscallback_t *callback, void *user
|
||||
) {
|
||||
csvbufferrowwithheadersdata_t data;
|
||||
data.user = user;
|
||||
data.callback = callback;
|
||||
|
||||
return csvBufferRow(asset, &_csvBufferRowWithHeadersCallback, &data);
|
||||
}
|
||||
|
||||
void csvRowPopulate(csvrow_t *source, csvrow_t *dest) {
|
||||
int32_t i;
|
||||
|
||||
dest->columnCount = source->columnCount;
|
||||
|
||||
// Copy the raw characters from the source buffer.
|
||||
arrayCopy(sizeof(char), source->data, CSV_ROW_CHARACTERS_MAX, dest->data);
|
||||
|
||||
// Now update the destination pointers to reference the data buffer.
|
||||
for(i = 0; i < source->columnCount; i++) {
|
||||
dest->columns[i] = dest->data + (i * CSV_CELL_SIZE_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool _csvHeadersGetCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *current
|
||||
) {
|
||||
csvrow_t *rowData = (csvrow_t *)user;
|
||||
csvRowPopulate(current, rowData);
|
||||
return false;// False to break the loop
|
||||
}
|
||||
|
||||
csvbufferresult_t csvHeadersGet(assetbuffer_t *asset, csvrow_t *row) {
|
||||
return csvBufferRow(asset, &_csvHeadersGetCallback, row);
|
||||
}
|
||||
|
||||
int32_t csvColumnGetIndex(csvrow_t *row, char *key) {
|
||||
return arrayFindString(row->columns, row->columnCount, key);
|
||||
}
|
||||
|
||||
|
||||
bool _csvRowSearchCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
) {
|
||||
csvsearchdata_t *data = (csvsearchdata_t *)user;
|
||||
// Does the search match?
|
||||
if(strcmp(csv->columns[data->column], data->value) != 0) return true;
|
||||
// Matched, copy and end.
|
||||
csvRowPopulate(csv, data->row);
|
||||
data->rowIndex = row;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t csvRowSearch(
|
||||
assetbuffer_t *asset, csvrow_t *row, int32_t column, char *value
|
||||
) {
|
||||
csvsearchdata_t data = {
|
||||
.column = column,
|
||||
.row = row,
|
||||
.rowIndex = -1,
|
||||
.value = value
|
||||
};
|
||||
csvBufferRow(asset, &_csvRowSearchCallback, &data);
|
||||
return data.rowIndex;
|
||||
}
|
191
src/file/csv.h
Normal file
191
src/file/csv.h
Normal file
@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "asset.h"
|
||||
#include "../util/array.h"
|
||||
|
||||
/** Maximum characters that a cell can support */
|
||||
#define CSV_BUFFER_SIZE 32
|
||||
|
||||
/** Maximum characters in any given cell */
|
||||
#define CSV_CELL_SIZE_MAX 1024
|
||||
|
||||
/** Maximum number of columns/cells in a given row */
|
||||
#define CSV_ROW_COLUMNS_MAX 16
|
||||
|
||||
/** Count of characters maximum that a row can support */
|
||||
#define CSV_ROW_CHARACTERS_MAX CSV_CELL_SIZE_MAX * CSV_ROW_COLUMNS_MAX
|
||||
|
||||
/** Result of a CSV buffer operation. */
|
||||
typedef struct {
|
||||
/** How many rows within the CSV */
|
||||
int32_t rowCount;
|
||||
/** Count of columns in the CSV, this is the longest row in the CSV. */
|
||||
int32_t columnCount;
|
||||
/** How many cells within the CSV */
|
||||
int32_t cellCount;
|
||||
} csvbufferresult_t;
|
||||
|
||||
/** Callback to receive data for each cell in a CSV being buffered */
|
||||
typedef bool csvbuffercallback_t(
|
||||
assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data
|
||||
);
|
||||
|
||||
/** Representation of a CSV Row's complete data. */
|
||||
typedef struct {
|
||||
/** Characters within the row */
|
||||
char data[CSV_ROW_CHARACTERS_MAX];
|
||||
/** Pointer to the start of each string within the row */
|
||||
char *columns[CSV_ROW_COLUMNS_MAX];
|
||||
/** How many columns within the row */
|
||||
int32_t columnCount;
|
||||
} csvrow_t;
|
||||
|
||||
/** Callback to receive buffer data for a CSV row */
|
||||
typedef bool csvbufferrowcallback_t(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
);
|
||||
|
||||
/** Callback to receive buffer data for a CSV row, but includes CSV headers. */
|
||||
typedef bool csvbufferrowwitheaderscallback_t(
|
||||
assetbuffer_t *asset, void *user, int32_t row,
|
||||
csvrow_t *header, csvrow_t *current
|
||||
);
|
||||
|
||||
/** Data used by the cell callback for when the row buffering is progressing */
|
||||
typedef struct {
|
||||
/** Which row the current buffer is on */
|
||||
int32_t row;
|
||||
/** Information about the current row being parsed */
|
||||
csvrow_t rowCurrent;
|
||||
/** Pointer to custom user data */
|
||||
void *user;
|
||||
/** Pointer to custom user callback */
|
||||
csvbufferrowcallback_t *callback;
|
||||
} csvbufferrowdata_t;
|
||||
|
||||
/** Data used by the row callback for when the header row is parsed */
|
||||
typedef struct {
|
||||
/** Information about the header row */
|
||||
csvrow_t headerRow;
|
||||
/** Pointer to custom user data */
|
||||
void *user;
|
||||
/** Pointer to custom user callback */
|
||||
csvbufferrowwitheaderscallback_t *callback;
|
||||
} csvbufferrowwithheadersdata_t;
|
||||
|
||||
/** Data used while searching a CSV */
|
||||
typedef struct {
|
||||
/** Row to store the data in */
|
||||
csvrow_t *row;
|
||||
/** Row's index */
|
||||
int32_t rowIndex;
|
||||
/** Column to check */
|
||||
int32_t column;
|
||||
/** Value to check row */
|
||||
char *value;
|
||||
} csvsearchdata_t;
|
||||
|
||||
/**
|
||||
* Buffer each cell within a CSV Asset Buffer with a callback.
|
||||
*
|
||||
* @param asset Asset to buffer the CSV from.
|
||||
* @param callback Callback to fire for each cell parsed.
|
||||
* @param user Pointer to any custom user data.
|
||||
* @return The result of the CSV Buffer Operation.
|
||||
*/
|
||||
csvbufferresult_t csvBuffer(
|
||||
assetbuffer_t *asset, csvbuffercallback_t *callback, void *user
|
||||
);
|
||||
|
||||
/** Callback for when the CSV Row Buffer is parsing a row */
|
||||
bool _csvBufferRowParserCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffer each row within a CSV Asset Buffer with a callback.
|
||||
*
|
||||
* @param asset Asset to buffer the CSV from.
|
||||
* @param callback Callback to fire when a row is parsed.
|
||||
* @param user Pointer to any custom user data.
|
||||
* @return The result of the CSV Buffer Operation.
|
||||
*/
|
||||
csvbufferresult_t csvBufferRow(
|
||||
assetbuffer_t *asset, csvbufferrowcallback_t *callback, void *user
|
||||
);
|
||||
|
||||
|
||||
/** Parser that the header parser buffer uses. */
|
||||
bool _csvBufferRowWithHeadersCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffer each row within a CSV Asset Buffer with a callback. This will also
|
||||
* provide the callback with the header row (The first row), already parsed.
|
||||
*
|
||||
* @param asset
|
||||
* @param callback
|
||||
* @param user
|
||||
* @return csvbufferresult_t
|
||||
*/
|
||||
csvbufferresult_t csvBufferRowWithHeaders(
|
||||
assetbuffer_t *asset, csvbufferrowwitheaderscallback_t *callback, void *user
|
||||
);
|
||||
|
||||
/**
|
||||
* Essentially a CSV Row Cloner, copies data from one CSV row to another and
|
||||
* updates the char pointers for you.
|
||||
*
|
||||
* @param source The source CSV row to copy from.
|
||||
* @param dest The destination CSV row to copy to.
|
||||
*/
|
||||
void csvRowPopulate(csvrow_t *source, csvrow_t *dest);
|
||||
|
||||
/** Callback used to parse and get the headers row */
|
||||
bool _csvHeadersGetCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *current
|
||||
);
|
||||
/**
|
||||
* Parses just the headers row from a CSV and stores the output into the
|
||||
* provided buffers.
|
||||
*
|
||||
* @param asset Asset to get the headers from.
|
||||
* @param row The CSV Row to store the headers data in.
|
||||
* @return The result of the buffer operation.
|
||||
*/
|
||||
csvbufferresult_t csvHeadersGet(assetbuffer_t *asset, csvrow_t *row);
|
||||
|
||||
/**
|
||||
* Gets the column index within the CSV Row for the specific key.
|
||||
* @param row Row to get from.
|
||||
* @param key Key to search for
|
||||
* @return The column index for the key, or -1 if not found.
|
||||
*/
|
||||
int32_t csvColumnGetIndex(csvrow_t *row, char *key);
|
||||
|
||||
/** Callback to use while scanning the CSV to find the matching row */
|
||||
bool _csvRowSearchCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
);
|
||||
|
||||
/**
|
||||
* Search the CSV for a matching row. Will return data only if the given column
|
||||
* matches the given value.
|
||||
*
|
||||
* @param asset Asset buffer to search.
|
||||
* @param row Where the returned row will be stored.
|
||||
* @param column Column to check.
|
||||
* @param value Value to check in that column
|
||||
* @return The row index that the result was found on, or -1 if not found.
|
||||
*/
|
||||
int32_t csvRowSearch(
|
||||
assetbuffer_t *asset, csvrow_t *row, int32_t column, char *value
|
||||
);
|
39
src/file/loaders/font.c
Normal file
39
src/file/loaders/font.c
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "font.h"
|
||||
|
||||
assetmanageritem_t * assetManagerLoadFont(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner, char *fileName
|
||||
) {
|
||||
assetmanageritem_t *item;
|
||||
item = assetManagerItemGet(manager, fileName);
|
||||
if(item == NULL) {
|
||||
item = assetManagerItemAdd(manager, fileName);
|
||||
item->type = ASSET_MANAGER_TYPE_FONT;
|
||||
item->data.font.fileName = fileName;
|
||||
}
|
||||
assetManagerItemGetOrAddHolder(item, owner);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderFontAsync(assetmanageritem_t *item) {
|
||||
item->data.font.data = assetStringLoad(item->data.font.fileName);
|
||||
return item->data.font.data != NULL;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderFontSync(assetmanageritem_t *item) {
|
||||
fontInit(&item->data.font.font, item->data.font.data);
|
||||
free(item->data.font.data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderFontDispose(assetmanageritem_t *item) {
|
||||
fontDispose(&item->data.font.font);
|
||||
return true;
|
||||
}
|
27
src/file/loaders/font.h
Normal file
27
src/file/loaders/font.h
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "../asset.h"
|
||||
|
||||
/**
|
||||
* Queue a font load onto the asset manager buffer.
|
||||
*
|
||||
* @param manager Manager to queue on to.
|
||||
* @param owner Owner ID requesting to load this resource.
|
||||
* @param font Font to push the result in to.
|
||||
* @param fileName Filename of the asset to load.
|
||||
* @return A pointer to the asset manager item for tracking.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerLoadFont(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner, char *fileName
|
||||
);
|
||||
|
||||
bool _assetManagerLoaderFontAsync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderFontSync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderFontDispose(assetmanageritem_t *item);
|
57
src/file/loaders/item.c
Normal file
57
src/file/loaders/item.c
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "item.h"
|
||||
|
||||
assetmanageritem_t * assetManagerItemGet(assetmanager_t *man, char *key) {
|
||||
uint8_t i;
|
||||
assetmanageritem_t *item;
|
||||
|
||||
for(i = 0; i < man->itemCount; i++) {
|
||||
item = man->items + i;
|
||||
if(strcmp(item->key, key) == 0) return item;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assetmanageritem_t * assetManagerItemAdd(assetmanager_t *manager, char *key) {
|
||||
// Check if key already exists.
|
||||
assetmanageritem_t *item = manager->items + manager->itemCount++;
|
||||
item->state = ASSET_MANAGER_STATE_NOT_READY;
|
||||
memcpy(item->key, key, strlen(key) + 1);
|
||||
item->holderCount = 0x00;
|
||||
return item;
|
||||
}
|
||||
|
||||
uint8_t assetManagerItemGetOrAddHolder(
|
||||
assetmanageritem_t *item, assetmanagerowner_t owner
|
||||
) {
|
||||
uint8_t i, firstEmpty;
|
||||
firstEmpty = 0xFF;
|
||||
|
||||
for(i = 0; i < item->holderCount; i++) {
|
||||
if(item->holders[i] == owner) return i;
|
||||
if(firstEmpty == 0xFF && item->holders[i] == 0xFF) {
|
||||
firstEmpty = i;
|
||||
}
|
||||
}
|
||||
|
||||
if(firstEmpty == 0xFF) firstEmpty = item->holderCount++;
|
||||
item->holders[firstEmpty] = owner;
|
||||
return firstEmpty;
|
||||
}
|
||||
|
||||
bool assetManagerItemIsFinished(assetmanageritem_t *item, assetmanagerloaderdefinition_t *def) {
|
||||
// Sync done is always done
|
||||
if(item->state == ASSET_MANAGER_STATE_SYNC_DONE) return true;
|
||||
// Only check if ASYNC is done.
|
||||
if(item->state != ASSET_MANAGER_STATE_ASYNC_DONE) return false;
|
||||
// Does it need to still sync load?
|
||||
if(def->loadSync == NULL) return true;
|
||||
return false;
|
||||
}
|
49
src/file/loaders/item.h
Normal file
49
src/file/loaders/item.h
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../types/common.h"
|
||||
|
||||
/**
|
||||
* Retreive an exisitng asset manager item by its key.
|
||||
*
|
||||
* @param man Manager to get from
|
||||
* @param key Key to search for.
|
||||
* @return The matching asset manager item, or NULL if not found.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerItemGet(assetmanager_t *man, char *key);
|
||||
|
||||
/**
|
||||
* Private method, simply adds an item to the manager and resets the state.
|
||||
*
|
||||
* @param manager Manager to add to.
|
||||
* @param key Key to use when adding.
|
||||
* @return The added and reset item.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerItemAdd(assetmanager_t *manager, char *key);
|
||||
|
||||
/**
|
||||
* Add or get the index that a given holder has as a manager item.
|
||||
*
|
||||
* @param i Asset Item to check.
|
||||
* @param o Owner to get/add.
|
||||
* @return The index within the item that the owner is at.
|
||||
*/
|
||||
uint8_t assetManagerItemGetOrAddHolder(
|
||||
assetmanageritem_t *i, assetmanagerowner_t o
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks if a given asset item is finished or not.
|
||||
*
|
||||
* @param item Item to check.
|
||||
* @param def Item type definition used for loading.
|
||||
* @return True if finished, otherwise false.
|
||||
*/
|
||||
bool assetManagerItemIsFinished(
|
||||
assetmanageritem_t *item, assetmanagerloaderdefinition_t *def
|
||||
);
|
123
src/file/loaders/scaledtexture.c
Normal file
123
src/file/loaders/scaledtexture.c
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scaledtexture.h"
|
||||
|
||||
assetmanageritem_t * assetManagerLoadScaledTexture(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner,
|
||||
char *path, char *file, uint8_t scale
|
||||
) {
|
||||
assetmanageritem_t *item;
|
||||
texturescale_t *st;
|
||||
char buffer[ASSET_MANAGER_ITEM_NAME_MAX];
|
||||
|
||||
sprintf(buffer, "%s/%s_%u", path, file, scale);
|
||||
item = assetManagerItemGet(manager, buffer);
|
||||
|
||||
if(item == NULL) {
|
||||
item = assetManagerItemAdd(manager, buffer);
|
||||
item->type = ASSET_MANAGER_TYPE_SCALED_TEXTURE;
|
||||
item->data.scaledTexture.scale = scale;
|
||||
|
||||
st = &item->data.scaledTexture.textureScale;
|
||||
st->scaleCount = 0;
|
||||
st->baseWidth = 0;
|
||||
st->baseHeight = 0;
|
||||
st->path = path;
|
||||
st->file = file;
|
||||
}
|
||||
|
||||
assetManagerItemGetOrAddHolder(item, owner);
|
||||
return item;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderScaledTextureAsync(assetmanageritem_t *item) {
|
||||
char buffer[128];
|
||||
char *xmlData;
|
||||
xml_t xml;
|
||||
xml_t *child;
|
||||
int16_t i, j;
|
||||
texturescale_t *st;
|
||||
texturescalescale_t *sts;
|
||||
size_t length;
|
||||
|
||||
// TODO: This can be improved if we allow both asset dependencies and
|
||||
// dependency sibling adding
|
||||
|
||||
st = &item->data.scaledTexture.textureScale;
|
||||
|
||||
// Begin loading texture XML
|
||||
sprintf(buffer, "%s/%s.xml", st->path, st->file);
|
||||
|
||||
xmlData = assetStringLoad(buffer);
|
||||
if(xmlData == NULL) return false;
|
||||
xmlLoad(&xml, xmlData);
|
||||
free(xmlData);
|
||||
|
||||
// Parse root texture info
|
||||
i = xmlGetAttributeByName(&xml, "channels");
|
||||
st->channels = (uint8_t)atoi(xml.attributeDatas[i]);
|
||||
i = xmlGetAttributeByName(&xml, "width");
|
||||
st->baseWidth = (int16_t)atoi(xml.attributeDatas[i]);
|
||||
i = xmlGetAttributeByName(&xml, "height");
|
||||
st->baseHeight = (int16_t)atoi(xml.attributeDatas[i]);
|
||||
|
||||
for(j = 0; j < xml.childrenCount; j++) {
|
||||
child = xml.children + j;
|
||||
i = xmlGetAttributeByName(child, "scale");
|
||||
st->scales[st->scaleCount].scale = (uint8_t)atoi(child->attributeDatas[i]);
|
||||
i = xmlGetAttributeByName(child, "width");
|
||||
st->scales[st->scaleCount].width = (int16_t)atoi(child->attributeDatas[i]);
|
||||
i = xmlGetAttributeByName(child, "height");
|
||||
st->scales[st->scaleCount].height = (int16_t)atoi(child->attributeDatas[i]);
|
||||
st->scaleCount++;
|
||||
}
|
||||
|
||||
// Cleanup XML
|
||||
xmlDispose(&xml);
|
||||
|
||||
// Get the scale
|
||||
sts = st->scales + item->data.scaledTexture.scale;
|
||||
|
||||
// Get filename
|
||||
sprintf(buffer, "%s/%s_%i.texture", st->path, st->file, sts->scale);
|
||||
|
||||
// Create some space
|
||||
length = assetRawLoad(buffer, NULL);
|
||||
if(length == 0) return false;
|
||||
item->data.scaledTexture.data = malloc(sizeof(pixel_t) * length);
|
||||
|
||||
// Load
|
||||
length = assetRawLoad(buffer, (uint8_t *)item->data.scaledTexture.data);
|
||||
if(length == 0) {
|
||||
free(item->data.scaledTexture.data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderScaledTextureSync(assetmanageritem_t *item) {
|
||||
texturescale_t *st;
|
||||
texturescalescale_t *sts;
|
||||
st = &item->data.scaledTexture.textureScale;
|
||||
sts = st->scales + item->data.scaledTexture.scale;
|
||||
|
||||
textureInit(
|
||||
&item->data.scaledTexture.texture,
|
||||
sts->width, sts->height,
|
||||
item->data.scaledTexture.data
|
||||
);
|
||||
|
||||
free(item->data.scaledTexture.data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderScaledTextureDispose(assetmanageritem_t *item) {
|
||||
textureDispose(&item->data.scaledTexture.texture);
|
||||
return true;
|
||||
}
|
30
src/file/loaders/scaledtexture.h
Normal file
30
src/file/loaders/scaledtexture.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "../xml.h"
|
||||
#include "../asset.h"
|
||||
|
||||
/**
|
||||
* Load the given texture scale for a scaled texture.
|
||||
*
|
||||
* @param manager Manager to queue on to.
|
||||
* @param owner Owner ID requesting to load this resource.
|
||||
* @param path Path of the texture size sets
|
||||
* @param file Name of the texture that was generated.
|
||||
* @param scale Scale to load.
|
||||
* @return A pointer to the asset manager item for tracking.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerLoadScaledTexture(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner,
|
||||
char *path, char *file, uint8_t scale
|
||||
);
|
||||
|
||||
bool _assetManagerLoaderScaledTextureAsync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderScaledTextureSync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderScaledTextureDispose(assetmanageritem_t *item);
|
55
src/file/loaders/shader.c
Normal file
55
src/file/loaders/shader.c
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "shader.h"
|
||||
|
||||
assetmanageritem_t * assetManagerLoadShader(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner,
|
||||
char *fileVert, char *fileFrag
|
||||
) {
|
||||
assetmanageritem_t *item;
|
||||
char buffer[ASSET_MANAGER_ITEM_NAME_MAX];
|
||||
sprintf(buffer, "%s/%s", fileVert, fileFrag);
|
||||
item = assetManagerItemGet(manager, buffer);
|
||||
if(item == NULL) {
|
||||
item = assetManagerItemAdd(manager, buffer);
|
||||
item->type = ASSET_MANAGER_TYPE_SHADER;
|
||||
item->data.shader.fileVert = fileVert;
|
||||
item->data.shader.fileFrag = fileFrag;
|
||||
}
|
||||
assetManagerItemGetOrAddHolder(item, owner);
|
||||
return item;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderShaderAsync(assetmanageritem_t *item) {
|
||||
item->data.shader.dataVert = assetStringLoad(item->data.shader.fileVert);
|
||||
if(item->data.shader.dataVert == NULL) return false;
|
||||
|
||||
item->data.shader.dataFrag = assetStringLoad(item->data.shader.fileFrag);
|
||||
if(item->data.shader.dataFrag == NULL) {
|
||||
free(item->data.shader.fileVert);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderShaderSync(assetmanageritem_t *item) {
|
||||
shaderInit(
|
||||
&item->data.shader.shader,
|
||||
item->data.shader.dataVert,
|
||||
item->data.shader.dataFrag
|
||||
);
|
||||
free(item->data.shader.dataFrag);
|
||||
free(item->data.shader.dataVert);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderShaderDispose(assetmanageritem_t *item) {
|
||||
shaderDispose(&item->data.shader.shader);
|
||||
return true;
|
||||
}
|
29
src/file/loaders/shader.h
Normal file
29
src/file/loaders/shader.h
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "../asset.h"
|
||||
|
||||
/**
|
||||
* Queues a shader load onto the asset manager buffer.
|
||||
*
|
||||
* @param manager Manager to queue on to.
|
||||
* @param owner Owner ID requesting to load this resource.
|
||||
* @param shader Shader to push the result in to.
|
||||
* @param fileVert Vertex file in question to load.
|
||||
* @param fileFrag Fragment file in question to load.
|
||||
* @return A pointer to the asset manager item for tracking.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerLoadShader(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner,
|
||||
char *fileVert, char *fileFrag
|
||||
);
|
||||
|
||||
bool _assetManagerLoaderShaderAsync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderShaderSync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderShaderDispose(assetmanageritem_t *item);
|
69
src/file/loaders/texture.c
Normal file
69
src/file/loaders/texture.c
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
assetmanageritem_t * assetManagerLoadTexture(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner, char *fileName
|
||||
) {
|
||||
assetmanageritem_t *item;
|
||||
item = assetManagerItemGet(manager, fileName);
|
||||
if(item == NULL) {
|
||||
item = assetManagerItemAdd(manager, fileName);
|
||||
item->type = ASSET_MANAGER_TYPE_TEXTURE;
|
||||
item->data.texture.fileName = fileName;
|
||||
}
|
||||
assetManagerItemGetOrAddHolder(item, owner);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderTextureAsync(assetmanageritem_t *item) {
|
||||
assetbuffer_t *buffer;
|
||||
int channels;
|
||||
stbi_io_callbacks OPENGL_STBI_CALLBACKS;
|
||||
|
||||
buffer = assetBufferOpen(item->data.texture.fileName);
|
||||
if(buffer == NULL) return false;
|
||||
|
||||
// Setup the interface for STBI
|
||||
OPENGL_STBI_CALLBACKS.read = &assetBufferRead;
|
||||
OPENGL_STBI_CALLBACKS.skip = &assetBufferSkip;
|
||||
OPENGL_STBI_CALLBACKS.eof = &assetBufferEnd;
|
||||
|
||||
// Buffer the image
|
||||
channels = 0;
|
||||
item->data.texture.data = (pixel_t *)stbi_load_from_callbacks(
|
||||
&OPENGL_STBI_CALLBACKS, buffer,
|
||||
&item->data.texture.width, &item->data.texture.height,
|
||||
&channels, STBI_rgb_alpha
|
||||
);
|
||||
|
||||
// Close the buffer
|
||||
assetBufferClose(buffer);
|
||||
if(item->data.texture.data == NULL) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderTextureSync(assetmanageritem_t *item) {
|
||||
// Turn into a texture.
|
||||
textureInit(
|
||||
&item->data.texture.texture,
|
||||
item->data.texture.width,
|
||||
item->data.texture.height,
|
||||
item->data.texture.data
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
stbi_image_free(item->data.texture.data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderTextureDispose(assetmanageritem_t *item) {
|
||||
textureDispose(&item->data.texture.texture);
|
||||
return true;
|
||||
}
|
27
src/file/loaders/texture.h
Normal file
27
src/file/loaders/texture.h
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "../asset.h"
|
||||
|
||||
/**
|
||||
* Queue a texture load onto the asset manager buffer.
|
||||
*
|
||||
* @param manager Manager to queue on to.
|
||||
* @param owner Owner ID requesting to load this resource.
|
||||
* @param texture Texture to push the result in to.
|
||||
* @param fileName Texture filename to load.
|
||||
* @return A pointer to the asset manager item for tracking.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerLoadTexture(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner, char *fileName
|
||||
);
|
||||
|
||||
bool _assetManagerLoaderTextureAsync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderTextureSync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderTextureDispose(assetmanageritem_t *item);
|
80
src/file/types/common.h
Normal file
80
src/file/types/common.h
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../engine/thread.h"
|
||||
#include "texture.h"
|
||||
#include "font.h"
|
||||
#include "shader.h"
|
||||
#include "scaledtexture.h"
|
||||
|
||||
#define ASSET_MANAGER_ITEMS_MAX 64
|
||||
#define ASSET_MANAGER_ITEM_NAME_MAX 96
|
||||
#define ASSET_MANAGER_HOLDERS_MAX 8
|
||||
|
||||
/** States */
|
||||
#define ASSET_MANAGER_STATE_NOT_READY 0x00
|
||||
#define ASSET_MANAGER_STATE_PENDING 0x01
|
||||
#define ASSET_MANAGER_STATE_ASYNC_LOADING 0x02
|
||||
#define ASSET_MANAGER_STATE_ASYNC_ERROR 0x03
|
||||
#define ASSET_MANAGER_STATE_ASYNC_DONE 0x04
|
||||
#define ASSET_MANAGER_STATE_SYNC_LOADING 0x05
|
||||
#define ASSET_MANAGER_STATE_SYNC_ERROR 0x06
|
||||
#define ASSET_MANAGER_STATE_SYNC_DONE 0x07
|
||||
|
||||
/** Type IDs */
|
||||
#define ASSET_MANAGER_TYPE_TEXTURE 0x00
|
||||
#define ASSET_MANAGER_TYPE_FONT 0x01
|
||||
#define ASSET_MANAGER_TYPE_SHADER 0x02
|
||||
#define ASSET_MANAGER_TYPE_SCALED_TEXTURE 0x03
|
||||
|
||||
// Owner
|
||||
typedef uint8_t assetmanagerowner_t;
|
||||
|
||||
// Union of all the manager types
|
||||
typedef union {
|
||||
assetmanagertexture_t texture;
|
||||
assetmanagershader_t shader;
|
||||
assetmanagerfont_t font;
|
||||
assetmanagerscaledtexture_t scaledTexture;
|
||||
} assetmanagerassetdata_t;
|
||||
|
||||
// Item Type
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t state;
|
||||
char key[ASSET_MANAGER_ITEM_NAME_MAX];
|
||||
assetmanagerassetdata_t data;
|
||||
assetmanagerowner_t holders[ASSET_MANAGER_HOLDERS_MAX];
|
||||
uint8_t holderCount;
|
||||
} assetmanageritem_t;
|
||||
|
||||
// Loader
|
||||
typedef bool assetmanagerloader_t(assetmanageritem_t *item);
|
||||
|
||||
// Loader Definition
|
||||
typedef struct {
|
||||
assetmanagerloader_t *loadAsync;
|
||||
assetmanagerloader_t *loadSync;
|
||||
assetmanagerloader_t *dispose;
|
||||
} assetmanagerloaderdefinition_t;
|
||||
|
||||
|
||||
|
||||
// Manager
|
||||
typedef struct {
|
||||
thread_t thread;
|
||||
bool finished;
|
||||
bool running;
|
||||
|
||||
assetmanageritem_t items[ASSET_MANAGER_ITEMS_MAX];
|
||||
uint8_t itemCount;
|
||||
|
||||
assetmanagerowner_t holders[ASSET_MANAGER_HOLDERS_MAX];
|
||||
uint8_t holderCount;
|
||||
} assetmanager_t;
|
15
src/file/types/font.h
Normal file
15
src/file/types/font.h
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../display/font.h"
|
||||
|
||||
typedef struct {
|
||||
font_t font;
|
||||
char *fileName;
|
||||
char *data;
|
||||
} assetmanagerfont_t;
|
18
src/file/types/scaledtexture.h
Normal file
18
src/file/types/scaledtexture.h
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../display/texture.h"
|
||||
#include "../../display/texturescale.h"
|
||||
|
||||
typedef struct {
|
||||
texturescale_t textureScale;
|
||||
texture_t texture;
|
||||
uint8_t scale;
|
||||
pixel_t *data;
|
||||
} assetmanagerscaledtexture_t;
|
16
src/file/types/shader.h
Normal file
16
src/file/types/shader.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../display/shader.h"
|
||||
|
||||
typedef struct {
|
||||
shader_t shader;
|
||||
char *fileVert;
|
||||
char *fileFrag;
|
||||
char *dataVert;
|
||||
char *dataFrag;
|
||||
} assetmanagershader_t;
|
15
src/file/types/texture.h
Normal file
15
src/file/types/texture.h
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../display/texture.h"
|
||||
|
||||
typedef struct {
|
||||
texture_t texture;
|
||||
char *fileName;
|
||||
int32_t width, height;
|
||||
pixel_t *data;
|
||||
} assetmanagertexture_t;
|
210
src/file/xml.c
Normal file
210
src/file/xml.c
Normal file
@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i) {
|
||||
char c;
|
||||
int32_t level = 0;
|
||||
uint8_t doing = XML_DOING_NOTHING;
|
||||
bool insideTag = false;
|
||||
char* buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
int32_t bufferLength = 0;
|
||||
|
||||
xml->value = NULL;
|
||||
xml->attributeCount = 0;
|
||||
|
||||
xml->children = malloc(sizeof(xml_t) * XML_CHILD_COUNT_MAX);
|
||||
xml->childrenCount = 0;
|
||||
|
||||
while(c = data[i++]) {
|
||||
switch(doing) {
|
||||
case XML_DOING_NOTHING:
|
||||
// Look for either an opening tag (<) or a word for a value.
|
||||
if(c == '>') continue;
|
||||
if(c == '<') {
|
||||
if(insideTag) {
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
doing = XML_PARSING_CHILD;
|
||||
} else {
|
||||
doing = XML_PARSING_TAG_NAME;
|
||||
level++;
|
||||
insideTag = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
doing = XML_PARSING_VALUE;
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_TAG_NAME:
|
||||
// Just keep reading until we either hit a space (end of the tag name)
|
||||
// or a closing tag value, either / or >
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/') {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->node = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
} else {
|
||||
doing = c == '>' ? XML_DOING_NOTHING : XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE:
|
||||
// Look until we hit either the end of a tag, or the attribute itself
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/' || c == '=') {
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
}
|
||||
} else if(c == '=') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE_VALUE;
|
||||
} else {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
|
||||
if(bufferLength > 0) {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeNames[xml->attributeCount++] = buffer;
|
||||
xml->attributeDatas[xml->attributeCount] = NULL;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE_VALUE:
|
||||
// Keep looking until we find a quote mark
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
insideTag = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c != '"') continue;
|
||||
doing = XML_PARSING_ATTRIBUTE_VALUE;
|
||||
break;
|
||||
|
||||
case XML_PARSING_ATTRIBUTE_VALUE:
|
||||
// Parse the attribute value until we find a quote mark.
|
||||
if(c == '"') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeDatas[xml->attributeCount - 1] = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_VALUE:
|
||||
// Keep parsing child until we find a < for an opening/closing tag.
|
||||
if(c == '<') {
|
||||
// In HTML Spec there could be a child here but not in XML spec.
|
||||
doing = XML_PARSING_CLOSE;
|
||||
buffer[bufferLength] = '\0';
|
||||
bufferLength = 0;
|
||||
xml->value = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_CHILD:
|
||||
if(c == '<') {
|
||||
// Read ahead and confirm this is a close or not
|
||||
if(data[i] == '/') {
|
||||
doing = XML_PARSING_CLOSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Likely another child.
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
|
||||
// In HTML Spec there's a chance for there to be a value here, but not
|
||||
// in the XML spec.
|
||||
break;
|
||||
|
||||
case XML_PARSING_CLOSE:
|
||||
// Just keep parsing until the tag closer finishes.
|
||||
if(c != '>') continue;
|
||||
doing = XML_DOING_NOTHING;
|
||||
|
||||
//TODO: Return index or something?
|
||||
free(buffer);
|
||||
return i;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return i;
|
||||
}
|
||||
|
||||
void xmlLoad(xml_t *xml, char *data) {
|
||||
xmlLoadChild(xml, data, 0);
|
||||
}
|
||||
|
||||
void xmlDispose(xml_t *xml) {
|
||||
uint8_t i;
|
||||
|
||||
// Dispose children recursively
|
||||
for(i = 0; i < xml->childrenCount; i++) {
|
||||
xmlDispose(xml->children + i);
|
||||
}
|
||||
|
||||
// Free children array.
|
||||
free(xml->children);
|
||||
|
||||
// Dispose attributes
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
free(xml->attributeNames[i]);
|
||||
if((xml->attributeDatas + i) != NULL) {
|
||||
free(xml->attributeDatas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(xml->node);
|
||||
if(xml-> value != NULL) free(xml->value);
|
||||
}
|
||||
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name) {
|
||||
int16_t i;
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
if(strcmp(xml->attributeNames[i], name) == 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool xmlIsWhitespace(char c) {
|
||||
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
|
||||
}
|
66
src/file/xml.h
Normal file
66
src/file/xml.h
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
|
||||
#define XML_DOING_NOTHING 0x00
|
||||
#define XML_PARSING_TAG_NAME 0x01
|
||||
#define XML_LOOKING_FOR_ATTRIBUTE 0x02
|
||||
#define XML_PARSING_ATTRIBUTE_NAME 0x03
|
||||
#define XML_LOOKING_FOR_ATTRIBUTE_VALUE 0x04
|
||||
#define XML_PARSING_ATTRIBUTE_VALUE 0x05
|
||||
#define XML_PARSING_VALUE 0x06
|
||||
#define XML_PARSING_CHILD 0x07
|
||||
#define XML_PARSING_CLOSE 0x08
|
||||
|
||||
#define XML_TEXT_BUFFER_MAX 256
|
||||
#define XML_CHILD_COUNT_MAX 16
|
||||
#define XML_ATTRIBUTE_MAX 16
|
||||
|
||||
typedef struct _xml_t xml_t;
|
||||
|
||||
typedef struct _xml_t {
|
||||
char *node;
|
||||
char *value;
|
||||
|
||||
char *attributeNames[XML_ATTRIBUTE_MAX];
|
||||
char *attributeDatas[XML_ATTRIBUTE_MAX];
|
||||
uint8_t attributeCount;
|
||||
|
||||
xml_t *children;
|
||||
uint8_t childrenCount;
|
||||
} xml_t;
|
||||
|
||||
/**
|
||||
* Load an XML child from a string buffer.
|
||||
*
|
||||
* @param xml XML to load.
|
||||
* @param data Data to parse
|
||||
* @param i Character index within the data
|
||||
* @return The index in the data string this XML node ends.
|
||||
*/
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i);
|
||||
|
||||
/**
|
||||
* Load an XML String into an XML memory.
|
||||
*
|
||||
* @param xml XML to load into.
|
||||
* @param data XML string.
|
||||
*/
|
||||
void xmlLoad(xml_t *xml, char *data);
|
||||
|
||||
/**
|
||||
* Dispose a previously loaded XML.
|
||||
*
|
||||
* @param xml XML to dispose.
|
||||
*/
|
||||
void xmlDispose(xml_t *xml);
|
||||
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name);
|
||||
|
||||
bool xmlIsWhitespace(char c);
|
Reference in New Issue
Block a user