Tool refactoring
This commit is contained in:
@@ -5,9 +5,6 @@
|
||||
|
||||
#pragma once
|
||||
#include "dawnsharedlibs.hpp"
|
||||
#include "../../util/file.hpp"
|
||||
#include "../../util/csv.hpp"
|
||||
#include "../../util/xml.hpp"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
@@ -1,120 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "csv.hpp"
|
||||
|
||||
char * csvGetCell(csv_t *csv, int32_t row, int32_t cell) {
|
||||
return csv->rows[(row * CSV_COLUMN_COUNT_MAX) + cell];
|
||||
}
|
||||
|
||||
void csvParse(char *string, csv_t *csv) {
|
||||
char c;
|
||||
size_t i, j, length;
|
||||
csvparsestate_t state;
|
||||
int32_t rowCellCount;
|
||||
|
||||
length = strlen(string);
|
||||
csv->buffer = (char *)malloc(sizeof(char) * (length+1) * CSV_COLUMN_COUNT_MAX * CSV_ROW_COUNT_MAX);
|
||||
csv->cellCounts = (int32_t *)malloc(sizeof(int32_t) * CSV_ROW_COUNT_MAX);
|
||||
csv->rows = (char**)malloc(sizeof(char*) * CSV_ROW_COUNT_MAX * CSV_COLUMN_COUNT_MAX);
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
rowCellCount = 0;
|
||||
csv->rowCount = 0;
|
||||
state = CSV_PARSE_STATE_FIND_CELL;
|
||||
while(i < length) {
|
||||
c = string[i++];
|
||||
|
||||
// What are we doing
|
||||
switch(state) {
|
||||
case CSV_PARSE_STATE_FIND_CELL:
|
||||
if(c == '"') {
|
||||
state = CSV_PARSE_STATE_PARSE_CELL_WITH_QUOTES;
|
||||
csv->rows[(csv->rowCount * CSV_COLUMN_COUNT_MAX) + rowCellCount] = csv->buffer + j;
|
||||
rowCellCount++;
|
||||
continue;
|
||||
} else if(c == '\r' || c == '\n') {
|
||||
// Newline (todo: is this a blank line?)
|
||||
state = CSV_PARSE_STATE_LINE_END;
|
||||
continue;
|
||||
} else if(c == ',') {
|
||||
csv->rows[(csv->rowCount * CSV_COLUMN_COUNT_MAX) + rowCellCount] = csv->buffer + j;
|
||||
csv->buffer[j++] = '\0';
|
||||
rowCellCount++;
|
||||
continue;
|
||||
} else {
|
||||
state = CSV_PARSE_STATE_PARSE_CELL;
|
||||
csv->rows[(csv->rowCount * CSV_COLUMN_COUNT_MAX) + rowCellCount] = csv->buffer + j;
|
||||
csv->buffer[j++] = c;
|
||||
rowCellCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
case CSV_PARSE_STATE_PARSE_CELL:
|
||||
if(c == '\r' || c == '\n') {
|
||||
state = CSV_PARSE_STATE_LINE_END;
|
||||
csv->buffer[j++] = '\0';
|
||||
continue;
|
||||
} else if(c == ',') {
|
||||
state = CSV_PARSE_STATE_FIND_CELL;
|
||||
csv->buffer[j++] = '\0';
|
||||
continue;
|
||||
}
|
||||
csv->buffer[j++] = c;
|
||||
continue;
|
||||
|
||||
case CSV_PARSE_STATE_PARSE_CELL_WITH_QUOTES:
|
||||
if((c == '\\' && string[i] == '"') || (c == '"' && string[i] == '"')) {
|
||||
// Handle escaped quotes. I normally see [\"] but excel does [""] in
|
||||
// most cases
|
||||
csv->buffer[j++] = '"';
|
||||
i++;
|
||||
continue;
|
||||
} else if(c == '"') {
|
||||
// Handle end of quoted string
|
||||
state = CSV_PARSE_STATE_FIND_CELL;
|
||||
csv->buffer[j++] = '\0';
|
||||
// Because we tend to do [",] at the end of a quoted cell, we do this
|
||||
// to prevent [,,] cases being treated the same
|
||||
if(string[i] == ',') i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Normal character.
|
||||
csv->buffer[j++] = c;
|
||||
continue;
|
||||
|
||||
case CSV_PARSE_STATE_LINE_END:
|
||||
// Skip blanks
|
||||
if(c == '\r' || c == '\n') continue;
|
||||
csv->cellCounts[csv->rowCount] = rowCellCount;
|
||||
csv->rowCount++;
|
||||
rowCellCount = 0;
|
||||
state = CSV_PARSE_STATE_FIND_CELL;
|
||||
i--;
|
||||
continue;
|
||||
|
||||
default:
|
||||
printf("Error occured during parse operation.");
|
||||
free(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
csv->buffer[j++] = '\0';
|
||||
|
||||
if(rowCellCount != 0) {
|
||||
csv->cellCounts[csv->rowCount] = rowCellCount;
|
||||
csv->rowCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void csvDispose(csv_t *csv) {
|
||||
free(csv->buffer);
|
||||
free(csv->cellCounts);
|
||||
free(csv->rows);
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dawnsharedlibs.hpp"
|
||||
#include "string.h"
|
||||
|
||||
#define CSV_ROW_COUNT_MAX 128
|
||||
#define CSV_COLUMN_COUNT_MAX 16
|
||||
|
||||
typedef enum {
|
||||
CSV_PARSE_STATE_FIND_CELL,//0
|
||||
CSV_PARSE_STATE_PARSE_CELL_WITH_QUOTES,
|
||||
CSV_PARSE_STATE_PARSE_CELL,//2
|
||||
CSV_PARSE_STATE_LINE_END
|
||||
} csvparsestate_t;
|
||||
|
||||
typedef struct {
|
||||
char *buffer;
|
||||
char **rows;
|
||||
int32_t rowCount;
|
||||
int32_t *cellCounts;
|
||||
} csv_t;
|
||||
|
||||
char * csvGetCell(csv_t *csv, int32_t row, int32_t cell);
|
||||
|
||||
void csvParse(char *string, csv_t *csv);
|
||||
|
||||
void csvDispose(csv_t *csv);
|
@@ -1,26 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "file.hpp"
|
||||
#include "File.hpp"
|
||||
|
||||
void fileNormalizeSlashes(char *string) {
|
||||
char c;
|
||||
int i = 0;
|
||||
using namespace Dawn;
|
||||
|
||||
while(c = string[i++]) {
|
||||
if(c != '\\' && c != '/') continue;
|
||||
string[i-1] = FILE_PATH_SEP;
|
||||
std::string File::normalizeSlashes(std::string str) {
|
||||
size_t i = 0;
|
||||
while(i < str.size()) {
|
||||
auto c = str[i];
|
||||
if(c == '\\' || c == '/') str[i] = FILE_PATH_SEP;
|
||||
++i;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void fileMkdirp(char *path) {
|
||||
char buffer[FILENAME_MAX];
|
||||
void File::mkdirp(std::string path) {
|
||||
std::string buffer;
|
||||
char c;
|
||||
int i = 0;
|
||||
size_t i = 0;
|
||||
bool inFile;
|
||||
bool hasMore;
|
||||
|
||||
@@ -28,172 +28,166 @@ void fileMkdirp(char *path) {
|
||||
hasMore = false;
|
||||
while(c = path[i]) {
|
||||
if((c == '\\' || c == '/') && i > 0) {
|
||||
buffer[i] = '\0';
|
||||
fileMkdir(buffer, 0755);
|
||||
fileMkdir(buffer.c_str(), 0755);
|
||||
inFile = false;
|
||||
hasMore = false;
|
||||
buffer[i] = FILE_PATH_SEP;
|
||||
buffer += FILE_PATH_SEP;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c == '.') inFile = true;
|
||||
hasMore = true;
|
||||
buffer[i] = c;
|
||||
buffer += c;
|
||||
i++;
|
||||
}
|
||||
|
||||
if(!inFile && hasMore) {
|
||||
buffer[i] = '\0';
|
||||
fileMkdir(buffer, 0755);
|
||||
fileMkdir(buffer.c_str(), 0755);
|
||||
}
|
||||
}
|
||||
|
||||
size_t assetReadString(FILE *file, char *buffer) {
|
||||
size_t length;
|
||||
fseek(file, 0, SEEK_END);// Seek to the end
|
||||
length = ftell(file);// Get our current position (the end)
|
||||
fseek(file, 0, SEEK_SET);// Reset the seek
|
||||
if(buffer == NULL) return length;
|
||||
return fread(buffer, 1, length, file);// Read all the bytes
|
||||
//
|
||||
|
||||
File::File(std::string filename) {
|
||||
this->filename = File::normalizeSlashes(filename);
|
||||
}
|
||||
|
||||
int32_t readAhead(
|
||||
char *bufferIn, int32_t start,
|
||||
char *bufferOut,
|
||||
char *needles, int32_t needleCount
|
||||
) {
|
||||
int32_t i = start, k = 0, j;
|
||||
char c;
|
||||
bool needleFound = false;
|
||||
bool_t File::open(enum FileMode mode) {
|
||||
assertNull(this->file);
|
||||
|
||||
if(bufferIn[i] == '\0') return 0;
|
||||
this->mode = mode;
|
||||
this->file = fopen(
|
||||
this->filename.c_str(),
|
||||
mode == FILE_MODE_READ ? "rb" : "wb"
|
||||
);
|
||||
|
||||
while((c = bufferIn[i++]) != '\0') {
|
||||
for(j = 0; j < needleCount; j++) {
|
||||
if(c != needles[j]) continue;
|
||||
needleFound = true;
|
||||
}
|
||||
if(needleFound) break;
|
||||
if(bufferOut != NULL) bufferOut[k] = c;
|
||||
k++;
|
||||
}
|
||||
if(this->file == NULL) return false;
|
||||
|
||||
if(bufferOut != NULL) bufferOut[k] = '\0';
|
||||
return k;
|
||||
}
|
||||
if(mode == FILE_MODE_READ) {
|
||||
fseek(this->file, 0, SEEK_END);
|
||||
this->length = ftell(this->file);
|
||||
fseek(this->file, 0, SEEK_SET);
|
||||
|
||||
int32_t skipAhead(
|
||||
char *bufferIn, int32_t start,
|
||||
char *needles, int32_t needleCount
|
||||
) {
|
||||
char c;
|
||||
int32_t j, k = 0, i = start;
|
||||
bool needleFound;
|
||||
|
||||
while((c = bufferIn[i++]) != '\0') {
|
||||
needleFound = false;
|
||||
for(j = 0; j < needleCount; j++) {
|
||||
if(c != needles[j]) continue;
|
||||
needleFound = true;
|
||||
break;
|
||||
}
|
||||
if(!needleFound) break;
|
||||
k++;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
void fileGetDirectory(char *file, char* buffer) {
|
||||
char *c, *p;
|
||||
int32_t i;
|
||||
p = strrchr(file, FILE_PATH_SEP);
|
||||
c = file;
|
||||
i = 0;
|
||||
do {
|
||||
buffer[i++] = *c;
|
||||
} while(++c < p);
|
||||
buffer[i] = '\0';
|
||||
}
|
||||
|
||||
bool fileListChildren(
|
||||
char *directory,
|
||||
char *buffer,
|
||||
int32_t *count,
|
||||
uint8_t *types,
|
||||
char **children
|
||||
) {
|
||||
#if defined(_MSC_VER)
|
||||
WIN32_FIND_DATA fdFile;
|
||||
HANDLE hFind = NULL;
|
||||
char sPath[2048];
|
||||
int32_t i;
|
||||
|
||||
// Append wildcard
|
||||
sprintf(sPath, "%s\\*.*", directory);
|
||||
|
||||
// Scan first
|
||||
if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE) {
|
||||
printf("Path not found: [%s]\n", directory);
|
||||
if(this->length <= 0) {
|
||||
this->close();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
this->length = 0;
|
||||
}
|
||||
|
||||
// Iterate
|
||||
i = 0;
|
||||
do {
|
||||
if(
|
||||
strcmp(fdFile.cFileName, ".") == 0 ||
|
||||
strcmp(fdFile.cFileName, "..") == 0
|
||||
) continue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get Full path.
|
||||
sprintf(sPath, "%s\\%s", directory, fdFile.cFileName);
|
||||
bool_t File::isOpen() {
|
||||
return this->file != nullptr;
|
||||
}
|
||||
|
||||
//Is the entity a File or Folder?
|
||||
if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
types[i] = FILE_CHILD_TYPE_DIR;
|
||||
} else {
|
||||
types[i] = FILE_CHILD_TYPE_FILE;
|
||||
}
|
||||
bool_t File::exists() {
|
||||
if(this->file != nullptr) return true;
|
||||
FILE *f = fopen(this->filename.c_str(), "rb");
|
||||
if(f == NULL || f == nullptr) return false;
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
children[i] = buffer + (i * FILE_CHILD_NAME_MAX);
|
||||
strcpy(children[i], fdFile.cFileName);
|
||||
i++;
|
||||
} while(FindNextFile(hFind, &fdFile));
|
||||
void File::close() {
|
||||
assertNotNull(this->file);
|
||||
fclose(this->file);
|
||||
this->file = nullptr;
|
||||
}
|
||||
|
||||
*count = i;
|
||||
return true;
|
||||
#else
|
||||
struct dirent *de;
|
||||
DIR *dr;
|
||||
int32_t i;
|
||||
bool_t File::mkdirp() {
|
||||
File::mkdirp(this->filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Open Dir
|
||||
dr = opendir(directory);
|
||||
if(dr == NULL) {
|
||||
printf("Could not open directory");
|
||||
return false;
|
||||
}
|
||||
bool_t File::readString(std::string *out) {
|
||||
assertNotNull(out);
|
||||
|
||||
if(!this->isOpen()) {
|
||||
if(!this->open(FILE_MODE_READ)) return false;
|
||||
}
|
||||
assertTrue(this->mode == FILE_MODE_READ);
|
||||
out->clear();
|
||||
|
||||
// Iterate
|
||||
i = 0;
|
||||
while ((de = readdir(dr)) != NULL) {
|
||||
// File or folder?
|
||||
if(de->d_type != DT_REG) continue;
|
||||
size_t i = 0;
|
||||
char buffer[FILE_BUFFER_SIZE + 1];// +1 for null term
|
||||
while(i != this->length) {
|
||||
size_t amt = mathMin<size_t>(FILE_BUFFER_SIZE, (this->length - i));
|
||||
auto amtRead = fread(buffer, sizeof(char), amt, this->file);
|
||||
if(amtRead != amt) return false;
|
||||
i += amtRead;
|
||||
buffer[amtRead] = '\0';
|
||||
out->append(buffer);
|
||||
}
|
||||
|
||||
// Copy into child buffer
|
||||
children[i] = buffer + (i * FILE_CHILD_NAME_MAX);
|
||||
strcpy(children[i], de->d_name);
|
||||
i++;
|
||||
}
|
||||
if(closedir(dr)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t File::readAhead(char *buffer, size_t max, char needle) {
|
||||
assertNotNull(buffer);
|
||||
assertTrue(max > 0);
|
||||
|
||||
if(!this->isOpen()) {
|
||||
if(!this->open(FILE_MODE_READ)) return 0;
|
||||
}
|
||||
assertTrue(this->mode == FILE_MODE_READ);
|
||||
|
||||
// Buffer
|
||||
size_t pos = ftell(this->file);
|
||||
size_t amountLeftToRead = mathMin<size_t>(max, this->length - pos);
|
||||
char temporary[FILE_BUFFER_SIZE];
|
||||
size_t n = 0;
|
||||
|
||||
*count = i;
|
||||
return true;
|
||||
#endif
|
||||
while(amountLeftToRead > 0) {
|
||||
size_t toRead = mathMin<size_t>(amountLeftToRead, FILE_BUFFER_SIZE);
|
||||
amountLeftToRead -= toRead;
|
||||
// Read bytes
|
||||
size_t read = fread(temporary, sizeof(char), toRead, this->file);
|
||||
|
||||
// Read error?
|
||||
if(toRead != read) return 0;
|
||||
|
||||
// Did we read the needle?
|
||||
size_t i = 0;
|
||||
while(i < read) {
|
||||
char c = temporary[i++];
|
||||
if(c == needle) {
|
||||
return n;
|
||||
} else {
|
||||
buffer[n++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Needle was not found.
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string fileNormalizeSlashesNew(std::string str) {
|
||||
return str;
|
||||
bool_t File::writeString(std::string in) {
|
||||
if(!this->isOpen()) {
|
||||
if(!this->open(FILE_MODE_WRITE)) return false;
|
||||
}
|
||||
assertTrue(this->mode == FILE_MODE_WRITE);
|
||||
return this->writeRaw((char *)in.c_str(), in.size()) && this->length == in.size();
|
||||
}
|
||||
|
||||
bool_t File::writeRaw(char *data, size_t len) {
|
||||
if(!this->isOpen()) {
|
||||
if(!this->open(FILE_MODE_WRITE)) return false;
|
||||
}
|
||||
assertTrue(this->mode == FILE_MODE_WRITE);
|
||||
this->length = fwrite(data, sizeof(char_t), len, this->file);
|
||||
return true;
|
||||
}
|
||||
|
||||
void File::setPosition(size_t n) {
|
||||
fseek(this->file, 0, SEEK_SET);
|
||||
fseek(this->file, n, SEEK_CUR);
|
||||
}
|
||||
|
||||
File::~File() {
|
||||
if(this->file != nullptr) this->close();
|
||||
}
|
@@ -1,17 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnsharedlibs.hpp"
|
||||
|
||||
#define FILE_CHILD_TYPE_DIR 0x00
|
||||
#define FILE_CHILD_TYPE_FILE 0x01
|
||||
#define FILE_CHILD_NAME_MAX 512
|
||||
#define FILE_CHILD_COUNT_MAX 64
|
||||
#include "assert/assert.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <direct.h>
|
||||
@@ -26,51 +20,121 @@
|
||||
#define FILE_PATH_SEP '/'
|
||||
#define fileMkdir(path, perms) mkdir(path, perms)
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
void fileNormalizeSlashes(char *string);
|
||||
#define FILE_BUFFER_SIZE 512
|
||||
|
||||
void fileMkdirp(char *path);
|
||||
namespace Dawn {
|
||||
enum FileMode {
|
||||
FILE_MODE_READ,
|
||||
FILE_MODE_WRITE
|
||||
};
|
||||
|
||||
size_t assetReadString(FILE *file, char *buffer);
|
||||
class File {
|
||||
private:
|
||||
enum FileMode mode;
|
||||
|
||||
void fileGetDirectory(char *file, char* buffer);
|
||||
public:
|
||||
static std::string normalizeSlashes(std::string str);
|
||||
static void mkdirp(std::string path);
|
||||
|
||||
bool fileListChildren(
|
||||
char *directory,
|
||||
char *buffer,
|
||||
int32_t *count,
|
||||
uint8_t *types,
|
||||
char **children
|
||||
);
|
||||
std::string filename;
|
||||
size_t length;
|
||||
FILE *file = nullptr;
|
||||
|
||||
/**
|
||||
* Reads ahead to the first instance of the given character you provide.
|
||||
*
|
||||
* @param bufferIn Buffer to scan.
|
||||
* @param start Start position within the buffer to scan from (inclusive).
|
||||
* @param bufferOut Where to write the temporary data that was read ahead.
|
||||
* @param needles Array of characters to scan for.
|
||||
* @param needleCount How many elements are within the needles array.
|
||||
* @return The count of characters skipped.
|
||||
*/
|
||||
int32_t readAhead(
|
||||
char *bufferIn, int32_t start,
|
||||
char *bufferOut,
|
||||
char *needles, int32_t needleCount
|
||||
);
|
||||
/**
|
||||
* Constructs a new File interface class.
|
||||
*
|
||||
* @param filename Filename that you want to interface with.
|
||||
*/
|
||||
File(std::string filename);
|
||||
|
||||
/**
|
||||
* Skips any characters found in the needles.
|
||||
*
|
||||
* @param bufferIn Buffer of chars to read.
|
||||
* @param start Start of the buffer.
|
||||
* @param needles Needles you are trying to skip.
|
||||
* @param needleCount Count of needles in the needles array.
|
||||
* @return The count of chars to skip ahead.
|
||||
*/
|
||||
int32_t skipAhead(
|
||||
char *bufferIn, int32_t start,
|
||||
char *needles, int32_t needleCount
|
||||
);
|
||||
/**
|
||||
* Opens a connection to the file.
|
||||
*
|
||||
* @param mode File mode to use for this interface.
|
||||
* @return True if success, otherwise for failure.
|
||||
*/
|
||||
bool_t open(enum FileMode mode);
|
||||
|
||||
static std::string fileNormalizeSlashesNew(std::string str);
|
||||
/**
|
||||
* Returns whether or not the file connection is currently opened.
|
||||
*
|
||||
* @return True if the connection is open, otherwise if it's not.
|
||||
*/
|
||||
bool_t isOpen();
|
||||
|
||||
/**
|
||||
* Returns whether or not the file exists. Will open the connection if it
|
||||
* does exist.
|
||||
*
|
||||
* @return True if exists, otherwsie if it doesn't.
|
||||
*/
|
||||
bool_t exists();
|
||||
|
||||
/**
|
||||
* Closes the currently open interface to the file. Done automatically
|
||||
* when this object is disposed.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Makes all directories above this file's filename.
|
||||
*
|
||||
* @return True if successful, otherwise false.
|
||||
*/
|
||||
bool_t mkdirp();
|
||||
|
||||
/**
|
||||
* Reads the entire contents of a file to the given output string buffer.
|
||||
* This is a bit dangerous since the length of the file isn't checked
|
||||
* against the memory to be consumed.
|
||||
*
|
||||
* @param out Pointer to a string where the output data will be stored.
|
||||
* @return True if the read was successful, otherwise false.
|
||||
*/
|
||||
bool_t readString(std::string *out);
|
||||
|
||||
/**
|
||||
* Reads ahead from the current position to a specific needle (character).
|
||||
*
|
||||
* @param buffer Buffer to output read chars to.
|
||||
* @param max Max length of the buffer / amount of chars to read ahead.
|
||||
* @param needle The character (needle) to look for.
|
||||
* @return Amount of chars read, or <= 0 on error.
|
||||
*/
|
||||
size_t readAhead(
|
||||
char *buffer,
|
||||
size_t max,
|
||||
char needle
|
||||
);
|
||||
|
||||
/**
|
||||
* Writes the entire contents of a string to a file.
|
||||
*
|
||||
* @param in String to write to this file.
|
||||
* @return True if written successfully, otherwise false.
|
||||
*/
|
||||
bool_t writeString(std::string in);
|
||||
|
||||
/**
|
||||
* Write raw bytes to the file.
|
||||
*
|
||||
* @param data Data to write.
|
||||
* @return True if written successfully, otherwise false.
|
||||
*/
|
||||
bool_t writeRaw(char *data, size_t );
|
||||
|
||||
/**
|
||||
* Set the position of the cursor of the file reader.
|
||||
*
|
||||
* @param pos Position to set.
|
||||
*/
|
||||
void setPosition(size_t pos);
|
||||
|
||||
/**
|
||||
* Destruct the File manager.
|
||||
*/
|
||||
~File();
|
||||
};
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "image.hpp"
|
||||
|
||||
#ifndef STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
#endif
|
||||
|
||||
#ifndef STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include <stb_image_resize.h>
|
||||
#endif
|
||||
|
||||
#ifndef STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
#endif
|
||||
|
||||
void imageCopy(
|
||||
uint8_t *source, int32_t sourceWidth, int32_t sourceHeight,
|
||||
uint8_t *dest, int32_t destWidth, int32_t destHeight,
|
||||
int32_t cropX, int32_t cropY, int32_t cropWidth, int32_t cropHeight,
|
||||
int32_t pasteX, int32_t pasteY,
|
||||
int32_t channels
|
||||
) {
|
||||
int32_t x, y, c;
|
||||
int32_t absX, absY;
|
||||
int32_t sourceIndex, targetIndex;
|
||||
|
||||
if(cropX == -1) cropX = 0;
|
||||
if(cropY == -1) cropY = 0;
|
||||
if(cropWidth == -1) cropWidth = sourceWidth;
|
||||
if(cropHeight == -1) cropHeight = sourceHeight;
|
||||
if(pasteX == -1) pasteX = 0;
|
||||
if(pasteY == -1) pasteY = 0;
|
||||
|
||||
for(x = cropX; x < cropX + cropWidth; x++) {
|
||||
for(y = cropY; y < cropY + cropHeight; y++) {
|
||||
absX = x - cropX + pasteX;
|
||||
absY = y - cropY + pasteY;
|
||||
if(absX >= destWidth || absY >= destHeight || absX < 0 || absY < 0)continue;
|
||||
targetIndex = absY * destWidth + absX;
|
||||
sourceIndex = y * sourceWidth + x;
|
||||
for(c = 0; c < channels; c++) {
|
||||
dest[(targetIndex*channels) + c] = source[(sourceIndex*channels) + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dawnsharedlibs.hpp"
|
||||
#include "file.hpp"
|
||||
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_resize.h>
|
||||
#include <stb_image_write.h>
|
||||
|
||||
/**
|
||||
* Unused currently.
|
||||
*
|
||||
* @param source
|
||||
* @param sourceWidth
|
||||
* @param sourceHeight
|
||||
* @param dest
|
||||
* @param destWidth
|
||||
* @param destHeight
|
||||
* @param cropX
|
||||
* @param cropY
|
||||
* @param cropWidth
|
||||
* @param cropHeight
|
||||
* @param pasteX
|
||||
* @param pasteY
|
||||
* @param channels
|
||||
*/
|
||||
void imageCopy(
|
||||
uint8_t *source, int32_t sourceWidth, int32_t sourceHeight,
|
||||
uint8_t *dest, int32_t destWidth, int32_t destHeight,
|
||||
int32_t cropX, int32_t cropY, int32_t cropWidth, int32_t cropHeight,
|
||||
int32_t pasteX, int32_t pasteY,
|
||||
int32_t channels
|
||||
);
|
@@ -1,231 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "xml.hpp"
|
||||
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i) {
|
||||
char c;
|
||||
int32_t level = 0;
|
||||
uint8_t doing = XML_DOING_NOTHING;
|
||||
uint8_t doingBeforeComment;
|
||||
bool insideTag = false;
|
||||
char* buffer = (char *)malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
int32_t bufferLength = 0;
|
||||
|
||||
xml->value = NULL;
|
||||
xml->attributeCount = 0;
|
||||
|
||||
xml->children = (xml_t *)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(data[i] == '!' && data[i+1] == '-' && data[i+2] == '-') {
|
||||
doingBeforeComment = doing;
|
||||
doing = XML_PARSING_COMMENT;
|
||||
i += 3;
|
||||
} else 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 = (char *)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 = (char *)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 = (char *)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 = (char *)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;
|
||||
}
|
||||
|
||||
if(data[i] == '!' && data[i+1] == '-' && data[i+2] == '-') {
|
||||
doingBeforeComment = doing;
|
||||
doing = XML_PARSING_COMMENT;
|
||||
i += 3;
|
||||
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;
|
||||
|
||||
case XML_PARSING_COMMENT:
|
||||
if(c != '-') continue;
|
||||
if(data[i] != '-') continue;
|
||||
if(data[i+1] != '>') continue;
|
||||
i += 2;
|
||||
doing = doingBeforeComment;
|
||||
break;
|
||||
|
||||
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';
|
||||
}
|
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dawnsharedlibs.hpp"
|
||||
#include "file.hpp"
|
||||
|
||||
#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_PARSING_COMMENT 0x09
|
||||
|
||||
#define XML_TEXT_BUFFER_MAX 2048
|
||||
#define XML_CHILD_COUNT_MAX 128
|
||||
#define XML_ATTRIBUTE_MAX 128
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Find an attribute index by its name.
|
||||
*
|
||||
* @param xml Xml node to get the attribute from.
|
||||
* @param name The name of the attribute you're trying to find.
|
||||
* @return -1 if not found, otherwise the index of the attribute within array.
|
||||
*/
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name);
|
||||
|
||||
/**
|
||||
* Checks if a given character is a whitespace character or not.
|
||||
*
|
||||
* @param c Character to check if a whitespace.
|
||||
* @return True if whitespace, otherwise false.
|
||||
*/
|
||||
bool xmlIsWhitespace(char c);
|
Reference in New Issue
Block a user