Copyright 2009, Ifcaro & volca
Licenced under Academic Free License version 3.0
Review OpenUsbLd README & LICENSE files for further details.
*/
#include "include/opl.h"
#include "include/util.h"
#include "include/ioman.h"
#include "include/sound.h"
#include <string.h>
#define NEWLIB_PORT_AWARE
#include <fileXio_rpc.h>
int configGetStat(config_set_t *configSet, iox_stat_t *stat);
static u32 currentUID = 0;
static config_set_t configFiles[CONFIG_INDEX_COUNT];
static char legacyNetConfigPath[256] = "mc?:SYS-CONF/IPCONFIG.DAT";
static const char *configFilenames[CONFIG_INDEX_COUNT] = {
"conf_opl.cfg",
"conf_last.cfg",
"conf_apps.cfg",
"conf_network.cfg",
"conf_game.cfg",
};
static int strToColor(const char *string, unsigned char *color)
{
int cnt = 0, n = 0;
color[0] = 0;
color[1] = 0;
color[2] = 0;
if (!string || !*string)
return 0;
if (string[0] != '#')
return 0;
string++;
while (*string) {
int fh = fromHex(*string);
if (fh >= 0) {
color[n] = color[n] * 16 + fh;
} else {
break;
}
if (cnt == 1) {
cnt = 0;
n++;
} else {
cnt++;
}
string++;
}
return 1;
}
int isWS(char c)
{
return c == ' ' || c == '\t';
}
static int splitAssignment(char *line, char *key, size_t keymax, char *val, size_t valmax)
{
for (; isWS(*line); ++line)
;
char *eqpos = strchr(line, '=');
if (eqpos) {
size_t keylen = min(keymax, eqpos - line);
strncpy(key, line, keylen);
eqpos++;
size_t vallen = min(valmax, strlen(line) - (eqpos - line));
strncpy(val, eqpos, vallen);
}
return (int)eqpos;
}
static int parsePrefix(char *line, char *prefix)
{
char *colpos = strchr(line, ':');
if (colpos && colpos != line) {
strncpy(prefix, line, colpos - line);
prefix[colpos - line] = 0;
return 1;
} else {
return 0;
}
}
static int configKeyValidate(const char *key)
{
if (strlen(key) == 0)
return 0;
return !strchr(key, '=');
}
static struct config_value_t *allocConfigItem(const char *key, const char *val)
{
struct config_value_t *it = (struct config_value_t *)malloc(sizeof(struct config_value_t));
strncpy(it->key, key, sizeof(it->key));
it->key[sizeof(it->key) - 1] = '\0';
strncpy(it->val, val, sizeof(it->val));
it->val[sizeof(it->val) - 1] = '\0';
it->next = NULL;
return it;
}
static void addConfigValue(config_set_t *configSet, const char *key, const char *val)
{
if (!configSet->tail) {
configSet->head = allocConfigItem(key, val);
configSet->tail = configSet->head;
} else {
configSet->tail->next = allocConfigItem(key, val);
configSet->tail = configSet->tail->next;
}
}
static struct config_value_t *getConfigItemForName(config_set_t *configSet, const char *name)
{
struct config_value_t *val = configSet->head;
while (val) {
if (strncmp(val->key, name, sizeof(val->key)) == 0)
break;
val = val->next;
}
return val;
}
static char cfgDevice[8];
char *configGetDir(void)
{
if (!strncmp(cfgDevice, "mc", 2)) {
cfgDevice[2] = getmcID();
}
char *path = cfgDevice;
return path;
}
void configPrepareNotifications(char *prefix)
{
char *colpos;
snprintf(cfgDevice, sizeof(cfgDevice), prefix);
if ((colpos = strchr(cfgDevice, ':')) != NULL)
*(colpos + 1) = '\0';
}
void configInit(char *prefix)
{
char path[256];
int i;
if (prefix)
snprintf(legacyNetConfigPath, sizeof(legacyNetConfigPath), "%s/IPCONFIG.DAT", prefix);
else
prefix = gBaseMCDir;
for (i = 0; i < CONFIG_INDEX_COUNT; i++) {
snprintf(path, sizeof(path), "%s/%s", prefix, configFilenames[i]);
configAlloc(1 << i, &configFiles[i], path);
}
configPrepareNotifications(prefix);
}
void configSetMove(char *prefix)
{
char path[256];
int i;
if (prefix)
snprintf(legacyNetConfigPath, sizeof(legacyNetConfigPath), "%s/IPCONFIG.DAT", prefix);
else
prefix = gBaseMCDir;
for (i = 0; i < CONFIG_INDEX_COUNT; i++) {
snprintf(path, sizeof(path), "%s/%s", prefix, configFilenames[i]);
configMove(&configFiles[i], path);
}
configPrepareNotifications(prefix);
}
void configEnd()
{
int index = 0;
while (index < CONFIG_INDEX_COUNT) {
config_set_t *configSet = &configFiles[index];
configClear(configSet);
free(configSet->filename);
configSet->filename = NULL;
index++;
}
}
config_set_t *configAlloc(int type, config_set_t *configSet, char *fileName)
{
if (!configSet)
configSet = (config_set_t *)malloc(sizeof(config_set_t));
configSet->uid = ++currentUID;
configSet->type = type;
configSet->head = NULL;
configSet->tail = NULL;
if (fileName) {
int length = strlen(fileName) + 1;
configSet->filename = (char *)malloc(length * sizeof(char));
memcpy(configSet->filename, fileName, length);
} else
configSet->filename = NULL;
configSet->modified = 0;
return configSet;
}
void configMove(config_set_t *configSet, const char *fileName)
{
int length = strlen(fileName) + 1;
configSet->filename = realloc(configSet->filename, length);
memcpy(configSet->filename, fileName, length);
}
void configFree(config_set_t *configSet)
{
configClear(configSet);
free(configSet->filename);
free(configSet);
}
config_set_t *configGetByType(int type)
{
int index = 0;
while (index < CONFIG_INDEX_COUNT) {
config_set_t *configSet = &configFiles[index];
if (configSet->type == type)
return configSet;
index++;
}
return NULL;
}
int configSetStr(config_set_t *configSet, const char *key, const char *value)
{
if (!configKeyValidate(key))
return 0;
struct config_value_t *it = getConfigItemForName(configSet, key);
if (it) {
if (strncmp(it->val, value, sizeof(it->val)) != 0) {
strncpy(it->val, value, sizeof(it->val));
it->val[sizeof(it->val) - 1] = '\0';
if (it->key[0] != '#')
configSet->modified = 1;
}
} else {
addConfigValue(configSet, key, value);
if (key[0] != '#')
configSet->modified = 1;
}
return 1;
}
int configGetStr(config_set_t *configSet, const char *key, const char **value)
{
if (!configKeyValidate(key))
return 0;
struct config_value_t *it = getConfigItemForName(configSet, key);
if (it) {
*value = it->val;
return 1;
} else
return 0;
}
int configGetStrCopy(config_set_t *configSet, const char *key, char *value, int length)
{
const char *valref = NULL;
if (configGetStr(configSet, key, &valref)) {
strncpy(value, valref, length);
value[length - 1] = '\0';
return 1;
} else {
value[0] = '\0';
return 0;
}
}
int configSetInt(config_set_t *configSet, const char *key, const int value)
{
char tmp[12];
snprintf(tmp, sizeof(tmp), "%d", value);
return configSetStr(configSet, key, tmp);
}
int configGetInt(config_set_t *configSet, const char *key, int *value)
{
const char *valref = NULL;
if (configGetStr(configSet, key, &valref)) {
*value = atoi(valref);
return 1;
} else {
return 0;
}
}
int configSetColor(config_set_t *configSet, const char *key, unsigned char *color)
{
char tmp[8];
snprintf(tmp, sizeof(tmp), "#%02X%02X%02X", color[0], color[1], color[2]);
return configSetStr(configSet, key, tmp);
}
int configGetColor(config_set_t *configSet, const char *key, unsigned char *color)
{
const char *valref = NULL;
if (configGetStr(configSet, key, &valref)) {
strToColor(valref, color);
return 1;
} else {
return 0;
}
}
int configRemoveKey(config_set_t *configSet, const char *key)
{
if (!configKeyValidate(key))
return 0;
struct config_value_t *val = configSet->head;
struct config_value_t *prev = NULL;
while (val) {
if (strncmp(val->key, key, sizeof(val->key)) == 0) {
if (key[0] != '#')
configSet->modified = 1;
if (val == configSet->tail)
configSet->tail = prev;
val = val->next;
if (prev) {
free(prev->next);
prev->next = val;
} else {
free(configSet->head);
configSet->head = val;
}
} else {
prev = val;
val = val->next;
}
}
return 1;
}
void configMerge(config_set_t *dest, const config_set_t *source)
{
struct config_value_t *val;
for (val = source->head; val != NULL; val = val->next) {
configSetStr(dest, val->key, val->val);
}
}
static int configReadLegacyIP(void)
{
config_set_t *configSet;
char temp[16];
int fd = openFile(legacyNetConfigPath, O_RDONLY);
if (fd >= 0) {
char ipconfig[256];
int size = getFileSize(fd);
read(fd, &ipconfig, size);
close(fd);
sscanf(ipconfig, "%d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d", &ps2_ip[0], &ps2_ip[1], &ps2_ip[2], &ps2_ip[3],
&ps2_netmask[0], &ps2_netmask[1], &ps2_netmask[2], &ps2_netmask[3],
&ps2_gateway[0], &ps2_gateway[1], &ps2_gateway[2], &ps2_gateway[3]);
configSet = &configFiles[CONFIG_INDEX_NETWORK];
snprintf(temp, sizeof(temp), "%d.%d.%d.%d", ps2_ip[0], ps2_ip[1], ps2_ip[2], ps2_ip[3]);
configSetStr(configSet, CONFIG_NET_PS2_IP, temp);
snprintf(temp, sizeof(temp), "%d.%d.%d.%d", ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3]);
configSetStr(configSet, CONFIG_NET_PS2_NETM, temp);
snprintf(temp, sizeof(temp), "%d.%d.%d.%d", ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
configSetStr(configSet, CONFIG_NET_PS2_GATEW, temp);
configSetStr(configSet, CONFIG_NET_PS2_DNS, temp);
return 1;
}
return 0;
}
void configGetDiscIDBinary(config_set_t *configSet, void *dst)
{
memset(dst, 0, 5);
const char *gid = NULL;
if (configGetStr(configSet, CONFIG_ITEM_DNAS, &gid)) {
char *cdst = dst;
int p = 0;
while (*gid && p < 10) {
int dv = -1;
while (dv < 0 && *gid)
dv = fromHex(*(gid++));
if (dv < 0)
break;
*cdst = *cdst * 16 + dv;
if ((++p & 1) == 0)
cdst++;
}
}
}
static int configReadFileBuffer(file_buffer_t *fileBuffer, config_set_t *configSet)
{
char *line;
unsigned int lineno = 0;
char prefix[CONFIG_KEY_NAME_LEN];
memset(prefix, 0, sizeof(prefix));
while (readFileBuffer(fileBuffer, &line)) {
lineno++;
char key[CONFIG_KEY_NAME_LEN], val[CONFIG_KEY_VALUE_LEN];
memset(key, 0, sizeof(key));
memset(val, 0, sizeof(val));
if (splitAssignment(line, key, sizeof(key), val, sizeof(val))) {
* the prefix ends and we have to reset it
*/
if (!isWS(line[0]))
memset(prefix, 0, sizeof(prefix));
if (prefix[0]) {
char composedKey[CONFIG_KEY_NAME_LEN];
snprintf(composedKey, sizeof(composedKey), "%s_%s", prefix, key);
configSetStr(configSet, composedKey, val);
} else {
configSetStr(configSet, key, val);
}
} else if (parsePrefix(line, prefix)) {
} else {
LOG("CONFIG Malformed file '%s' line %d: '%s'\n", configSet->filename, lineno, line);
}
}
configSet->modified = 0;
return 1;
}
int configReadBuffer(config_set_t *configSet, const void *buffer, int size)
{
int ret;
file_buffer_t *fileBuffer = openFileBufferBuffer(0, buffer, size);
if (!fileBuffer) {
configSet->modified = 0;
return 0;
}
ret = configReadFileBuffer(fileBuffer, configSet);
closeFileBuffer(fileBuffer);
return ret;
}
int configRead(config_set_t *configSet)
{
int ret;
file_buffer_t *fileBuffer = openFileBuffer(configSet->filename, O_RDONLY, 0, 4096);
if (!fileBuffer) {
LOG("CONFIG No file %s.\n", configSet->filename);
configSet->modified = 0;
return 0;
}
ret = configReadFileBuffer(fileBuffer, configSet);
closeFileBuffer(fileBuffer);
return ret;
}
int configWrite(config_set_t *configSet)
{
if (configSet->modified) {
file_buffer_t *fileBuffer = openFileBuffer(configSet->filename, O_WRONLY | O_CREAT | O_TRUNC, 0, 4096);
if (fileBuffer) {
char line[512];
bgmMute();
struct config_value_t *cur = configSet->head;
while (cur) {
if ((cur->key[0] != '\0') && (cur->key[0] != '#')) {
snprintf(line, sizeof(line), "%s=%s\r\n", cur->key, cur->val);
writeFileBuffer(fileBuffer, line, strlen(line));
}
cur = cur->next;
}
closeFileBuffer(fileBuffer);
configSet->modified = 0;
bgmUnMute();
return 1;
}
return 0;
}
return 1;
}
int configGetStat(config_set_t *configSet, iox_stat_t *stat)
{
return (fileXioGetStat(configSet->filename, stat) >= 0 ? 1 : 0);
}
void configClear(config_set_t *configSet)
{
while (configSet->head) {
struct config_value_t *cur = configSet->head;
configSet->head = cur->next;
free(cur);
}
configSet->head = NULL;
configSet->tail = NULL;
configSet->modified = 1;
}
int configReadMulti(int types)
{
int result = 0, index;
for (index = 0; index < CONFIG_INDEX_COUNT; index++) {
config_set_t *configSet = &configFiles[index];
if (configSet->type & types) {
configClear(configSet);
if (configRead(configSet))
result |= configSet->type;
}
}
if ((types & CONFIG_NETWORK) && !(result & CONFIG_NETWORK))
if (configReadLegacyIP())
result |= CONFIG_NETWORK;
return result;
}
int configWriteMulti(int types)
{
int result = 0, index;
for (index = 0; index < CONFIG_INDEX_COUNT; index++) {
config_set_t *configSet = &configFiles[index];
if (configSet->type & types)
result += configWrite(configSet);
}
return result;
}
void configGetVMC(config_set_t *configSet, char *vmc, int length, int slot)
{
char gkey[CONFIG_KEY_NAME_LEN];
snprintf(gkey, sizeof(gkey), "%s_%d", CONFIG_ITEM_VMC, slot);
configGetStrCopy(configSet, gkey, vmc, length);
}
void configSetVMC(config_set_t *configSet, const char *vmc, int slot)
{
char gkey[CONFIG_KEY_NAME_LEN];
if (vmc[0] == '\0') {
configRemoveVMC(configSet, slot);
return;
}
snprintf(gkey, sizeof(gkey), "%s_%d", CONFIG_ITEM_VMC, slot);
configSetStr(configSet, gkey, vmc);
}
void configRemoveVMC(config_set_t *configSet, int slot)
{
char gkey[CONFIG_KEY_NAME_LEN];
snprintf(gkey, sizeof(gkey), "%s_%d", CONFIG_ITEM_VMC, slot);
configRemoveKey(configSet, gkey);
}