Cache now using SQL to store the directory. Images are pre-decompressed before use.

This commit is contained in:
Scott Duensing 2022-03-18 19:57:33 -05:00
parent 9f32ea202a
commit ebea70dd0b
19 changed files with 430 additions and 243 deletions

1
.gitignore vendored
View file

@ -11,6 +11,7 @@ retired/
test/
doors/
client/src/thirdparty/sqlite-3.4.2/build
client/src/thirdparty/sqlite-3.4.2/build-linux
*/out/

View file

@ -33,13 +33,11 @@ BINDIR = bin
# CFLAGS, LDFLAGS, CPPFLAGS, PREFIX can be overriden on CLI
CFLAGS := $(DEBUG)
#CFLAGS += -DALLEGRONOTAVAIL -DALLEGRONOTPROGS -DDZCOMM_SRC
CFLAGS += -I$(SRCDIR)/client/src -I$(SRCDIR)/client/src/system -I$(SRCDIR)/client/src/dos -I$(SRCDIR)/client/src/gui -I$(SRCDIR)/client/src/thirdparty
CFLAGS += -I$(SRCDIR)/client/src/thirdparty/sqlite-3.4.2/build -I$(SRCDIR)/shared -I$(SRCDIR)/shared/thirdparty
#CFLAGS += -I$(SRCDIR)/client/src/thirdparty/dzcomm -I$(SRCDIR)/client/src/thirdparty/dzcomm/include
CPPFLAGS :=
LDFLAGS := -L$(SRCDIR)/client/src/thirdparty/sqlite-3.4.2/build/.libs -lsqlite3
#LDFLAGS += -L$(SRCDIR)/client/src/thirdparty/dzcomm -ldzcom
LDFLAGS := -L$(SRCDIR)/client/src/thirdparty/sqlite-3.4.2/build/.libs
LDLIBS := -lsqlite3
PREFIX := /usr/local
TARGET_ARCH :=
@ -54,7 +52,7 @@ ALL_CPPFLAGS := $(CPPFLAGS)
# Linker Flags
ALL_LDFLAGS := $(LDFLAGS)
ALL_LDLIBS := -lc
ALL_LDLIBS := $(LDLIBS) -lc
# Source, Binaries, Dependencies
@ -64,8 +62,6 @@ DEP := $(OBJ:.o=.d)
BIN := $(BINDIR)/$(TARGET)
-include $(DEP)
#obj/client/src/thirdparty/dzcomm/src/dos/djirqs.o
#$(info [${SRC}])
#$(info [${OBJ}])

View file

@ -85,7 +85,7 @@ PATH=/opt/cross/djgpp/bin:$PATH
#createEmbeddedBinary vga8x14 dat ../../client/src/embedded
#popd
# Build SQLite
# Build SQLite for DOS
pushd client/src/thirdparty/sqlite-3.4.2
[[ -d build ]] && rm -rf build
mkdir -p build
@ -97,3 +97,13 @@ sh ../configure \
--host=i586-pc-msdosdjgpp
make
popd
# Build SQLite for Linux
pushd client/src/thirdparty/sqlite-3.4.2
[[ -d build-linux ]] && rm -rf build
mkdir -p build-linux
cd build-linux
sh ../configure \
--disable-tcl
make
popd

View file

