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/eact.c

466 lines
12 KiB
C

/* ************************************************************************** */
/* _____ _ */
/* parse/eact.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/12/01 13:33:45 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* Content parsing */
/* ************************************************************************** */
/* line content parsing function prototype */
static int eact_parse_line(g1m_line_t *handle, uint8_t *buf, size_t size,
uint_fast8_t type);
/**
* eact_parse_content_eact:
* Parse an EACT in an EACT, from the subheader.
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg bufsize the buffer size.
* @return the error code (0 if ok).
*/
static int eact_parse_content_eact(g1m_line_t *handle, uint8_t *buf,
size_t bufsize)
{
int err;
/* initialize the handle */
handle->type = g1m_linetype_eact;
handle->count = 0;
handle->_size = 0;
handle->lines = NULL;
/* check if the buffer is non-empty */
if (!bufsize) {
log_info("Content was name-only.");
return (0);
}
/* get e-act subheader */
if (bufsize < sizeof(struct eact_eactheader)) return (g1m_error_eof);
struct eact_eactheader ehd;
memcpy(&ehd, buf, sizeof(struct eact_eactheader));
/* correct endianess */
ehd.line_count = be32toh(ehd.line_count);
/* get the line descriptors
* there is actually a "bonus" line descriptor at the end, but the
* fact that we're using offsets lets us unaware of it. */
if (bufsize < sizeof(struct eact_eactheader)
+ (ehd.line_count + 1) * sizeof(struct line_descriptor))
return (g1m_error_eof);
struct line_descriptor *lds = (void*)&buf[sizeof(struct eact_eactheader)];
/* prepare the handle */
handle->count = 0;
handle->_size = ehd.line_count;
handle->lines = malloc(sizeof(g1m_line_t*) * handle->_size);
if (!handle->lines) return (g1m_error_alloc);
bzero(handle->lines, sizeof(g1m_line_t*) * handle->_size);
/* browse the lines */
log_info("%" PRIu32 " lines to browse", ehd.line_count);
if (ehd.line_count)
lds[0].entry_offset = be32toh(lds[0].entry_offset << 8);
for (uint_fast32_t i = 0; i < ehd.line_count; i++) {
/* allocate line */
g1m_line_t *line = malloc(sizeof(g1m_line_t));
err = g1m_error_alloc;
if (!line) goto fail;
/* get line size
* for this, we'll calculate the distance to the next line offset.
* if there is no next line (last line), then the data left will be
* attributed to the line. */
size_t linesize;
if (i == ehd.line_count - 1)
linesize = bufsize - lds[i].entry_offset;
else {
/* correct endianess of the next element */
lds[i + 1].entry_offset = be32toh(lds[i + 1].entry_offset << 8);
/* then calculate */
linesize = lds[i + 1].entry_offset - lds[i].entry_offset;
}
/* store current info */
uint_fast8_t entry_type = lds[i].entry_type;
uint_fast32_t entry_offset = lds[i].entry_offset;
/* check if buffer is big enough */
err = g1m_error_eof;
if (entry_offset + linesize > bufsize)
goto loop_fail;
/* look for the line type */
err = eact_parse_line(line, &buf[entry_offset], linesize, entry_type);
if (err) goto loop_fail;
/* store and continue */
handle->lines[handle->count++] = line;
continue;
loop_fail:
g1m_free_line_content(line);
free(line);
goto fail;
}
/* no error */
return (0);
fail:
g1m_free_line_content(handle);
return (err);
}
/* ************************************************************************** */
/* Content Type correspondance list */
/* ************************************************************************** */
/* Correspondance type */
struct eact_content_type_corresp {
const char *type;
int (*parse)(g1m_line_t*, uint8_t*, size_t);
};
/* Correspondance list */
static struct eact_content_type_corresp eact_content_types[] = {
{"@EACT\0\0", eact_parse_content_eact},
{}
};
/* ************************************************************************** */
/* Line parsing */
/* ************************************************************************** */
/**
* eact_parse_line_content:
* Parse an E-Activity content.
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg size the buffer size.
* @return the error code (0 if ok).
*/
static int eact_parse_line_content(g1m_line_t *handle, uint8_t *buf,
size_t size)
{
/* read content header */
size_t could_read = min(size, sizeof(struct eact_contentheader));
if (could_read < 9) return (g1m_error_eof);
struct eact_contentheader hd = {};
memcpy(&hd, buf, could_read);
/* store info */
bzero(handle->name, 17);
size_t namesize = max(could_read - 8, 16);
strncpy(handle->name, (char*)hd.name, namesize);
/* log info */
log_info("Type is '%.8s'", hd.type);
log_info("Name is '%s'", handle->name);
/* prepare for next */
buf += could_read;
size -= could_read;
/* check for content type */
struct eact_content_type_corresp *ctype = eact_content_types;
while (ctype->parse) {
if (!memcmp(hd.type, ctype->type, 8))
break ;
ctype++;
}
if (!ctype->parse) {
log_error("Unknown content type: '%.8s'", hd.type);
return (0);
}
/* then parse */
int err;
if ((err = (*ctype->parse)(handle, buf, size)))
return (err);
/* otherwise, no error. */
return (0);
}
/**
* eact_parse_line_calculation:
* Parse a calculation.
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg size the buffer size.
* @return the error code (0 if ok).
*/
static int eact_parse_line_calculation(g1m_line_t *handle, uint8_t *buf,
size_t size)
{
(void)handle;
(void)buf;
(void)size;
/* TODO */
log_info("Calculation raw data is:");
logm_info(buf, size);
return (0);
}
/**
* eact_parse_line_result:
* Parse a calculation result.
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg size the buffer size.
* @return the error code (0 if ok).
*/
static int eact_parse_line_result(g1m_line_t *handle, uint8_t *buf, size_t size)
{
(void)handle;
(void)buf;
(void)size;
/* TODO */
log_info("Calculation result raw data is:");
logm_info(buf, size);
return (0);
}
/**
* eact_parse_line_stdheading:
* Parse standard heading line.
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg size the buffer size.
* @return the error code (0 if ok).
*/
static int eact_parse_line_stdheading(g1m_line_t *handle, uint8_t *buf,
size_t size)
{
/* log */
log_info("Standard heading raw data is:");
logm_info(buf, size);
/* set handle info */
handle->type = g1m_linetype_text;
handle->content = strdup((char*)buf);
if (!handle->content) return (g1m_error_alloc);
/* no error */
return (0);
}
/**
* eact_parse_line_picture:
* Parse picture line.
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg size the buffer size.
* @return the error code (0 if ok).
*/
static int eact_parse_line_picture(g1m_line_t *handle, uint8_t *buf,
size_t size)
{
/* log */
log_info("Picture raw data is:");
logm_info(buf, size);
/* big endian to host endianness */
FONTCHARACTER *s = (FONTCHARACTER*)buf;
FONTCHARACTER *p = s - 1;
while (*(++p)) *p = be16toh(*p);
/* get the size of the multi-byte string */
size_t sz = g1m_fcstombs(NULL, s, 0);
if (sz == (size_t)-1) return (g1m_error_magic);
/* make the string */
handle->content = malloc(sizeof(FONTCHARACTER) * (sz + 1));
if (!handle->content) return (g1m_error_alloc);
g1m_fcstombs(handle->content, s, 0);
/* don't forget to set the handle type! */
handle->type = g1m_linetype_picture;
/* no error */
return (0);
}
/**
* eact_parse_line_text:
* Parse text line.
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg size the buffer size.
* @return the error code (0 if ok).
*/
static int eact_parse_line_text(g1m_line_t *handle, uint8_t *buf, size_t size)
{
/* log */
log_info("Text raw data is:");
logm_info(buf, size);
/* set handle info */
handle->type = g1m_linetype_text;
handle->content = strdup((char*)buf);
if (!handle->content) return (g1m_error_alloc);
/* TODO: manage text coloration */
/* no error */
return (0);
}
/**
* eact_parse_line_code:
* Parse code line.
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg size the buffer size.
* @return the error code (0 if ok).
*/
static int eact_parse_line_code(g1m_line_t *handle, uint8_t *buf, size_t size)
{
(void)handle;
(void)buf;
(void)size;
/* TODO */
log_info("Code raw data is:");
logm_info(buf, size);
return (0);
}
/* ************************************************************************** */
/* Line Type correspondance list */
/* ************************************************************************** */
/* Correspondance type */
struct eact_line_type_corresp {
int rawtype;
int (*parse)(g1m_line_t*, uint8_t*, size_t);
const char *info;
};
/* All correspondances */
static struct eact_line_type_corresp eact_line_types[] = {
{eact_ltype_calc, eact_parse_line_calculation,
"calculation"},
{eact_ltype_calc_result, eact_parse_line_result,
"calculation result"},
{eact_ltype_content, eact_parse_line_content,
"content"},
{eact_ltype_stdheading, eact_parse_line_stdheading,
"standard heading"},
{eact_ltype_picture, eact_parse_line_picture,
"picture"},
{eact_ltype_text, eact_parse_line_text,
"pure text"},
{eact_ltype_code, eact_parse_line_code,
"text mixed with functions"},
{}
};
/**
* eact_parse_line:
* Parse a line [content].
*
* @arg handle the handle.
* @arg buf the buffer.
* @arg size the buffer size.
* @arg type the type.
* @return the error code (0 if ok).
*/
static int eact_parse_line(g1m_line_t *handle, uint8_t *buf, size_t size,
uint_fast8_t type)
{
/* initialize handle */
handle->type = 0x00;
/* look for the line type */
struct eact_line_type_corresp *linetype = eact_line_types;
while (linetype->parse) {
if (linetype->rawtype == type)
break;
linetype++;
}
if (!linetype->parse) {
log_error("unknown line type: %02x", type);
return (0);
}
/* act */
log_info("line type is '%s' (0x%02x)", linetype->info, type);
return ((*linetype->parse)(handle, buf, size));
}
/* ************************************************************************** */
/* Main parsing functions */
/* ************************************************************************** */
/**
* g1m_parse_eact:
* Parse an EACT.
*
* Thanks to Julese50 for his help on e-acts parsing.
*
* @arg handle the handle.
* @arg stream the stream to parse from.
* @return the error code (0 if ok).
*/
int g1m_parse_eact(g1m_t * handle, FILE *stream,
struct standard_header *std)
{
(void)std;
/* parse the header */
DREAD(hd, eact_header)
/* correct endianess */
hd.filesize = be32toh(hd.filesize);
hd.setup_area_size = be32toh(hd.setup_area_size);
hd.eact_version = be32toh(hd.eact_version);
hd.os_version = be32toh(hd.os_version);
/* find out the size of the setup area */
log_info("E-Activity version is '%s'.",
hd.eact_version == EACT_G1E ? "g1e" :
hd.eact_version == EACT_G2E ? "g2e" : "g3e");
log_info("Setup area size is 0x%" PRIx32 " bytes long.",
hd.setup_area_size);
/* check if is CG */
if (hd.eact_version == EACT_G3E)
handle->platform = g1m_platform_cg;
/* skip the setup area */
SKIP(hd.setup_area_size)
/* get content buffer */
size_t bufsize = hd.filesize - sizeof(struct standard_header)
- sizeof(struct eact_header) - hd.setup_area_size;
uint8_t buf[bufsize];
READ(&buf, bufsize)
/* prepare handle */
handle->line = &handle->_linedata;
/* parse content */
return (eact_parse_line_content(handle->line, buf, bufsize));
}