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

489 lines
13 KiB
C

/* *****************************************************************************
* decode/std/eact.c -- decode an e-activity file.
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libg1m.
* libg1m is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libg1m 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* Content parsing */
/* ************************************************************************** */
/* line content parsing function prototype */
static int eact_decode_line(g1m_line_t *handle, uint8_t *buf, size_t size,
uint_fast8_t type);
/**
* eact_decode_content_eact:
* Decodes 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_decode_content_eact(g1m_line_t *handle, uint8_t *buf,
size_t bufsize)
{
int err;
unsigned long int i;
/* initialize the handle */
handle->g1m_line_type = g1m_linetype_eact;
handle->g1m_line_count = 0;
handle->g1m_line__size = 0;
handle->g1m_line_lines = NULL;
/* check if the buffer is non-empty */
if (!bufsize) 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->g1m_line_count = 0;
handle->g1m_line__size = ehd.line_count;
handle->g1m_line_lines =
malloc(sizeof(g1m_line_t*) * handle->g1m_line__size);
if (!handle->g1m_line_lines) return (g1m_error_alloc);
bzero(handle->g1m_line_lines, sizeof(g1m_line_t*) * handle->g1m_line__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 (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_decode_line(line, &buf[entry_offset], linesize, entry_type);
if (err) goto loop_fail;
/* store and continue */
handle->g1m_line_lines[handle->g1m_line_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 (*decode)(g1m_line_t*, uint8_t*, size_t);
};
/* Correspondance list */
static struct eact_content_type_corresp eact_content_types[] = {
{"@EACT\0\0", eact_decode_content_eact},
{}
};
/* ************************************************************************** */
/* Line parsing */
/* ************************************************************************** */
/**
* eact_decode_line_content:
* Decodes 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_decode_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->g1m_line_name, 17);
size_t namesize = max(could_read - 8, 16);
strncpy(handle->g1m_line_name, (char*)hd.name, namesize);
/* log info */
log_info("Type is '%.8s'", hd.type);
log_info("Name is '%s'", handle->g1m_line_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->decode) {
if (!memcmp(hd.type, ctype->type, 8))
break ;
ctype++;
}
/* print the content */
#if LOGLEVEL <= ll_info
if (!ctype->decode) log_error("Type is unmanaged!");
if (!size) log_info("Content was name-only.");
else if (!ctype->decode) {
log_info("Content was:");
logm_info(buf, size);
}
#endif
/* then decode */
return (ctype->decode ? (*ctype->decode)(handle, buf, size) : 0);
}
/**
* eact_decode_line_calculation:
* Decodes 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_decode_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_decode_line_result:
* Decodes 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_decode_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_decode_line_stdheading:
* Decodes 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_decode_line_stdheading(g1m_line_t *handle, uint8_t *buf,
size_t size)
{
(void)size;
/* log */
log_info("Standard heading raw data is:");
logm_info(buf, size);
/* set handle info */
handle->g1m_line_type = g1m_linetype_text;
handle->g1m_line_content = strdup((char*)buf);
if (!handle->g1m_line_content) return (g1m_error_alloc);
/* no error */
return (0);
}
/**
* eact_decode_line_picture:
* Decodes 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_decode_line_picture(g1m_line_t *handle, uint8_t *buf,
size_t size)
{
(void)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_wcstombs(NULL, s, 0);
if (sz == (size_t)-1) return (g1m_error_magic);
/* make the string */
handle->g1m_line_content = malloc(sizeof(FONTCHARACTER) * (sz + 1));
if (!handle->g1m_line_content) return (g1m_error_alloc);
g1m_wcstombs(handle->g1m_line_content, s, 0);
/* don't forget to set the handle type! */
handle->g1m_line_type = g1m_linetype_picture;
/* no error */
return (0);
}
/**
* eact_decode_line_text:
* Decodes a 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_decode_line_text(g1m_line_t *handle, uint8_t *buf, size_t size)
{
(void)size;
/* log */
log_info("Text raw data is:");
logm_info(buf, size);
/* set handle info */
handle->g1m_line_type = g1m_linetype_text;
handle->g1m_line_content = strdup((char*)buf);
if (!handle->g1m_line_content) return (g1m_error_alloc);
/* TODO: manage text coloration */
/* no error */
return (0);
}
/**
* eact_decode_line_code:
* Decodes 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_decode_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 (*decode)(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_decode_line_calculation,
"calculation"},
{eact_ltype_calc_result, eact_decode_line_result,
"calculation result"},
{eact_ltype_content, eact_decode_line_content,
"content"},
{eact_ltype_stdheading, eact_decode_line_stdheading,
"standard heading"},
{eact_ltype_picture, eact_decode_line_picture,
"picture"},
{eact_ltype_text, eact_decode_line_text,
"pure text"},
{eact_ltype_code, eact_decode_line_code,
"text mixed with functions"},
{}
};
/**
* eact_decode_line:
* decode 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_decode_line(g1m_line_t *handle, uint8_t *buf, size_t size,
uint_fast8_t type)
{
/* initialize handle */
handle->g1m_line_type = 0x00;
/* look for the line type */
struct eact_line_type_corresp *linetype = eact_line_types;
while (linetype->decode) {
if (linetype->rawtype == type)
break;
linetype++;
}
if (!linetype->decode) {
log_error("unknown line type: %02x", type);
return (0);
}
/* act */
log_info("line type is '%s' (0x%02x)", linetype->info, type);
return ((*linetype->decode)(handle, buf, size));
}
/* ************************************************************************** */
/* Main parsing functions */
/* ************************************************************************** */
/**
* g1m_decode_std_eact:
* Decodes an EACT.
*
* Thanks to Julese50 for his help on e-acts parsing.
*
* @arg h the handle to create.
* @arg buffer the buffer to read from.
* @return the error code (0 if ok).
*/
int g1m_decode_std_eact(g1m_handle_t **h, g1m_buffer_t *buffer,
struct standard_header *std)
{
(void)std; int err;
/* decode the header */
DREAD(hd, eact_header)
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);
/* allocate handle */
*h = malloc(sizeof(g1m_handle_t));
if (!*h) return (g1m_error_alloc);
g1m_handle_t *handle = *h;
memset(handle, 0, sizeof(g1m_handle_t));
/* skip the setup area */
SKIP(hd.setup_area_size)
/* prepare the handle */
handle->g1m_handle_type = g1m_type_eact;
handle->g1m_handle_platform = g1m_platform_fx;
if (hd.eact_version == EACT_G3E) /* check if fx-CG */
handle->g1m_handle_platform = g1m_platform_cg;
/* get content buffer */
size_t bufsize = hd.filesize - sizeof(struct standard_header)
- sizeof(struct eact_header) - hd.setup_area_size;
uint8_t buf[bufsize];
GREAD(&buf, bufsize)
/* decode content */
handle->g1m_handle_line = &handle->g1m_handle__linedata;
return (eact_decode_line_content(handle->g1m_handle_line, buf, bufsize));
fail:
g1m_free(*h); *h = NULL;
return (err);
}