cake
/
libg1m
Archived
1
0
Fork 0
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
libg1m/src/parse/lang.c

256 lines
7.4 KiB
C

/* ************************************************************************** */
/* _____ _ */
/* parse/lang.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/12/01 13:33:45 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* fx language files parsing */
/* ************************************************************************** */
/**
* g1m_parse_lang:
* Parse fx language files.
*
* @arg handle the libg1m handle.
* @arg stream the stream to parse from.
* @return the error code (0 if ok).
*/
int g1m_parse_lang(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
(void)std;
/* set handle type */
handle->messages = NULL;
/* read the subheader */
DREAD(hd, g1l_subheader)
/* correct the endianness */
uint_fast16_t num = be16toh(hd.message_count) + 1;
/* log */
log_info("%" PRIuFAST16 " messages to read", num);
/* beat the best, read the rest! */
size_t data_size = std->filesize - sizeof(struct standard_header)
- sizeof(struct g1l_subheader);
uint8_t data[data_size];
READ(data, data_size)
/* allocate tab */
handle->messages = malloc(sizeof(char*) * num);
handle->count = 0;
handle->_size = num;
if (!handle->messages)
return (g1m_error_alloc);
/* get the offset table */
uint16_t *offsets = (uint16_t*)data;
char *messages = (char*)(offsets + num);
/* read messages */
for (uint_fast16_t i = 0; i < num; i++) {
handle->messages[i] = NULL;
if (offsets[i] == (uint16_t)-1) {
log_info("[#%" PRIuFAST16 "] -", i);
handle->count++;
continue ;
}
/* correct offset */
offsets[i] = be16toh(offsets[i]);
/* log */
log_info("[#%" PRIuFAST16 "] '%s' (0x%" PRIu16 ")", i,
&messages[offsets[i]], offsets[i]);
/* store */
handle->messages[i] = strdup(&messages[offsets[i]]);
if (!handle->messages[i]) goto fail;
handle->count++;
}
/* no error */
return (0);
/* omg fail! */
fail:
for (int i = 0; i < handle->count; i++)
free(handle->messages[i]);
free(handle->messages);
handle->messages = NULL;
return (g1m_error_alloc);
}
/* ************************************************************************** */
/* cg language files parsing */
/* ************************************************************************** */
/**
* g1m_parse_lang_cg_content:
* Parse the content of the message zone size for a G3L language file.
*
* @arg handle the libg1m handle.
* @arg stream the stream to read from.
* @arg zonesize the message zone size.
* @arg pchecksum pointer to the checksum to contribute to.
* @return the error code (0 if ok).
*/
static int g1m_parse_lang_cg_content(g1m_t *handle, FILE *stream,
uint_fast32_t zonesize, uint32_t *pchecksum)
{
int err; uint32_t checksum = *pchecksum;
/* correct the handle type */
handle->type = g1m_type_lang;
/* read the subheader */
DREAD(lhd, g3l_lang_header)
checksum = g1m_checksum32(&lhd, sizeof(struct g3l_lang_header), checksum);
/* get the messages table */
uint_fast32_t num = be32toh(lhd.num) + 1;
uint32_t off[num + 1]; off[num] = zonesize;
READ(off, num * sizeof(uint32_t))
checksum = g1m_checksum32(off, num * sizeof(uint32_t), checksum);
/* prepare for next */
uint32_t *offsets = &off[1]; num--;
log_info("%" PRIuFAST32 " messages to read", num);
/* get index of first message */
uint_fast32_t i;
for (i = 0; i < num && offsets[i] == (uint32_t)-1; i++)
handle->messages[i] = NULL;
offsets[i] = be32toh(offsets[i]);
/* get and copy the language name */
off[0] = be32toh(off[0]);
if (off[0] == (uint32_t)-1) {
log_fatal("First offset shouldn't be blank!");
return (g1m_error_magic);
}
size_t langname_size = offsets[i] - off[0];
uint8_t langname[langname_size];
READ(langname, langname_size)
handle->title[16] = 0;
strncpy(handle->title, (char*)langname, 16);
log_info("Language name is '%s'", handle->title);
/* prepare the handle messages table */
handle->messages = malloc(sizeof(char*) * num);
if (!handle->messages) return (g1m_error_alloc);
handle->count = 0;
handle->_size = num;
/* main loop */
uint_fast32_t next;
for (; i < num; i = next) {
/* find and correct next offset */
for (next = i + 1; offsets[next] == (uint32_t)-1; next++)
handle->messages[next] = NULL;
offsets[next] = be32toh(offsets[next]);
/* read the message */
size_t msg_size = offsets[next] - offsets[i];
uint8_t msg[msg_size];
GREAD(msg, msg_size)
checksum = g1m_checksum32(msg, msg_size, checksum);
/* copy it */
handle->messages[i] = malloc(msg_size + 1);
if (!handle->messages[i]) goto fail;
handle->messages[i][msg_size] = 0;
strncpy(handle->messages[i], (char*)msg, msg_size);
handle->count += (next - i);
/* log it */
log_info("[#%04" PRIuFAST32 "] '%s'", i, handle->messages[i]);
}
/* done */
*pchecksum = checksum;
return (0);
fail:
g1m_free_content(handle);
return (err);
}
/**
* g1m_parse_lang_cg:
* Parse fx-CG language files.
*
* @arg handle the libg1m handle.
* @arg stream the stream to parse from.
* @arg std the standard header.
* @return the error code (0 if ok).
*/
int g1m_parse_lang_cg(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
/* set handle type */
handle->messages = NULL;
/* read the subheader */
DREAD(hd, g3l_subheader)
/* correct the endianness */
hd.checksum = be32toh(hd.checksum);
hd.message_zone_size = be32toh(hd.message_zone_size);
/* log */
log_info("internal name is '%.8s'", hd.internal_name);
log_info("language name is '%.16s'", hd.language_name);
log_info("language salutation is '%.16s'", hd.language_salutation);
log_info("version is '%.10s'", hd.version);
log_info("datetime is '%.14s'", hd.datetime);
log_info("g3l filename is '%.16s'", hd.g3l_filename);
/* precalculate the checksum beginning */
uint32_t checksum =
sizeof(struct standard_header) * 255
- g1m_checksum32(std, sizeof(struct standard_header), 0) +
g1m_checksum32(&hd.magic, sizeof(struct g3l_subheader) - 4, 0);
/* read and decode the message zone */
int err = 0;
size_t zonesize = hd.filesize - sizeof(struct standard_header)
- sizeof(struct g3l_subheader) - sizeof(struct g3l_footer);
if (hd.magic[0] == 0x04)
err = g1m_parse_lang_cg_content(handle, stream, zonesize, &checksum);
else return (g1m_error_magic);
if (err) return (g1m_error_magic);
/* check the checksum */
if (hd.checksum && hd.checksum != checksum) {
log_fatal("header checksum was invalid");
goto fail;
}
/* read the footer */
GDREAD(footer, g3l_footer)
footer.checksum = be32toh(footer.checksum);
if (footer.checksum != hd.checksum) {
log_fatal("footer checksum was invalid!");
log_info("header checksum is %" PRIu32 ","
" calculated checksum is %" PRIu32,
hd.checksum, checksum);
goto fail;
}
/* no error */
return (0);
/* omg fail! */
fail:
g1m_free_content(handle);
return (g1m_error_alloc);
}