From 0233e77d046ed48974107409482062b4ead64c21 Mon Sep 17 00:00:00 2001 From: "Thomas \"Cakeisalie5\" Touhey" Date: Wed, 2 Nov 2016 01:46:08 +0100 Subject: [PATCH] I love e-activities. No, I do. Really. --- Makefile | 0 Makefile.msg | 0 Makefile.vars | 0 include/libg1m/internals/format.h | 68 +++++++++------ src/parse.c | 137 +++++++++++++++++++----------- 5 files changed, 129 insertions(+), 76 deletions(-) mode change 100644 => 100755 Makefile mode change 100644 => 100755 Makefile.msg mode change 100644 => 100755 Makefile.vars diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 diff --git a/Makefile.msg b/Makefile.msg old mode 100644 new mode 100755 diff --git a/Makefile.vars b/Makefile.vars old mode 100644 new mode 100755 diff --git a/include/libg1m/internals/format.h b/include/libg1m/internals/format.h index 304efcd..b3f47bc 100644 --- a/include/libg1m/internals/format.h +++ b/include/libg1m/internals/format.h @@ -368,12 +368,12 @@ struct mcs_matheader { * E-Activities (g1e, g2e, g3e) * ----------------------------------------------------------------------------- * E-Activities are the format CASIO uses for in-calc documents. + * It is the funniest subformat the the libg1m can parse. * * There is only one part for e-activities. - * This part is quite complicated. The header has three zones: + * The overall header has two zones: * - the special header, that keeps the global info; - * - the setup area, that keeps part of the calculator setup; - * - the intermediate data, with magic things and line count. + * - the setup area, that keeps one part of the calculator setup. * * There are several types for E-Activies, identified by the extensions * CASIO give them. @@ -406,38 +406,43 @@ struct eact_header { uint32_t os_version; }; -/* Here, we won't put the setup directory, but we have to skip - * `0x04 + setup_directory_size` + (`setup_area_size` - 0x30) bytes. - * Parse the setup directory is TODO. - * - * The intermediate zone is full of control and magic bytes. - * The line count is not really part of it, but we'll bodge it here for - * simplicity: */ +/* And now, the funniest part: the content. + * So a content has this header: */ -struct eact_intermediate { - /* magic sequence: "@EACT" 0x00 0x00 0x00 0x00 0x00 0x00 0x01 */ - uint8_t magic[12]; +struct eact_contentheader { + /* content type: @EACT, @RUNMAT, ... */ + uint8_t type[8]; - /* control byte: `filesize` - 0x40 - `setup_area_size` */ - uint32_t control; + /* magic sequence: 0x00 0x00 0x00 0x01 */ + uint8_t magic[4]; - /* magic sequence: "EACT1" 0x00 0x00 0x00 0x00 0x00 0x00 0x14 */ - uint8_t magic2[12]; + /* first length: simlo says `filesize` - 0x40 - `setup_area_size` + * i don't get what length is this... */ + uint32_t length1; - /* control byte: `filesize` - 0x54 - `setup_area_size` */ - uint32_t control2; + /* element name: "EACT1", "TEXT1", ... */ + uint8_t name[12]; + + /* second length: simlo says `filesize` - 0x54 - `setup_area_size` + * i don't really get what length is this neither. */ + uint32_t length2; /* magic sequence: 0xD4 0x00 0x00 0x66 */ - uint8_t magic3[4]; + uint8_t magic2[4]; +}; +/* There are several types of contents. + * The most basic one is also called "@EACT". + * It has this content subheader: */ + +struct eact_eactheader { /* line count */ uint32_t line_count; }; -/* Once this intermediate zone is passed, we have to parse the line directory, - * which is an array of `line_count` line descriptors. - * - * Each line has a type. Here are the known types: */ +/* And after, lines come. First of all, there is a line descriptor table, + * that contain the line type and the line offset from the subheader begin. + * A line type can have these types: */ enum eact_linetype { eact_ltype_stdheading = 0x07, @@ -445,7 +450,7 @@ enum eact_linetype { eact_ltype_code = 0x82 }; -/* And here's the structure of a line descriptor: */ +/* And here's the line descriptor structure: */ struct line_descriptor { /* the entry type */ @@ -455,9 +460,16 @@ struct line_descriptor { uint32_t entry_offset :24; }; -/* Once this directory is passed, we have the array of lines. - * Each one is zero-terminated and 4-aligned by random filler bytes. - * ----------------------------------------------------------------------------- +/* And there is only one content after the main header, and it's a content + * of EACT type. But hey, why the heck have we defined several types and stuff? + * Well, that's the funniest thing of E-Activities: + * + * they are RECURSIVE. [drama alert] + * + * Which means in each node, there can be a content to parse. + * TODO: find the link between line types and the @TYPES in + * the Content Header. */ +/* ----------------------------------------------------------------------------- * fx-CG Pictures (g3p) * ----------------------------------------------------------------------------- * These are pictures for fx-CG. They only have one part. diff --git a/src/parse.c b/src/parse.c index 2b899c6..08a93e6 100644 --- a/src/parse.c +++ b/src/parse.c @@ -480,6 +480,82 @@ static int g1m_parse_g3p(g1m_t *handle, FILE *stream, /* ************************************************************************** */ /* E-Activities */ /* ************************************************************************** */ +/** + * g1m_parse_eact_content: + * Parse en EACT in an EACT. + * + * @arg handle the handle. + * @arg buf the buffer. + * @arg bufsize the buffer length. + * @return the error code (0 if ok). + */ + +static int g1m_parse_eact_content(g1m_t *handle, uint8_t *buf, size_t bufsize) +{ + /* read intermediate area */ + struct eact_contentheader hd; + memcpy(&hd, buf, sizeof(struct eact_contentheader)); + buf += sizeof(struct eact_contentheader); + bufsize -= sizeof(struct eact_contentheader); + + /* correct endianess */ + hd.length1 = be32toh(hd.length1); + hd.length2 = be32toh(hd.length2); + + /* check magic sequences */ + if (memcmp(hd.magic, "\x00\x00\x00\x01", 4)) { + log_info("First magic sequence is incorrect"); + return (g1m_error_magic); + } else if (memcmp(hd.magic2, "\xD4\x00\x00\x66", 4)) { + log_info("Second magic sequence is incorrect"); + return (g1m_error_magic); + } + + /* log info */ + log_info("Type is '%s'", hd.type); + log_info("Name is '%s'", hd.name); + + /* get e-act subheader */ + 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. */ + struct line_descriptor *lds = (void*)&buf[sizeof(struct eact_eactheader)]; + + /* browse the lines */ + 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++) { + /* 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; + } + + /* log data */ + log_info("[%ld] Is '%s' (0x%02x)", i + 1, + g1m_get_eact_ltype_string(lds[i].entry_type), lds[i].entry_type); + log_info("[%ld] Buffer (0x%zxo) is:", i + 1, linesize); + logm_info(&buf[lds[i].entry_offset], linesize); + } + + /* no errors */ + return (0); +} + /** * g1m_parse_eact: * Parse an EACT. @@ -503,59 +579,24 @@ static int g1m_parse_eact(g1m_t * handle, FILE *stream) hd.os_version = be32toh(hd.os_version); /* find out the size of the setup area */ - uint_fast32_t setup_directory_size = (hd.eact_version == EACT_G3E) ? 0x2C : 0x10; - uint_fast32_t setup_area_size = 0x04 + setup_directory_size - + hd.setup_area_size - 0x30; - log_info("(Header) setup area size is 0x%x bytes long.", + 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%x bytes long.", hd.setup_area_size); - log_info("(Calculation) setup area size is 0x%lx bytes long.", - setup_area_size); /* skip the setup area */ - SKIP(setup_area_size) + SKIP(hd.setup_area_size) - /* read intermediate area */ - DREAD(in, eact_intermediate) + /* get content buffer */ + size_t bufsize = hd.filesize - sizeof(struct eact_header) + - hd.setup_area_size; + log_info("bufsize is %zu", bufsize); + uint8_t buf[bufsize]; + READ(&buf, bufsize) - /* correct endianess */ - in.control = be32toh(in.control); - in.control2 = be32toh(in.control2); - in.line_count = be32toh(in.line_count); - - /* check magic sequences and control numbers */ - if (memcmp(in.magic, "@EACT\x00\x00\x00\x00\x00\x00\x01", 12)) { - log_info("First magic sequence is incorrect"); - return (g1m_error_magic); - } else if (memcmp(in.magic2, "EACT1\x00\x00\x00\x00\x00\x00\x14", 12)) { - log_info("Second magic sequence is incorrect"); - return (g1m_error_magic); - } else if (memcmp(in.magic3, "\xD4\x00\x00\x66", 4)) { - log_info("Third magic sequence is incorrect"); - return (g1m_error_magic); - } else if (in.control != hd.filesize - 0x40 - hd.setup_area_size) { - log_info("First control number is incorrect"); - return (g1m_error_magic); - } else if (in.control2 != hd.filesize - 0x54 - hd.setup_area_size) { - log_info("Second control number is incorrect"); - return (g1m_error_magic); - } - - /* browse the lines */ - log_info("%d lines to browse.", in.line_count); - for (uint_fast32_t i = 0; i < in.line_count; i++) { - /* read the line descriptor */ - DREAD(ld, line_descriptor) - - /* correct endianess */ - ld.entry_offset = be32toh(ld.entry_offset >> 8); - - /* log info */ - log_info("[%ld] Is '%s' (0x%02x)", i, - g1m_get_eact_ltype_string(ld.entry_type), ld.entry_type); - } - - /* no errors */ - return (0); + /* parse content */ + return (g1m_parse_eact_content(handle, buf, bufsize)); } /* ************************************************************************** */