Added config parser. Changed language file format.

This commit is contained in:
TheFloW 2016-08-26 23:57:51 +02:00
parent 608102ad51
commit b20212177d
7 changed files with 343 additions and 137 deletions

View File

@ -1,13 +1,13 @@
TITLE_ID = VITASHELL
TARGET = VitaShell
OBJS = main.o init.o io_process.o package_installer.o archive.o photo.o file.o text.o hex.o \
uncommon_dialog.o message_dialog.o ime_dialog.o language.o utils.o sha1.o \
uncommon_dialog.o message_dialog.o ime_dialog.o config.o language.o utils.o sha1.o \
audioplayer.o minizip/unzip.o minizip/ioapi.o
RESOURCES_PNG = resources/ftp.png resources/battery.png resources/battery_bar_green.png resources/battery_bar_red.png \
resources/headphone.png resources/audio_previous.png resources/audio_pause.png resources/audio_play.png \
resources/audio_next.png
RESOURCES_TXT = resources/english_us_translation.txt
RESOURCES_TXT = resources/english_us.txt
OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o)
LIBS = -lftpvita -lvita2d -lpng -ljpeg -lz -lm -lc \

225
config.c Normal file
View File

@ -0,0 +1,225 @@
/*
VitaShell
Copyright (C) 2015-2016, TheFloW
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 <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#include "config.h"
void trim(char *str) {
int len = strlen(str);
int i;
for (i = len - 1; i >= 0; i--) {
if (str[i] == 0x20 || str[i] == '\t') {
str[i] = 0;
} else {
break;
}
}
}
int GetLine(char *buf, int size, char *str) {
uint8_t ch = 0;
int n = 0;
int i = 0;
uint8_t *s = (uint8_t *)str;
while (1) {
if (i >= size)
break;
ch = ((uint8_t *)buf)[i];
if (ch < 0x20 && ch != '\t') {
if (n != 0) {
i++;
break;
}
} else {
*str++ = ch;
n++;
}
i++;
}
trim((char *)s);
return i;
}
int getDecimal(char *str) {
return strtol(str, NULL, 0);
}
int getHexdecimal(char *str) {
return strtoul(str, NULL, 16);
}
int getBoolean(char *str) {
if (strcasecmp(str, "false") == 0 || strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0)
return 0;
if (strcasecmp(str, "true") == 0 || strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0)
return 1;
return -1;
}
char *getString(char *str) {
if (str[0] != '"')
return NULL;
char *p = strchr(str + 1, '"');
if (!p)
return NULL;
int len = p - (str + 1);
char *out = malloc(len + 1);
strncpy(out, str + 1, len);
out[len] = '\0';
int i;
for (i = 0; i < strlen(out); i++) {
if (out[i] == '\\')
out[i] = '\n';
}
return out;
}
int readEntry(char *line, ConfigEntry *entries, int n_entries) {
// Trim at beginning
while (*line == ' ' || *line == '\t')
line++;
// Ignore comments #1
if (line[0] == '#') {
// debugPrintf("IGNORE %s\n", line);
return 0;
}
// Ignore comments #2
char *p = strchr(line, '#');
if (p) {
// debugPrintf("IGNORE %s\n", p);
*p = '\0';
}
// Get token
p = strchr(line, '=');
if (!p)
return -1;
// Name of entry
char name[MAX_NAME_LENGTH];
strncpy(name, line, p - line);
name[p - line] = '\0';
trim(name);
// debugPrintf("NAME: %s\n", name);
// String of entry
char *string = p + 1;
// Trim at beginning
while (*string == ' ' || *string == '\t')
string++;
// Trim at end
trim(string);
// debugPrintf("STRING: %s\n", string);
int i;
for (i = 0; i < n_entries; i++) {
if (strcasecmp(name, entries[i].name) == 0) {
switch (entries[i].type) {
case CONFIG_TYPE_DECIMAL:
*(uint32_t *)entries[i].value = getDecimal(string);
// debugPrintf("VALUE DECIMAL: %d\n", *(uint32_t *)entries[i].value);
break;
case CONFIG_TYPE_HEXDECIMAL:
*(uint32_t *)entries[i].value = getHexdecimal(string);
// debugPrintf("VALUE HEXDECIMAL: 0x%X\n", *(uint32_t *)entries[i].value);
break;
case CONFIG_TYPE_BOOLEAN:
*(uint32_t *)entries[i].value = getBoolean(string);
// debugPrintf("VALUE BOOLEAN: %d\n", *(uint32_t *)entries[i].value);
break;
case CONFIG_TYPE_STRING:
*(uint32_t *)entries[i].value = (uint32_t)getString(string);
// debugPrintf("VALUE STRING: %s\n", *(uint32_t *)entries[i].value);
break;
}
break;
}
}
return 1;
}
int readConfigBuffer(void *buffer, int size, ConfigEntry *entries, int n_entries) {
int res = 0;
char line[MAX_LINE_LENGTH];
char *p = buffer;
// Skip UTF-8 bom
uint32_t bom = 0xBFBBEF;
if (memcmp(p, &bom, 3) == 0) {
p += 3;
size -= 3;
}
do {
memset(line, 0, sizeof(line));
res = GetLine(p, size, line);
if (res > 0) {
readEntry(line, entries, n_entries);
size -= res;
p += res;
}
} while (res > 0);
return 0;
}
int readConfig(char *path, ConfigEntry *entries, int n_entries) {
SceUID fd = sceIoOpen(path, SCE_O_RDONLY, 0);
if (fd < 0)
return fd;
int size = sceIoLseek32(fd, 0, SCE_SEEK_END);
sceIoLseek32(fd, 0, SCE_SEEK_SET);
void *buffer = malloc(size);
sceIoRead(fd, buffer, size);
sceIoClose(fd);
readConfigBuffer(buffer, size, entries, n_entries);
free(buffer);
return 0;
}

42
config.h Normal file
View File

@ -0,0 +1,42 @@
/*
VitaShell
Copyright (C) 2015-2016, TheFloW
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 <http://www.gnu.org/licenses/>.
*/
#ifndef __CONFIG_H__
#define __CONFIG_H__
#define MAX_NAME_LENGTH 128
#define MAX_STRING_LENGTH 512
#define MAX_LINE_LENGTH 1024
enum ConfigTypes {
CONFIG_TYPE_DECIMAL,
CONFIG_TYPE_HEXDECIMAL,
CONFIG_TYPE_BOOLEAN,
CONFIG_TYPE_STRING,
};
typedef struct {
char *name;
int type;
void *value;
} ConfigEntry;
int readConfigBuffer(void *buffer, int size, ConfigEntry *entries, int n_entries);
int readConfig(char *path, ConfigEntry *entries, int n_entries);
#endif

