Cache now using SQL to store the directory. Images are pre-decompressed before use.
This commit is contained in:
parent
9f32ea202a
commit
ebea70dd0b
19 changed files with 430 additions and 243 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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/
|
||||
|
||||
|
|
|
@ -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}])
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -20,153 +20,54 @@
|
|||
|
||||
#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) {
|
||||
// Found! Delete data from disk.
|
||||
entryDir = cacheEntryNameDirGet(name, 1);
|
||||
unlink(entryDir);
|
||||
// Attempt to remove the second-level directory.
|
||||
dir2 = osLastPathComponentGetUpTo(entryDir);
|
||||
if (rmdir(dir2) == 0) {
|
||||
// Attempt to move the top level directory.
|
||||
dir1 = osLastPathComponentGetUpTo(dir2);
|
||||
rmdir(dir1);
|
||||
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;
|
||||
entryDir = cacheFilenameGet(virtualPath);
|
||||
if (entryDir) {
|
||||
// Found! Delete data from disk.
|
||||
unlink(entryDir);
|
||||
// Attempt to remove the second-level directory.
|
||||
dir2 = osLastPathComponentGetUpTo(entryDir);
|
||||
if (rmdir(dir2) == 0) {
|
||||
// Attempt to move the top level directory.
|
||||
dir1 = osLastPathComponentGetUpTo(dir2);
|
||||
rmdir(dir1);
|
||||
DEL(dir1);
|
||||
}
|
||||
DEL(dir2);
|
||||
}
|
||||
|
||||
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;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
153
client/src/system/db.c
Normal 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
37
client/src/system/db.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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++;
|
||||
|
|
Loading…
Add table
Reference in a new issue