@ -30,11 +30,9 @@ QMAKE_CFLAGS += -O0
DEFINES *= CLIENT
UNUSED_CRAP = \
src/thirdparty/dzcomm/include/dzcomm.h
DOS_HEADERS = \
src/thirdparty/serial/serial.h
src/thirdparty/serial/serial.h \
src/thirdparty/sqlite-3.4.2/build/sqlite.h
DOS_SOURCES = \
src/thirdparty/serial/serial.c \
@ -43,10 +41,12 @@ DOS_SOURCES = \
src/dos/vesa.c
LINUX_INCLUDES = \
$$PWD/src/linux
src/linux \
src/thirdparty/sqlite-3.4.2/build-linux
LINUX_HEADERS = \
$$SHARED/thirdparty/enet/include/enet.h
$$SHARED/thirdparty/enet/include/enet.h \
src/thirdparty/sqlite-3.4.2/build-linux/sqlite.h
LINUX_SOURCES = \
src/linux/linux.c
@ -54,9 +54,9 @@ LINUX_SOURCES = \
INCLUDEPATH += \
$$LINUX_INCLUDES \
$$SHARED \
$$PWD/src/system \
$$PWD/src/gui \
$$PWD/src
src/system \
src/gui \
src
HEADERS = \
$$LINUX_HEADERS \
@ -82,6 +82,7 @@ HEADERS = \
src/runtime.h \
src/signup.h \
src/system/cache.h \
src/system/db.h \
src/thirdparty/SHA256/sha256.h \
src/thirdparty/minicoro/minicoro.h \
src/system/comport.h \
@ -133,6 +134,7 @@ SOURCES = \
src/hangup.c \
src/system/cache.c \
src/system/comport.c \
src/system/db.c \
src/system/os.c \
src/system/surface.c \
src/system/network.c \
@ -166,6 +168,8 @@ SOURCES = \
src/settings.c
LIBS = \
-L$$PWD/src/thirdparty/sqlite-3.4.2/build-linux/.libs \
-lsqlite3 \
-lSDL2 \
-lSDL2_image

View file