View File

@ -17,10 +17,11 @@
*/
#include "main.h"
#include "config.h"
#include "language.h"
extern unsigned char _binary_resources_english_us_translation_txt_start;
extern unsigned char _binary_resources_english_us_translation_txt_size;
extern unsigned char _binary_resources_english_us_txt_start;
extern unsigned char _binary_resources_english_us_txt_size;
static char *lang[] ={
"japanese",
@ -46,49 +47,6 @@ static char *lang[] ={
char *language_container[LANGUAGE_CONTRAINER_SIZE];
void trim(char *str) {
int len = strlen(str);
int i;
for (i = len - 1; i >= 0; i--) {
if (str[i] == 0x20 || str[i] == '\t') {
str[i] = 0;
} else {
break;
}
}
}
int GetLine(char *buf, int size, char *str) {
unsigned char ch = 0;
int n = 0;
int i = 0;
unsigned char *s = (unsigned char *)str;
while (1) {
if (i >= size)
break;
ch = ((unsigned char *)buf)[i];
if (ch < 0x20 && ch != '\t') {
if (n != 0) {
i++;
break;
}
} else {
*str++ = ch;
n++;
}
i++;
}
trim((char *)s);
return i;
}
void freeLanguageContainer() {
int i;
for (i = 0; i < LANGUAGE_CONTRAINER_SIZE; i++) {
@ -99,57 +57,50 @@ void freeLanguageContainer() {
}
}
int loadLanguageContainer(void *buffer, int size) {
int res;
int i = 0;
char *p = buffer;
char line[512];
freeLanguageContainer();
do {
memset(line, 0, sizeof(line));
if ((res = GetLine(p, size, line)) > 0) {
int j;
for (j = 0; j < strlen(line); j++) {
if (line[j] == '\\')
line[j] = '\n';
}
language_container[i] = malloc(strlen(line) + 1);
strcpy(language_container[i], line);
i++;
}
size -= res;
p += res;
} while (res > 0 && i < LANGUAGE_CONTRAINER_SIZE);
return i == LANGUAGE_CONTRAINER_SIZE;
}
void loadLanguage(int id) {
int loaded = 0;
freeLanguageContainer();
#define LANGUAGE_ENTRY(name) { #name, CONFIG_TYPE_STRING, &language_container[name] }
ConfigEntry language_entries[] = {
LANGUAGE_ENTRY(ERROR),
LANGUAGE_ENTRY(OK),
LANGUAGE_ENTRY(YES),
LANGUAGE_ENTRY(NO),
LANGUAGE_ENTRY(CANCEL),
LANGUAGE_ENTRY(OFFSET),
LANGUAGE_ENTRY(MARK_ALL),
LANGUAGE_ENTRY(UNMARK_ALL),
LANGUAGE_ENTRY(MOVE),
LANGUAGE_ENTRY(COPY),
LANGUAGE_ENTRY(PASTE),
LANGUAGE_ENTRY(DELETE),
LANGUAGE_ENTRY(RENAME),
LANGUAGE_ENTRY(NEW_FOLDER),
LANGUAGE_ENTRY(FOLDER),
LANGUAGE_ENTRY(COPIED_FILE),
LANGUAGE_ENTRY(COPIED_FOLDER),
LANGUAGE_ENTRY(COPIED_FILES_FOLDERS),
LANGUAGE_ENTRY(MOVING),
LANGUAGE_ENTRY(COPYING),
LANGUAGE_ENTRY(DELETING),
LANGUAGE_ENTRY(INSTALLING),
LANGUAGE_ENTRY(DELETE_FILE_QUESTION),
LANGUAGE_ENTRY(DELETE_FOLDER_QUESTION),
LANGUAGE_ENTRY(DELETE_FILES_FOLDERS_QUESTION),
LANGUAGE_ENTRY(INSTALL_QUESTION),
LANGUAGE_ENTRY(WIFI_ERROR),
LANGUAGE_ENTRY(FTP_SERVER),
};
int loaded = -1;
if (id >= 0 && id < (sizeof(lang) / sizeof(char *))) {
char path[128];
sprintf(path, "cache0:VitaShell/%s_translation.txt", lang[id]);
SceUID fd = sceIoOpen(path, SCE_O_RDONLY, 0);
if (fd >= 0) {
int size = sceIoLseek(fd, 0, SCE_SEEK_END);
sceIoLseek(fd, 0, SCE_SEEK_SET);
void *buffer = malloc(size);
sceIoRead(fd, buffer, size);
loaded = loadLanguageContainer(buffer, size);
free(buffer);
}
sprintf(path, "ux0:VitaShell/language/%s.txt", lang[id]);
loaded = readConfig(path, language_entries, sizeof(language_entries) / sizeof(ConfigEntry));
}
if (!loaded)
loadLanguageContainer(&_binary_resources_english_us_translation_txt_start, (int)&_binary_resources_english_us_translation_txt_size);
}
if (loaded < 0)
readConfigBuffer(&_binary_resources_english_us_txt_start, (int)&_binary_resources_english_us_txt_size, language_entries, sizeof(language_entries) / sizeof(ConfigEntry));
}

View File

@ -24,20 +24,6 @@ static int message_dialog_type = -1;
static char message_string[1024];
void ansi_to_utf8(uint8_t *src, uint8_t *dst) {
int i;
for (i = 0; src[i]; i++) {
if (src[i] < 0x80) {
*(dst++) = src[i];
} else {
*(dst++) = 0xC0 | (src[i] & 0xC0) >> 6;
*(dst++) = 0x80 | (src[i] & 0x3F);
}
}
*dst = '\0';
}
int initMessageDialog(int type, char *msg, ...) {
if (message_dialog_running)
return -1;
@ -49,7 +35,7 @@ int initMessageDialog(int type, char *msg, ...) {
vsprintf(string, msg, list);
va_end(list);
ansi_to_utf8((uint8_t *)string, (uint8_t *)message_string);
strcpy(message_string, string);
SceMsgDialogParam param;
sceMsgDialogParamInit(&param);

30
resources/english_us.txt Normal file
View File

@ -0,0 +1,30 @@
# VitaShell language config file
ERROR = "Error 0x%08X."
OK = "OK"
YES = "Yes"
NO = "No"
CANCEL = "Cancel"
OFFSET = "Offset"
MARK_ALL = "Mark all"
UNMARK_ALL = "Unmark all"
MOVE = "Move"
COPY = "Copy"
PASTE = "Paste"
DELETE = "Delete"
RENAME = "Rename"
NEW_FOLDER = "New folder"
FOLDER = "Folder"
COPIED_FILE = "Copied %d file."
COPIED_FOLDER = "Copied %d folder."
COPIED_FILES_FOLDERS = "Copied %d files/folders."
MOVING = "Moving..."
COPYING = "Copying..."
DELETING = "Deleting..."
INSTALLING = "Installing..."
DELETE_FILE_QUESTION = "Are you sure you want to delete this file?"
DELETE_FOLDER_QUESTION = "Are you sure you want to delete this folder?"
DELETE_FILES_FOLDERS_QUESTION = "Are you sure you want to delete these files/folders?"
INSTALL_QUESTION = "Do you want to install this package?"
WIFI_ERROR = "You must use Wi-Fi to do this."
FTP_SERVER = "FTP server is now running at\ftp://%s:%i\\Press 'OK' to keep it in background.\Press 'Cancel' to disconnect."

View File

@ -1,28 +0,0 @@
Error 0x%08X.
OK
Yes
No
Cancel
Offset
Mark all
Unmark all
Move
Copy
Paste
Delete
Rename
New folder
Folder
Copied %d file.
Copied %d folder.
Copied %d files/folders.
Moving...
Copying...
Deleting...
Installing...
Are you sure you want to delete this file?
Are you sure you want to delete this folder?
Are you sure you want to delete these files/folders?
Do you want to install this package?
You must use Wi-Fi to do this.
FTP server is now running at\ftp://%s:%i\\Press 'OK' to keep it in background.\Press 'Cancel' to disconnect.