joeydev/src/utils.c
2023-01-24 20:08:34 -06:00

466 lines
10 KiB
C

/*
* JoeyDev
* Copyright (C) 2018-2023 Scott Duensing <scott@kangaroopunch.com>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <sys/stat.h>
#include "utils.h"
#ifdef _WIN32
#define ourMkdir(p,m) mkdir(p)
#else
#define ourMkdir mkdir
#endif
typedef struct WindowListS {
GtkWidget *key;
WindowDataT *value;
} WindowListT;
static WindowListT *_windowList = NULL;
char *utilCreateString(char *format, ...) {
va_list args;
char *string;
va_start(args, format);
string = utilCreateStringVArgs(format, args);
va_end(args);
return string;
}
__attribute__((__format__(__printf__, 1, 0)))
char *utilCreateStringVArgs(char *format, va_list args) {
va_list argsCopy;
int32_t size = 0;
char *buffer = NULL;
va_copy(argsCopy, args);
size = vsnprintf(NULL, 0, format, argsCopy) + 1;
va_end(argsCopy);
buffer = calloc(1, (size_t)size);
if (buffer) {
vsnprintf(buffer, (size_t)size, format, args);
}
return buffer;
}
char *utilDeobfuscateASCII(char *obfuscated) {
char *deobfuscated = NULL;
char *hostname;
int i;
int j;
int c;
// Valid ASCII 32 - 126 (94 chars)
hostname = strdup(g_get_host_name());
// Decrypt.
j = 0;
deobfuscated = (char *)malloc((strlen(obfuscated) + 1) * sizeof(char));
for (i=0; i<strlen(obfuscated); i++) {
c = obfuscated[i] - hostname[j] - 32;
while (c < 0) c += 94;
deobfuscated[i] = c + 32;
j++;
if (j >= strlen(hostname)) j = 0;
}
deobfuscated[i] = 0;
return deobfuscated;
}
void utilDequote(char *string) {
int x;
if (string[0] == '"' || string[strlen(string) - 1] == '"') {
string[strlen(string) - 1] = 0;
for (x=1; x<strlen(string) + 1; x++) {
string[x - 1] = string[x];
}
}
}
void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted) {
unsigned char *temp = NULL;
if (*length < wanted) {
*length = *length + 1024;
temp = realloc(*buffer, *length);
if (temp == NULL) {
//***TODO*** Something bad happened.
} else {
*buffer = temp;
}
}
}
gboolean utilFileExists(char *filename) {
FILE *f = fopen(filename, "rb");
if (f) {
fclose(f);
return TRUE;
}
return FALSE;
}
gboolean utilFileOpen(WindowDataT *self, char *extension, char *what) {
GtkWidget *dialog;
GtkFileFilter *filter;
char *title = utilCreateString("Open %s", what);
char *warning = utilCreateString("You have unsaved changes. Open different %s?", what);
char *files = utilCreateString("%s Files", what);
gboolean result = TRUE;
if (self->isDirty) {
if (!utilQuestionDialog(self->window, title, warning)) {
result = FALSE;
}
}
if (result == TRUE) {
dialog = gtk_file_chooser_dialog_new(title,
GTK_WINDOW(self->window),
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Cancel", GTK_RESPONSE_CANCEL,
"_Open", GTK_RESPONSE_ACCEPT,
NULL
);
filter = gtk_file_filter_new();
gtk_file_filter_set_name(filter, files);
gtk_file_filter_add_pattern(filter, extension);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
utilSetDirty((WindowDataT *)self, FALSE);
DEL(self->filename);
self->filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
} else {
result = FALSE;
}
gtk_widget_destroy(dialog);
}
DEL(files);
DEL(warning);
DEL(title);
return result;
}
gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what) {
GtkWidget *dialog;
GtkFileFilter *filter;
gboolean result = FALSE;
char *files = utilCreateString("%s Files", what);
dialog = gtk_file_chooser_dialog_new("Save As",
GTK_WINDOW(self->window),
GTK_FILE_CHOOSER_ACTION_SAVE,
"_Cancel", GTK_RESPONSE_CANCEL,
"_Save", GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
filter = gtk_file_filter_new();
gtk_file_filter_set_name(filter, files);
gtk_file_filter_add_pattern(filter, extension);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
DEL(self->filename);
self->filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
utilSetDirty(self, TRUE);
result = TRUE;
}
DEL(files);
gtk_widget_destroy(dialog);
return result;
}
// https://stackoverflow.com/questions/26187037/in-c-split-char-on-spaces-with-strtok-function-except-if-between-quotes
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock) {
static char *token = NULL;
char *lead = NULL;
char *block = NULL;
int iBlock = 0;
int iBlockIndex = 0;
if (input != NULL) {
token = input;
lead = input;
} else {
lead = token;
if (*token == 0) lead = NULL;
}
while (*token != 0) {
if (iBlock) {
if (closeblock[iBlockIndex] == *token) {
iBlock = 0;
}
token++;
continue;
}
if ((block = strchr(openblock, *token)) != NULL) {
iBlock = 1;
iBlockIndex = block - openblock;
token++;
continue;
}
if (strchr(delimit, *token) != NULL) {
*token = 0;
token++;
break;
}
token++;
}
return lead;
}
WindowDataT *utilGetWindowData(GtkWidget *window) {
return hmget(_windowList, window);
}
gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widgets[], gpointer userData) {
GtkBuilder *gtkBuilder;
int x;
gtkBuilder = gtk_builder_new();
if (gtk_builder_add_from_resource(gtkBuilder, resource, NULL) == 0) {
printf("Failed to build UI '%s'!\n", name[0]);
exit(1);
}
x = 0;
while (name[x] != NULL) {
*widgets[x] = GTK_WIDGET(gtk_builder_get_object(gtkBuilder, name[x]));
x++;
}
gtk_builder_connect_signals(gtkBuilder, userData);
g_object_unref(G_OBJECT(gtkBuilder));
return TRUE;
}
gboolean utilMkDirP(const char *dir, const mode_t mode) {
char tmp[UTIL_PATH_MAX];
char *p = NULL;
struct stat sb;
size_t len;
// Make copy of dir.
len = strnlen(dir, UTIL_PATH_MAX);
if (len == 0 || len == UTIL_PATH_MAX) {
return -1;
}
memcpy(tmp, dir, len);
tmp[len] = '\0';
// Remove trailing slash.
if (tmp[len - 1] == UTIL_PATH_CHAR) {
tmp[len - 1] = '\0';
}
// Does it already exist?
if (stat(tmp, &sb) == 0) {
if (S_ISDIR(sb.st_mode)) {
return TRUE;
}
}
// Recursive mkdir.
for (p = tmp + 1; *p; p++) {
if (*p == UTIL_PATH_CHAR) {
*p = 0;
if (stat(tmp, &sb) != 0) {
// Does not exist - create it.
if (ourMkdir(tmp, mode) < 0) {
return FALSE;
}
} else {
if (!S_ISDIR(sb.st_mode)) {
// Not a directory
return FALSE;
}
}
*p = UTIL_PATH_CHAR;
}
}
// Check path
if (stat(tmp, &sb) != 0) {
// Does not exist - create it.
if (ourMkdir(tmp, mode) < 0) {
return FALSE;
}
} else {
if (!S_ISDIR(sb.st_mode)) {
// Not a directory
return FALSE;
}
}
return TRUE;
}
char *utilObfuscateASCII(char *clearText) {
char *obfuscated = NULL;
char *hostname;
int i;
int j;
int c;
// Valid ASCII 32 - 126 (94 chars)
hostname = strdup(g_get_host_name());
// Obfuscate.
j = 0;
obfuscated = (char *)malloc((strlen(clearText) + 1) * sizeof(char));
for (i=0; i<strlen(clearText); i++) {
c = clearText[i] + hostname[j] - 32;
while (c > 94) c -= 94;
obfuscated[i] = c + 32;
j++;
if (j >= strlen(hostname)) j = 0;
}
obfuscated[i] = 0;
return obfuscated;
}
gboolean utilQuestionDialog(GtkWidget *parent, char *title, char *question) {
GtkWidget *dialog;
int response;
dialog = gtk_message_dialog_new(
GTK_WINDOW(parent),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_OK_CANCEL,
"%s", question);
gtk_window_set_title(GTK_WINDOW(dialog), title);
response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return (response == GTK_RESPONSE_OK) ? TRUE : FALSE;
}
void utilSetDirty(WindowDataT *self, gboolean dirty) {
char *title;
self->isDirty = dirty;
if (dirty) {
if (self->filename) {
title = utilCreateString("%s - %s *", self->title, self->filename);
} else {
title = utilCreateString("%s - (no name) *", self->title);
}
} else {
if (self->filename) {
title = utilCreateString("%s - %s", self->title, self->filename);
} else {
title = utilCreateString("%s", self->title);
}
}
gtk_window_set_title(GTK_WINDOW(self->window), title);
DEL(title);
}
void utilWindowRegister(gpointer windowData) {
WindowDataT *w = (WindowDataT *)windowData;
// Grab title.
w->title = strdup(gtk_window_get_title(GTK_WINDOW(w->window)));
hmput(_windowList, w->window, windowData);
}
int utilWindowsCloseAll(void) {
WindowDataT *w;
while (hmlen(_windowList) > 0) {
w = (WindowDataT *)_windowList[0].value;
if (w->closeWindow(w->window, w) == TRUE) {
// User canceled closing.
break;
}
// Mark it clean and close it ourselves.
w->isDirty = FALSE;
gtk_window_close(GTK_WINDOW(w->window));
// Unregister it.
utilWindowUnRegister(w);
}
return utilWindowsOpen();
}
int utilWindowsOpen(void) {
return hmlen(_windowList);
}
gboolean utilWindowUnRegister(gpointer windowData) {
int result;
WindowDataT *w = (WindowDataT *)windowData;
result = hmdel(_windowList, w->window);
DEL(w->filename);
DEL(w->title);
return (result == 1) ? TRUE : FALSE;
}