From a3d708c766ceb0bd7b50b69c205cd82c8ffab8c9 Mon Sep 17 00:00:00 2001 From: "Thomas \"Cakeisalie5\" Touhey" Date: Fri, 10 Mar 2017 13:32:27 +0100 Subject: [PATCH] Implemented matrixes and correct CAS type decoding. --- include/libg1m/format/caspro.h | 22 ++++++++++- include/libg1m/internals.h | 1 + include/libg1m/mcs.h | 3 +- src/decode/cas.c | 10 +++++ src/decode/mcs/matrix.c | 38 +++++++++++++++++++ src/type/cas.c | 12 ++++++ src/type/caspro.c | 68 +++++++++++++++++++--------------- 7 files changed, 122 insertions(+), 32 deletions(-) diff --git a/include/libg1m/format/caspro.h b/include/libg1m/format/caspro.h index e2e06d6..591a618 100644 --- a/include/libg1m/format/caspro.h +++ b/include/libg1m/format/caspro.h @@ -55,7 +55,7 @@ struct caspro_header { }; /* ************************************************************************** */ -/* Variable/number */ +/* Variable */ /* ************************************************************************** */ /* Variable has the following structure (described in a comment): * @@ -73,6 +73,26 @@ struct caspro_header { * * uint8_t checksum; * The checksum (calculated as for the header). */ +/* ************************************************************************** */ +/* Matrix/List */ +/* ************************************************************************** */ +/* The matrix height is stored in `used`, and its width is stored in the low + * byte of `length`. For the list, only the height is used (`used`). + * + * There aren't any imaginary parts in matrixes and lists (and this wasn't made + * possible until CASIOWIN 2.00, so a long time after). Each value (line by + * line) is sent as an independent cell, which has this format: */ + +struct caspro_cell { + /* coordinates */ + uint16_t y, x; + + /* the value */ + cas_bcd_t val; + + /* the checksum */ + uint8_t checksum; +}; /* TODO: other file formats */ # pragma pack() diff --git a/include/libg1m/internals.h b/include/libg1m/internals.h index d0d36fe..f600c31 100644 --- a/include/libg1m/internals.h +++ b/include/libg1m/internals.h @@ -153,6 +153,7 @@ int g1m_decode_cashpart_##NAME(g1m_mcshead_t *head, g1m_mcshead_t *heads, \ G1M_CASFUNC(var) G1M_CASFUNC(program) G1M_CASHFUNC(program) +G1M_CASFUNC(matrix) /* ************************************************************************** */ /* Picture utilities */ /* ************************************************************************** */ diff --git a/include/libg1m/mcs.h b/include/libg1m/mcs.h index a7a7751..1e50151 100644 --- a/include/libg1m/mcs.h +++ b/include/libg1m/mcs.h @@ -82,6 +82,7 @@ typedef struct g1m_mcs_cell_s { /* mcs file head flags */ # define g1m_mcsflag_unfinished 0x8000 /* is there still parts to read? */ # define g1m_mcsflag_multiple 0x4000 /* is a group */ +# define g1m_mcsflag_request 0x2000 /* is a request */ # define g1m_mcsflag_complex 0x0001 /* is a complex variable */ /* mcs file type -- what type of raw information is there @@ -110,7 +111,7 @@ typedef struct g1m_mcshead_s { unsigned char _group[17], _dirname[9]; /* cas-related raw data */ - unsigned char _maintype[4]; + unsigned char _appname[4]; unsigned char _datatype[3]; /* the program password */ diff --git a/src/decode/cas.c b/src/decode/cas.c index 6e0f18b..11a1b77 100644 --- a/src/decode/cas.c +++ b/src/decode/cas.c @@ -47,6 +47,8 @@ struct cas_corresp { static struct cas_corresp cas_types[] = { {g1m_mcstype_var, FUNC(var), NULL}, {g1m_mcstype_program, FUNC(program), HFUNC(program)}, + {g1m_mcstype_matrix, FUNC(matrix), NULL}, + {g1m_mcstype_list, FUNC(matrix), NULL}, TTERM }; @@ -115,6 +117,14 @@ static int decode_caspro_head(g1m_mcshead_t *head, struct caspro_header *hd) /* TODO: id */ head->count = 1; break; + case g1m_mcstype_matrix: + head->height = hd->used; + head->width = be16toh(hd->length) & 0xFF; + break; + case g1m_mcstype_list: + head->height = hd->used; + head->width = 1; + break; } /* TODO */ diff --git a/src/decode/mcs/matrix.c b/src/decode/mcs/matrix.c index 98e54d9..b05d527 100644 --- a/src/decode/mcs/matrix.c +++ b/src/decode/mcs/matrix.c @@ -104,3 +104,41 @@ fail: *handle = NULL; return (err); } + +/** + * g1m_decode_caspart_matrix: + * Decode a CAS matrix part. + * + * @arg handle the handle to contribute to. + * @arg buffer the buffer to read from. + * @return the error code (0 if ok). + */ + +int g1m_decode_caspart_matrix(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) +{ + /* get content */ + DREAD(cell, caspro_cell) + + /* check the cell */ + uint8_t csum = ~g1m_checksum8(&cell, sizeof(struct caspro_cell) - 1) + 1; + if (csum != cell.checksum) + return (g1m_error_checksum); + + /* decode */ + cell.y = be16toh(cell.y); + cell.x = be16toh(cell.x); + g1m_bcd_t bcd; g1m_bcd_fromcas(&cell.val, &bcd); + handle->cells[cell.y][cell.x] = (g1m_mcs_cell_t){ + .real = bcd, + .imgn = {}, + .used = 1 + }; + + /* check if its the last cell */ + if (cell.y == handle->head.height - 1 + && cell.x == handle->head.width - 1) + handle->head.flags &= ~g1m_mcsflag_unfinished; + + /* no error! */ + return (0); +} diff --git a/src/type/cas.c b/src/type/cas.c index a639748..ac27f1d 100644 --- a/src/type/cas.c +++ b/src/type/cas.c @@ -41,8 +41,12 @@ struct type_corresp { #define TTERM {NULL, 0, 0} static struct type_corresp cas_groups[] = { /* implemented */ + {"LT", g1m_mcstype_list, 0}, // list + {"MT", g1m_mcstype_matrix, 0}, // matrix {"P1", g1m_mcstype_program, 0}, // one program + {"PG", g1m_mcstype_program, 0}, // same than above {"PZ", g1m_mcstype_program, g1m_mcsflag_multiple}, // set of programs + {"VM", g1m_mcstype_variable, 0}, // one variable /* not implemented yet */ {"AA", 0, 0}, // dynamic graph functions @@ -54,18 +58,26 @@ static struct type_corresp cas_groups[] = { {"DD", 0, 0}, // screenshot {"EN", 0, 0}, // one editor file {"FN", 0, 0}, // set of editor files + {"FT", 0, 0}, // ??? (cafix) {"F1", 0, 0}, // one function memory {"F6", 0, 0}, // set of function memories {"GA", 0, 0}, // set of graph functions {"GF", 0, 0}, // graph zoom factor (graph function?) + {"GM", 0, 0}, // gmem (cafix) {"GR", 0, 0}, // graph range {"GT", 0, 0}, // function table {"MA", 0, 0}, // set of matrices + {"PC", 0, 0}, // picture from 9xxx (cafix) {"PD", 0, 0}, // polynomial equations + {"RF", 0, 0}, // ??? (cafix) + {"RR", 0, 0}, // ??? (cafix) {"RT", 0, 0}, // recursion table {"SD", 0, 0}, // simultaneous equations + {"SE", 0, 0}, // equation (cafix) {"SR", 0, 0}, // linear regression data {"SS", 0, 0}, // standard deviation data + {"TR", 0, 0}, // ??? (cafix) + {"WD", 0, 0}, // window data (cafix) /* terminating entry */ TTERM diff --git a/src/type/caspro.c b/src/type/caspro.c index f8c3f9f..dc99858 100644 --- a/src/type/caspro.c +++ b/src/type/caspro.c @@ -22,13 +22,15 @@ /* Local types */ /* ************************************************************************** */ /* Correspondance type */ -struct type_corresp { +#define flg_type 0x0001 /* if not there, the type is defined by the datatype */ +#define flg_flags 0x0002 /* the following value is the flag to OR. */ +struct app_corresp { /* identification */ - const char *maintype; - const char *datatype; + const char *name; - /* libg1m MCS file type */ - g1m_mcstype_t type; + /* values */ + unsigned int flags; /* the internal flags */ + unsigned long int value; /* meaning of this depends on the flags */ }; /* ************************************************************************** */ @@ -38,12 +40,12 @@ struct type_corresp { * - Correspondances with a NULL data type means the data type isn't to be * read. */ -#define TTERM {NULL, NULL, 0} -static struct type_corresp cas_types[] = { - {"TXT", "PG", g1m_mcstype_program}, - {"VAL", "VM", g1m_mcstype_variable}, - {"END", NULL, g1m_mcstype_end}, - //{"VAL", "MT", g1m_mcstype_matrix}, +#define TTERM {NULL, 0, 0} +static struct app_corresp apps[] = { + {"TXT", 0, 0}, /* editor */ + {"VAL", 0, 0}, /* RUN? */ + {"REQ", flg_flags, g1m_mcsflag_request}, /* request */ + {"END", flg_type, g1m_mcstype_end}, /* end */ /* terminating entry */ TTERM @@ -57,38 +59,44 @@ static struct type_corresp cas_types[] = { * Get the libg1m MCS type from raw CAS identification data. * * @arg head the head to fill. - * @arg maintype the main type string. + * @arg app the app string. * @arg datatype the data type string. * @return the error (if any). */ int g1m_maketype_caspro(g1m_mcshead_t *head, - const char *maintype, const char *datatype) + const char *app, const char *datatype) { - /* copy raw information */ - memset(head, 0, sizeof(g1m_mcshead_t)); - head->flags |= g1m_mcsinfo_caspro; - memcpy(head->_maintype, maintype, 3); - head->_maintype[3] = 0; - memcpy(head->_datatype, datatype, 2); - head->_datatype[2] = 0; - - /* look for correspondance */ - struct type_corresp *c; - for (c = cas_types; c->datatype; c++) { - if ((!c->maintype || !strncmp(maintype, c->maintype, 4)) - && (!c->datatype || !strncmp(datatype, c->datatype, 3))) + /* look for the app */ + struct app_corresp *a; + for (a = apps; a->name; a++) { + if (!strncmp(a->name, app, 3)) break; } - if (!c->maintype) goto notfound; + if (!a->name) goto notfound; + + /* check if we need the datatype */ + if (a->flags & flg_type) { + memset(head, 0, sizeof(g1m_mcshead_t)); + head->type = a->value; + memcpy(head->_appname, app, 3); head->_appname[3] = 0; + } else { + int err = g1m_maketype_cas(head, datatype); + if (err) return (err); + } + + /* copy raw information */ + head->flags = (head->flags & ~g1m_mcsmask_info) | g1m_mcsinfo_caspro; + memcpy(head->_appname, app, 3); head->_appname[3] = 0; + if (a->flags & flg_flags) + head->flags |= (unsigned int)a->value; /* fill in info and return */ - head->type = c->type; return (0); notfound: - log_info("Type with '%.4s' data string was not implemented or not " - "recognized.", datatype); + log_info("Type with '%.3s' app name and '%.2s' data string was not" + "implemented or recognized.", app, datatype); head->type = 0; return (1); }