@ -27,6 +27,7 @@
#include "label.h"
#include "timer.h"
#include "msgbox.h"
#include "image.h"
#include "file.h"
#include "hangup.h"
@ -232,6 +233,7 @@ static void packetHandler(PacketDecodeDataT *packet) {
_handle = NULL;
// Update cache entry to include SHA.
cacheEntryAdd(_currentSha256, cacheEntryNameGet(_file), _file);
imageCacheIfNeeded(_file, _currentSha256); // If this was an image, decompress it now.
DEL(_currentSha256);
// Next file!
fileCheckNext();

View file

@ -18,6 +18,8 @@
*/
#include "ctype.h"
#define STB_IMAGE_IMPLEMENTATION
#define STBI_ONLY_PNG
#include "image.h"
@ -26,6 +28,9 @@
#include "vesa.h"
#define PIXEL_COMPONENTS 3
static ImageT *imageNativeImageGet(unsigned char *raw, uint32_t x, uint32_t y);
@ -64,6 +69,59 @@ ImageT *imageAllocate(uint16_t w, uint16_t h) {
}
void imageCacheIfNeeded(char *cacheFilename, char *sha256) {
int16_t len;
char ext[4];
uint32_t x = 0;
uint32_t y = 0;
uint32_t n = 0;
unsigned char *raw = NULL;
char *temp = NULL;
char *rawSha = NULL;
FILE *f = NULL;
// This function expects a cache filename, not a real filesystem filename!
len = strlen(cacheFilename);
// Is this something we care about?
if (len > 4) {
if (cacheFilename[len - 4] == '.') {
ext[0] = toupper(cacheFilename[len - 3]);
ext[1] = toupper(cacheFilename[len - 2]);
ext[2] = toupper(cacheFilename[len - 1]);
ext[3] = 0;
if ((strcmp(ext, "PNG") == 0) || (strcmp(ext, "GIF") == 0) || (strcmp(ext, "JPG") == 0)) {
// It's an image we care about. Is it decompressed already?
temp = (char *)malloc(strlen(cacheFilename) + 5);
if (!temp) return;
sprintf(temp, "%s.raw", cacheFilename);
rawSha = cacheSha256Get(temp);
if (!rawSha || strcmp(rawSha, sha256) != 0) {
// The decompressed file either does not exist or the SHA does not match the file we're checking.
logWrite("Unpacking %s - %s\n", cacheFilenameGet(cacheFilename), cacheFilename);
raw = stbi_load(cacheFilenameGet(cacheFilename), (int *)&x, (int *)&y, (int *)&n, PIXEL_COMPONENTS);
if (!raw) return;
// Write unpacked version to disk.
f = cacheFOpen(temp, "wb");
if (f) {
fwrite(&x, sizeof(uint32_t), 1, f);
fwrite(&y, sizeof(uint32_t), 1, f);
fwrite(raw, x * y * PIXEL_COMPONENTS, 1, f);
cacheFClose(f);
}
free(raw);
// Update SHA on unpacked image.
cacheEntryAdd(sha256, cacheEntryNameGet(temp), temp);
logWrite("Created %s - %s\n", cacheFilenameGet(temp), temp);
}
free(temp);
}
}
}
}
ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color) {
uint16_t x;
uint16_t y;
@ -88,7 +146,7 @@ ImageT *imageFromRAMLoad(uint8_t *buffer, size_t len) {
unsigned char *raw;
// Load image from RAM.
raw = stbi_load_from_memory((const unsigned char *)buffer, len, (int *)&x, (int *)&y, (int *)&n, 3);
raw = stbi_load_from_memory((const unsigned char *)buffer, len, (int *)&x, (int *)&y, (int *)&n, PIXEL_COMPONENTS);
if (!raw) return NULL;
return imageNativeImageGet(raw, x, y);
@ -117,20 +175,83 @@ uint8_t imageInfoGet(char *filename, uint16_t *width, uint16_t *height) {
}
ImageT *imageLoad(char *filename) {
uint32_t x;
uint32_t y;
uint32_t n;
unsigned char *raw;
uint8_t imageInfoGetCache(char *virtualPath, uint16_t *width, uint16_t *height) {
int w; // Using boring old compiler 'int' on purpose.
int h;
int n;
int r;
char *file;
// Load image from disk
raw = stbi_load(filename, (int *)&x, (int *)&y, (int *)&n, 3);
file = cacheFilenameGet(virtualPath);
if (file) {
r = stbi_info(file, &w, &h, &n);
if (r) {
*width = w;
*height = h;
return SUCCESS;
}
}
return FAIL;
}
ImageT *imageLoad(char *filename) {
uint32_t x = 0;;
uint32_t y = 0;
uint32_t n = 0;
unsigned char *raw = NULL;
// Load compressed image from disk
raw = stbi_load(filename, (int *)&x, (int *)&y, (int *)&n, PIXEL_COMPONENTS);
if (!raw) return NULL;
return imageNativeImageGet(raw, x, y);
}
ImageT *imageLoadCache(char *virtualPath) {
uint32_t x = 0;;
uint32_t y = 0;
uint32_t n = 0;
unsigned char *raw = NULL;
char *temp = NULL;
char *file = NULL;
FILE *f = NULL;
// Get name of uncompressed version.
temp = (char *)malloc(strlen(virtualPath) + 5);
if (!temp) return NULL;
sprintf(temp, "%s.raw", virtualPath);
file = cacheFilenameGet(temp);
if (file && osFileExists(file)) {
// Read unpacked version from disk.
logWrite("Loaded %s\n", file);
f = fopen(file, "rb");
if (f) {
fread(&x, sizeof(uint32_t), 1, f);
fread(&y, sizeof(uint32_t), 1, f);
raw = (unsigned char *)malloc(x * y * PIXEL_COMPONENTS);
if (raw) {
fread(raw, x * y * PIXEL_COMPONENTS, 1, f);
}
fclose(f);
}
} else {
// Load compressed image from disk
file = cacheFilenameGet(virtualPath);
logWrite("Loaded %s\n", file);
raw = stbi_load(file, (int *)&x, (int *)&y, (int *)&n, PIXEL_COMPONENTS);
if (!raw) return NULL;
}
free(temp);
return imageNativeImageGet(raw, x, y);
}
static ImageT *imageNativeImageGet(unsigned char *raw, uint32_t x, uint32_t y) {
uint32_t b;
ImageT *image;
@ -147,7 +268,7 @@ static ImageT *imageNativeImageGet(unsigned char *raw, uint32_t x, uint32_t y) {
for (y=0; y<image->height; y++) {
for (x=0; x<image->width; x++) {
image->pixels[x][y] = vbeColorMake(raw[b], raw[b + 1], raw[b + 2]);
b += 3;
b += PIXEL_COMPONENTS;
}
}

View file

@ -36,11 +36,14 @@ typedef struct ImageS {
ImageT *imageAllocate(uint16_t w, uint16_t h);
void imageCacheIfNeeded(char *cacheFilename, char *sha256);
ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color);
ImageT *imageFromRAMLoad(uint8_t *buffer, size_t len);
uint16_t imageHeightGet(ImageT *image);
uint8_t imageInfoGet(char *filename, uint16_t *width, uint16_t *height);
uint8_t imageInfoGetCache(char *virtualPath, uint16_t *width, uint16_t *height);
ImageT *imageLoad(char *filename);
ImageT *imageLoadCache(char *virtualPath);
ColorT imagePixelGet(ImageT *image, uint16_t x, uint16_t y);
void imageRender(ImageT *image, uint16_t x, uint16_t y);
void imageRenderHalf(ImageT *image, uint16_t x, uint16_t y);

View file

@ -377,7 +377,7 @@ void listboxStepSet(ListboxT *listbox, int32_t step) {
void listboxTitleSet(ListboxT *listbox, char *title) {
if (listbox->title) free(listbox->title);
listbox->title = strdup(title);
if (title) listbox->title = strdup(title);
listboxSizesRecalculate(listbox);
GUI_SET_FLAG((WidgetT *)listbox, WIDGET_FLAG_DIRTY);
}

View file

@ -184,7 +184,7 @@ void msgBoxThree(char *title, MsgBoxIconT icon, char *message, char *buttonOne,
// Load proper icon, if desired.
if (icon > MSGBOX_ICON_NONE && icon < MSGBOX_ICON_COUNT) {
context->picIcon = pictureNew(x, y, cacheFilenameGet(_iconFiles[icon - 1]));
context->picIcon = pictureNew(x, y, _iconFiles[icon - 1]);
guiAttach(W(context->winDialog), W(context->picIcon));
}

View file

@ -49,7 +49,7 @@ WidgetT *pictureInit(WidgetT *widget, char *filename) {
l->clicked = NULL;
l->zoom = PICTURE_FULL;
l->image = imageLoad(l->filename);
l->image = imageLoadCache(l->filename);
if (!l->image) {
free(l->filename);
return NULL;
@ -81,7 +81,7 @@ PictureT *pictureNew(uint16_t x, uint16_t y, char *filename) {
if (!picture) return NULL;
if (!imageInfoGet(filename, &w, &h)) {
if (!imageInfoGetCache(filename, &w, &h)) {
free(picture);
return NULL;
}

View file

@ -22,6 +22,7 @@
#include "gui.h"
#include "widget.h"
#include "cache.h"
#include "button.h"
#include "checkbox.h"
@ -84,6 +85,7 @@ static void tagListWidgetAttributeHandle(void) {
WidgetT *parent;
char *title;
char *filename;
char *cachename;
RectT pos;
uint8_t hasWidth;
uint8_t hasHeight;
@ -119,6 +121,7 @@ static void tagListWidgetAttributeHandle(void) {
// Reset all attributes for this widget.
title = NULL;
filename = NULL;
cachename = NULL;
pos.x = 0;
pos.y = 0;
pos.w = 0;
@ -157,6 +160,10 @@ static void tagListWidgetAttributeHandle(void) {
switch (t) {
case T_CACHENAME:
cachename = (char *)v;
break;
case T_COLOR_ACTIVE:
colorActive = (ColorT)v;
hasColorActive = 1;
@ -320,7 +327,7 @@ static void tagListWidgetAttributeHandle(void) {
break;
case T_PICTURE:
widget = W(pictureNew(pos.x, pos.y, filename));
widget = W(pictureNew(pos.x, pos.y, cachename));
pictureZoomSet((PictureT *)widget, zoom);
if (click != NULL) pictureClickHandlerSet((PictureT *)widget, click);
break;

View file

@ -61,7 +61,8 @@ enum TagItemsE {
T_META_END_OF_WIDGETS,
T_META_START_OF_ATTRIBUTES,
T_CLICK, // 17
T_CACHENAME, // 17
T_CLICK,
T_COLOR_ACTIVE,
T_COLOR_BACKGROUND,
T_COLOR_FOREGROUND,

View file

@ -48,6 +48,7 @@
#include "comport.h"
#include "network.h"
#include "timer.h"
#include "db.h"
#include "welcome.h"
#include "settings.h"
@ -131,6 +132,7 @@ static void shutdown(void) {
surfaceShutdown();
vbeShutdown();
cacheShutdown();
dbShutdown();
configShutdown();
osShutdown();
logClose();
@ -146,7 +148,6 @@ static void shutdown(void) {
putc(fgetc(in), stdout);
}
fclose(in);
free(in);
}
free(_logName);
_Exit(0);
@ -187,13 +188,14 @@ static uint8_t startup(int argc, char *argv[]) {
return 1;
}
dbStartup();
cacheStartup(argv[0]);
surfaceStartup();
mouseStartup();
guiStartup();
netStartup();
_pointer = imageLoad(cacheFilenameGet("gui:mouse.png"));
_pointer = imageLoadCache("gui:mouse.png");
_alpha = imagePixelGet(_pointer, 5, 0);
tableLoad();
@ -301,8 +303,8 @@ int main(int argc, char *argv[]) {
// Perform "first run" setup tasks or start the client?
if (hasValidSettings()) {
// We have what we need, start the client.
//welcomeShow();
browserShow();
welcomeShow();
//browserShow();
eventLoop();
} else {
// Run the setup.

View file

@ -93,32 +93,32 @@ static void menuFilesReady(void) {
uint16_t x = vbeDisplayWidthGet() - 49;
uint16_t y = vbeDisplayHeightGet() - 49;
_picLogoff = pictureNew(x, y, cacheFilenameGet("menu:48logoff.png"));
_picLogoff = pictureNew(x, y, "menu:48logoff.png");
pictureClickHandlerSet(_picLogoff, picLogoffClick);
guiAttach(guiRootGet(), W(_picLogoff));
x -= 49;
_picForums = pictureNew(x, y, cacheFilenameGet("menu:48forums.png"));
_picForums = pictureNew(x, y, "menu:48forums.png");
pictureClickHandlerSet(_picForums, picForumsClick);
guiAttach(guiRootGet(), W(_picForums));
x -= 49;
_picEmail = pictureNew(x, y, cacheFilenameGet("menu:48email.png"));
_picEmail = pictureNew(x, y, "menu:48email.png");
pictureClickHandlerSet(_picEmail, picEmailClick);
guiAttach(guiRootGet(), W(_picEmail));
x -= 49;
_picGames = pictureNew(x, y, cacheFilenameGet("menu:48games.png"));
_picGames = pictureNew(x, y, "menu:48games.png");
pictureClickHandlerSet(_picGames, picGamesClick);
guiAttach(guiRootGet(), W(_picGames));
x -= 49;
_picChat = pictureNew(x, y, cacheFilenameGet("menu:48chat.png"));
_picChat = pictureNew(x, y, "menu:48chat.png");
pictureClickHandlerSet(_picChat, picChatClick);
guiAttach(guiRootGet(), W(_picChat));
x -= 49;
_picProfile = pictureNew(x, y, cacheFilenameGet("menu:48profile.png"));
_picProfile = pictureNew(x, y, "menu:48profile.png");
pictureClickHandlerSet(_picProfile, picProfileClick);
guiAttach(guiRootGet(), W(_picProfile));
}

View file

@ -20,53 +20,26 @@
#include "thirdparty/SHA256/sha256.h"
#include "db.h"
#include "image.h"
#include "cache.h"
#define CACHE_FIELD_SHA256 0
#define CACHE_FIELD_ENTRYNAME 1
#define CACHE_FIELD_FILENAME 2
static char *cacheEntryNameDirGet(char *entryName, uint8_t includeCache);
static char *cacheEntryNameGenerate(void);
static char *cacheFieldGet(char *virtualPath, uint8_t field);
uint8_t cacheDelete(char *virtualPath) {
FILE *in = NULL;
FILE *out = NULL;
char index[16] = { 0 };
char indexNew[16] = { 0 };
char buffer[1024] = { 0 };
char *name = NULL;
char *path = NULL;
char *dir2 = NULL;
char *dir1 = NULL;
char *entryDir = NULL;
// Deletes entry from cache index AND the data from the cache.
sprintf(index, "CACHE%cINDEX.DAT", OS_PATH_SLASH);
sprintf(indexNew, "CACHE%cINDEX.NEW", OS_PATH_SLASH);
// Do we have an index yet?
if (osFileExists(index)) {
in = fopen(index, "rt");
if (in) {
out = fopen(indexNew, "wt");
if (out) {
while (fgets(buffer, 1024, in) != 0) {
name = strstr(buffer, " ");
*name = 0;
name++;
path = strstr(name, " ");
*path = 0;
path++;
path[strlen(path) - 1] = 0;
if (strcmp(virtualPath, path) == 0) {
entryDir = cacheFilenameGet(virtualPath);
if (entryDir) {
// Found! Delete data from disk.
entryDir = cacheEntryNameDirGet(name, 1);
unlink(entryDir);
// Attempt to remove the second-level directory.
dir2 = osLastPathComponentGetUpTo(entryDir);
@ -77,97 +50,25 @@ uint8_t cacheDelete(char *virtualPath) {
DEL(dir1);
}
DEL(dir2);
} else {
// Not what we're after, copy to new index.
fprintf(out, "%s %s %s\n", buffer, name, path);
}
}
} else {
fclose(in);
return FAIL;
}
fclose(in);
unlink(index);
rename(indexNew, index);
return SUCCESS;
}
}
return FAIL;
return SUCCESS;
}
uint8_t cacheEntryAdd(char *sha256, char *entryName, char *virtualPath) {
FILE *in = NULL;
FILE *out = NULL;
char index[16] = { 0 };
char indexNew[16] = { 0 };
char *name = NULL;
char *path = NULL;
char buffer[1024] = { 0 };
uint8_t found = 0;
// This adds or updates an entry to the index.
// It does not add data to the actual cache.
// Index format is: SHA256 ENTRYNAME VIRTUALPATH
dbExecute(
"REPLACE INTO cache (sha, entry, path) VALUES (?, ?, ?)",
"vvv",
sha256, entryName, virtualPath
);
sprintf(index, "CACHE%cINDEX.DAT", OS_PATH_SLASH);
sprintf(indexNew, "CACHE%cINDEX.NEW", OS_PATH_SLASH);
// Do we have an index yet?
if (!osFileExists(index)) {
// Nope. Just add this entry and be done.
out = fopen(index, "wt");
if (out) {
fprintf(out, "%s %s %s\n", sha256, entryName, virtualPath);
fclose(out);
return SUCCESS;
}
return FAIL;
}
// Read existing index, update the entry if it exists.
// If not, we'll add it at the end.
in = fopen(index, "rt");
if (in) {
out = fopen(indexNew, "wt");
if (out) {
while (fgets(buffer, 1024, in) != 0) {
name = strstr(buffer, " ");
*name = 0;
name++;
path = strstr(name, " ");
*path = 0;
path++;
path[strlen(path) - 1] = 0;
if (strcmp(virtualPath, path) == 0) {
// Update this entry.
fprintf(out, "%s %s %s\n", sha256, entryName, virtualPath);
found = 1;
} else {
// Not what we're after, copy to new index.
fprintf(out, "%s %s %s\n", buffer, name, path);
}
}
// Did we replace an entry?
if (!found) {
// Add new entry to end.
fprintf(out, "%s %s %s\n", sha256, entryName, virtualPath);
}
fclose(out);
} else {
fclose(in);
return FAIL;
}
fclose(in);
unlink(index);
rename(indexNew, index);
return SUCCESS;
}
return FAIL;
}
static char *cacheEntryNameDirGet(char *entryName, uint8_t includeCache) {
@ -218,16 +119,10 @@ static char *cacheEntryNameGenerate(void) {
char *cacheEntryNameGet(char *virtualPath) {
return cacheFieldGet(virtualPath, CACHE_FIELD_ENTRYNAME);
}
uint8_t cacheExists(void) {
char index[16] = { 0 };
sprintf(index, "CACHE%cINDEX.DAT", OS_PATH_SLASH);
return osFileExists(index);
char *temp = NULL;
dbQuerySingle('v', (void **)&temp, "SELECT entry FROM cache WHERE path = ?", "v", virtualPath);
if (DB_RESULT_EMPTY(temp)) temp = NULL;
return temp;
}
@ -237,60 +132,11 @@ void cacheFClose(FILE *handle) {
}
static char *cacheFieldGet(char *virtualPath, uint8_t field) {
FILE *in = NULL;
char index[16] = { 0 };
static char buffer[2048] = { 0 };
static char *name = NULL;
static char *path = NULL;
static char *result = NULL;
// Return SHA256 given virtual path or NULL if not found.
sprintf(index, "CACHE%cINDEX.DAT", OS_PATH_SLASH);
result = NULL;
// Do we have an index yet?
if (osFileExists(index)) {
in = fopen(index, "rt");
if (in) {
// Be sure the fread is the last conditional so it short-circuts properly.
while (result == NULL && (fgets(buffer, 2048, in) != 0)) {
name = strstr(buffer, " ");
*name = 0;
name++;
path = strstr(name, " ");
*path = 0;
path++;
path[strlen(path) - 1] = 0;
if (strcmp(virtualPath, path) == 0) {
// Found! Return requested data.
switch (field) {
case CACHE_FIELD_SHA256:
result = buffer;
break;
case CACHE_FIELD_ENTRYNAME:
result = name;
break;
case CACHE_FIELD_FILENAME:
result = cacheEntryNameDirGet(name, 1);
break;
}
}
}
fclose(in);
}
}
return result;
}
char *cacheFilenameGet(char *virtualPath) {
return cacheFieldGet(virtualPath, CACHE_FIELD_FILENAME);
char *temp = NULL;
dbQuerySingle('v', (void **)&temp, "SELECT entry FROM cache WHERE path = ?", "v", virtualPath);
if (DB_RESULT_EMPTY(temp)) return NULL;
return cacheEntryNameDirGet(temp, 1);
}
@ -448,6 +294,7 @@ uint8_t cachePreUnpack(char *name) {
fwrite(buffer, 1, i, out);
} while (length > 0);
fclose(out);
imageCacheIfNeeded(virtualPath, (char *)buffer);
} else {
result = FAIL;
}
@ -462,7 +309,10 @@ uint8_t cachePreUnpack(char *name) {
char *cacheSha256Get(char *virtualPath) {
return cacheFieldGet(virtualPath, CACHE_FIELD_SHA256);
char *temp = NULL;
dbQuerySingle('v', (void **)&temp, "SELECT sha FROM cache WHERE path = ?", "v", virtualPath);
if (DB_RESULT_EMPTY(temp)) temp = NULL;
return temp;
}
@ -474,8 +324,18 @@ void cacheShutdown(void) {
void cacheStartup(char *appName) {
char *temp = NULL;
// Do we need to create the cache database?
dbExecute(
"CREATE TABLE IF NOT EXISTS cache ("
"sha VARCHAR(65), "
"entry VARCHAR(13), "
"path VARCHAR(1024) PRIMARY KEY"
")",
NULL);
// Do we need to unpack the initial cache?
if (!cacheExists()) {
dbQuerySingle('v', (void **)&temp, "SELECT sha FROM cache LIMIT 1", NULL);
if (DB_RESULT_EMPTY(temp)) {
temp = utilAppNameWithNewExtensionGet(appName, "pre");
cachePreUnpack(temp);
DEL(temp);

153
client/src/system/db.c Normal file
View file

@ -0,0 +1,153 @@
/*
* Kangaroo Punch MultiPlayer Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "db.h"
#include "sqlite3.h"
static sqlite3 *_db = NULL;
static sqlite3_stmt *dbSqlBind(char *sql, char *format, va_list args);
static sqlite3_stmt *dbSqlBind(char *sql, char *format, va_list args) {
int32_t r;
int32_t index;
sqlite3_stmt *stmt;
char *buffer;
// Bind parameters.
r = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL);
if (r == SQLITE_OK) {
index = 1;
while (*format != 0) {
switch (*format) {
case 'd':
r = sqlite3_bind_double(stmt, index, va_arg(args, double));
break;
case 'i':
r = sqlite3_bind_int(stmt, index, va_arg(args, int));
break;
case 'v':
buffer = va_arg(args, char *);
r = sqlite3_bind_text(stmt, index, buffer, strlen(buffer), SQLITE_STATIC);
break;
default:
utilDie("db: Unknown format option '%c'.\n", *format);
break;
}
format++;
index++;
}
}
return stmt;
}
uint8_t dbExecute(char *sql, char *format, ...) {
char *error;
int32_t r;
va_list args;
sqlite3_stmt *stmt;
if (format == NULL) {
// No parameters, just run it.
r = sqlite3_exec(_db, sql, NULL, NULL, &error);
} else {
va_start(args, format);
stmt = dbSqlBind(sql, format, args);
va_end(args);
r = (sqlite3_step(stmt) == SQLITE_DONE ? SQLITE_OK : SQLITE_ERROR);
sqlite3_finalize(stmt);
}
return r == SQLITE_OK ? SUCCESS : FAIL;
}
uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...) {
va_list args;
sqlite3_stmt *stmt;
int32_t r;
static double d;
static int32_t i;
static char *v;
if (format == NULL) {
// No parameters, just run it.
r = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL);
} else {
va_start(args, format);
stmt = dbSqlBind(sql, format, args);
va_end(args);
r = SQLITE_OK;
}
if (r == SQLITE_OK) {
r = sqlite3_step(stmt);
if (r == SQLITE_ROW) {
switch (rformat) {
case 'd':
d = sqlite3_column_double(stmt, 0);
*result = &d;
break;
case 'i':
i = sqlite3_column_double(stmt, 0);
*result = &i;
break;
case 'v':
v = (char *)sqlite3_column_text(stmt, 0);
*result = v;
break;
default:
utilDie("db: Unknown format option '%c'.\n", rformat);
break;
}
}
}
return r == SQLITE_OK ? SUCCESS : FAIL;
}
void dbShutdown(void) {
sqlite3_close(_db);
_db = NULL;
}
void dbStartup(void) {
char temp[OS_PATH_MAX];
int32_t r;
osMkDirP("CACHE");
sprintf(temp, "CACHE%cCACHE.DB", OS_PATH_SLASH);
r = sqlite3_open(temp, &_db);
if (r) utilDie("Unable to open database: %s\n", sqlite3_errmsg(_db));
}

37
client/src/system/db.h Normal file
View file

@ -0,0 +1,37 @@
/*
* Kangaroo Punch MultiPlayer Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef DB_H
#define DB_H
#include "os.h"
#define DB_RESULT_EMPTY(r) (r == NULL || r[0] == 0)
uint8_t dbExecute(char *sql, char *format, ...);
uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...);
void dbShutdown(void);
void dbStartup(void);
#endif // DB_H

View file

@ -195,11 +195,6 @@ static void settingsFinished(WidgetT *widget) {
void welcomeShow(void) {
char *logo = strdup(cacheFilenameGet("welcome:logo.png"));
char *init = strdup(cacheFilenameGet("welcome:init.png"));
char *dial = strdup(cacheFilenameGet("welcome:dialing.png"));
char *conn = strdup(cacheFilenameGet("welcome:connect.png"));
// 450x128 logo
TagItemT uiWelcome[] = {
@ -209,22 +204,22 @@ void welcomeShow(void) {
T_WIDTH, 500, T_HEIGHT, 225,
T_PICTURE, O(_picLogo),
T_FILENAME, P(logo),
T_CACHENAME, P("welcome:logo.png"),
T_X, 18, T_Y, 18,
T_PICTURE, T_DONE,
T_PICTURE, O(_picInit),
T_FILENAME, P(init),
T_CACHENAME, P("welcome:init.png"),
T_X, 18, T_Y, 18,
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
T_PICTURE, O(_picDialing),
T_FILENAME, P(dial),
T_CACHENAME, P("welcome:dialing.png"),
T_X, 179, T_Y, 18,
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
T_PICTURE, O(_picConnect),
T_FILENAME, P(conn),
T_CACHENAME, P("welcome:connect.png"),
T_X, 339, T_Y, 18,
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
@ -256,11 +251,6 @@ void welcomeShow(void) {
};
tagListRun(uiWelcome);
DEL(conn);
DEL(dial);
DEL(init);
DEL(logo);
}

View file

@ -102,7 +102,7 @@ uint8_t *packetContentPack(uint16_t *length, char *format, ...) {
break;
default:
utilDie("restRequest: Unknown format option '%c'.\n", *format);
utilDie("packet: Unknown format option '%c'.\n", *format);
break;
}
format++;