cake
/
libcasio
Archived
1
1
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.
libcasio/lib/file/decode/std/eact.c.draft

515 lines
13 KiB
Plaintext

/* ****************************************************************************
* file/decode/std/eact.c -- decode an e-activity file.
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libcasio.
* libcasio 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.
*
* libcasio 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 libcasio; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************* */
#include "../decode.h"
/* ---
* Content parsing.
* --- */
/* Line content parsing function prototype. */
static int eact_decode_line(casio_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(casio_line_t *handle, uint8_t *buf,
size_t bufsize)
{
int err;
unsigned long int i;
/* initialize the handle */
handle->casio_line_type = casio_linetype_eact;
handle->casio_line_count = 0;
handle->casio_line__size = 0;
handle->casio_line_lines = NULL;
/* check if the buffer is non-empty */
if (!bufsize) return (0);
/* get e-act subheader */
if (bufsize < sizeof(casio_eact_content_eact_header_t))
return (casio_error_eof);
casio_eact_content_eact_header_t ehd;
memcpy(&ehd, buf, sizeof(casio_eact_content_eact_header_t));
/* 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. */
uint32_t count = be32toh(ehd.casio_eact_content_eact_header_line_count);
if (bufsize < sizeof(casio_eact_content_eact_header_t)
+ (count + 1) * sizeof(casio_eact_line_descriptor_t))
return (casio_error_eof);
casio_eact_line_descriptor_t *lds =
(void*)&buf[sizeof(casio_eact_content_eact_header_t)];
/* prepare the handle */
handle->casio_line_count = 0;
handle->casio_line__size = count;
handle->casio_line_lines =
casio_alloc(handle->casio_line__size, sizeof(casio_line_t*));
if (!handle->casio_line_lines) return (casio_error_alloc);
memset(handle->casio_line_lines, 0,
sizeof(casio_line_t*) * handle->casio_line__size);
/* browse the lines */
msg((ll_info, "%" CASIO_PRIu32 " lines to browse", count));
if (count)
lds[0].casio_eact_line_descriptor_offset =
be32toh(lds[0].casio_eact_line_descriptor_offset << 8);
for (i = 0; i < count; i++) {
/* allocate line */
casio_line_t *line = casio_alloc(1, sizeof(casio_line_t));
err = casio_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 == count - 1)
linesize = bufsize - lds[i].casio_eact_line_descriptor_offset;
else {
/* correct endianess of the next element */
lds[i + 1].casio_eact_line_descriptor_offset =
be32toh(lds[i + 1].casio_eact_line_descriptor_offset << 8);
/* then calculate */
linesize = lds[i + 1].casio_eact_line_descriptor_offset
- lds[i].casio_eact_line_descriptor_offset;
}
/* store current info */
uint_fast8_t entry_type = lds[i].casio_eact_line_descriptor_type;
uint_fast32_t entry_offset =
lds[i].casio_eact_line_descriptor_offset;
/* check if buffer is big enough */
err = casio_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->casio_line_lines[handle->casio_line_count++] = line;
continue;
loop_fail:
casio_free_line_content(line);
casio_free(line);
goto fail;
}
/* no error */
return (0);
fail:
casio_free_line_content(handle);
return (err);
}
/* ---
* Content Type correspondance list.
* --- */
/* Correspondance type. */
struct eact_content_type_corresp {
const char *type;
int (*decode)(casio_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(casio_line_t *handle, uint8_t *buf,
size_t size)
{
/* read content header */
size_t could_read = min(size, sizeof(casio_eact_content_header_t));
if (could_read < 9) return (casio_error_eof);
casio_eact_content_header_t hd = {};
memcpy(&hd, buf, could_read);
/* store info */
bzero(handle->casio_line_name, 17);
size_t namesize = max(could_read - 8, 16);
strncpy(handle->casio_line_name, (char*)hd.casio_eact_content_header_name,
namesize);
/* log info */
msg((ll_info, "Type is '%.8s'", hd.casio_eact_content_header_type));
msg((ll_info, "Name is '%s'", handle->casio_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.casio_eact_content_header_type, ctype->type, 8))
break ;
ctype++;
}
/* print the content */
#if !defined(LIBCASIO_DISABLED_LOG)
if (!ctype->decode)
msg((ll_error, "Type is unmanaged!"));
if (!size) log_info("Content was name-only.");
else if (!ctype->decode) {
msg((ll_info, "Content was:"));
mem((ll_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(casio_line_t *handle, uint8_t *buf,
size_t size)
{
(void)handle;
(void)buf;
(void)size;
/* TODO */
msg((ll_info, "Calculation raw data is:"));
mem((ll_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(casio_line_t *handle,
uint8_t *buf, size_t size)
{
(void)handle;
(void)buf;
(void)size;
/* TODO */
msg((ll_info, "Calculation result raw data is:"));
mem((ll_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(casio_line_t *handle, uint8_t *buf,
size_t size)
{
(void)size;
/* log */
msg((ll_info, "Standard heading raw data is:"));
mem((ll_info, buf, size));
/* set handle info */
handle->casio_line_type = casio_linetype_text;
handle->casio_line_content = strdup((char*)buf);
if (!handle->casio_line_content) return (casio_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(casio_line_t *handle, uint8_t *buf,
size_t size)
{
(void)size;
/* log */
msg((ll_info, "Picture raw data is:"));
mem((ll_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 = casio_wcstombs(NULL, s, 0);
if (sz == (size_t)-1) return (casio_error_magic);
/* make the string */
handle->casio_line_content = casio_alloc(sz + 1, sizeof(FONTCHARACTER));
if (!handle->casio_line_content) return (casio_error_alloc);
casio_wcstombs(handle->casio_line_content, s, 0);
/* don't forget to set the handle type! */
handle->casio_line_type = casio_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(casio_line_t *handle, uint8_t *buf,
size_t size)
{
(void)size;
/* log */
msg((ll_info, "Text raw data is:"));
mem((ll_info, buf, size));
/* set handle info */
handle->casio_line_type = casio_linetype_text;
handle->casio_line_content = strdup((char*)buf);
if (!handle->casio_line_content) return (casio_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(casio_line_t *handle, uint8_t *buf,
size_t size)
{
(void)handle;
(void)buf;
(void)size;
/* TODO */
msg((ll_info, "Code raw data is:"));
mem((ll_info, buf, size));
return (0);
}
/* ---
* Line Type correspondance list.
* --- */
/* Correspondance type. */
struct eact_line_type_corresp {
int rawtype;
int (*decode)(casio_line_t*, uint8_t*, size_t);
const char *info;
};
/* All correspondances. */
static struct eact_line_type_corresp eact_line_types[] = {
{casio_eact_ltype_calc, eact_decode_line_calculation,
"calculation"},
{casio_eact_ltype_calc_result, eact_decode_line_result,
"calculation result"},
{casio_eact_ltype_content, eact_decode_line_content,
"content"},
{casio_eact_ltype_stdheading, eact_decode_line_stdheading,
"standard heading"},
{casio_eact_ltype_picture, eact_decode_line_picture,
"picture"},
{casio_eact_ltype_text, eact_decode_line_text,
"pure text"},
{casio_eact_ltype_code, eact_decode_line_code,
"text mixed with functions"},
{0, 0, NULL}
};
/**
* 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(casio_line_t *handle, uint8_t *buf, size_t size,
uint_fast8_t type)
{
/* initialize handle */
handle->casio_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) {
msg((ll_error, "unknown line type: %02x", type));
return (0);
}
/* act */
msg((ll_info, "line type is '%s' (0x%02x)", linetype->info, type));
return ((*linetype->decode)(handle, buf, size));
}
/* ---
* Main parsing functions.
* --- */
/**
* casio_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 CASIO_EXPORT casio_decode_std_eact(casio_file_t **h,
casio_stream_t *buffer, casio_standard_header_t *std)
{
(void)std; int err;
/* decode the header */
DREAD(hd, casio_eact_header_s)
hd.casio_eact_header_filesize =
be32toh(hd.casio_eact_header_filesize);
hd.casio_eact_header_setup_area_size =
be32toh(hd.casio_eact_header_setup_area_size);
hd.casio_eact_header_eact_version =
be32toh(hd.casio_eact_header_eact_version);
hd.casio_eact_header_os_version =
be32toh(hd.casio_eact_header_os_version);
/* find out the size of the setup area */
msg((ll_info, "E-Activity version is '%s'.",
hd.casio_eact_header_eact_version == EACT_G1E ? "g1e" :
hd.casio_eact_header_eact_version == EACT_G2E ? "g2e" : "g3e"));
msg((ll_info, "Setup area size is 0x%" PRIx32 " bytes long.",
hd.casio_eact_header_setup_area_size));
/* allocate handle */
*h = casio_alloc(1, sizeof(casio_file_t));
if (!*h) return (casio_error_alloc);
casio_file_t *handle = *h;
memset(handle, 0, sizeof(casio_file_t));
/* skip the setup area */
SKIP(hd.casio_eact_header_setup_area_size)
/* prepare the handle */
handle->casio_file_type = casio_filetype_eact;
handle->casio_handle_platform = casio_filefor_fx;
if (hd.casio_eact_header_eact_version == EACT_G3E) /* check if fx-CG */
handle->casio_handle_platform = casio_filefor_cg;
/* get content buffer */
size_t bufsize = hd.casio_eact_header_filesize
- sizeof(casio_standard_header_t)
- sizeof(casio_eact_header_t)
- hd.casio_eact_header_setup_area_size;
uint8_t buf[bufsize];
GREAD(&buf, bufsize)
/* decode content */
handle->casio_file_line = &handle->casio_file__linedata;
return (eact_decode_line_content(handle->casio_file_line, buf, bufsize));
fail:
casio_free_file(*h); *h = NULL;
return (err);
}