I love e-activities. No, I do. Really.
This commit is contained in:
parent
0f131384c2
commit
0233e77d04
|
@ -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.
|
||||
|
|
137
src/parse.c
137
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));
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
|
Reference in New Issue