diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..60a61fc --- /dev/null +++ b/TODO.md @@ -0,0 +1,11 @@ +# TODO in libg1m +## Find out what these formats are/how to parse them +- G1L (languages for fx calculators?); +- G1N (???); +- G3L (languages for cg calculators); +- G3M (like G1M?); + +## Correct the parsing of these formats +- G1M (BCD, other subtypes); +- G1A/G3A (addins for fx and cg calculators); +- G3P (pictures). diff --git a/include/libg1m/format.h b/include/libg1m/format.h index 6f4ddad..8d2d56c 100644 --- a/include/libg1m/format.h +++ b/include/libg1m/format.h @@ -20,32 +20,7 @@ * In fact, there is no name for the general format, only names for the * "subformats" based on this one. * - * Here's a complete list of the declinations and corresponding IDs: */ - -enum g1m_type { - /* fx-CG add-in */ - g1m_typ_addin_cg = 0x2c, - - /* mcs (main memory) save */ - g1m_typ_mcs = 0x31, - - /* e-activity (document) */ - g1m_typ_eact = 0x49, - - /* g1r equivalent */ - g1m_typ_g2r = 0x62, - - /* g3m (fx-CG program) */ - g1m_typ_g3m = 0x75, - - /* g3p (fx-CG picture) */ - g1m_typ_g3p = 0x7d, - - /* add-in (compiled program) */ - g1m_typ_addin = 0xf3, -}; - -/* It all starts with a header, called Standard Header by Simon Lothar. + * It all starts with a header, called Standard Header by Simon Lothar. * This Standard Header contains the total filesize, the G1M type (add-in, * MCS, e-acts), some data that will be useful for the MCS type, and some * magic and control bytes. @@ -57,7 +32,7 @@ enum g1m_type { * it can simply be obtained bitwise-AND-ing with 0xff. */ struct standard_header { - /* the file identifier, should be "USBPower". */ + /* the file identifier - see below */ uint8_t main_id[8]; /* our filetype! */ @@ -90,6 +65,52 @@ struct standard_header { uint16_t number; }; +/* At the beginning, we thought "USBPower" was some magic sequence we would + * systematically find in the "main_id" field. But a counter example came: + * the G3L, where the main ID was "Ly755 ". + * + * So here are the known main IDs: */ + +enum g1m_main_id { + /* "USBPower": the most common one */ + g1m_mid_usbpower, + + /* "Ly755 ": fx-CG specific types */ + g1m_mid_ly755, +}; + +/* Here are USBPower types: */ + +enum g1m_usbpower_type { + /* fx-CG add-in */ + g1m_usbpower_type_addin_cg = 0x2c, + + /* mcs (main memory) save */ + g1m_usbpower_type_mcs = 0x31, + + /* e-activity (document) */ + g1m_usbpower_type_eact = 0x49, + + /* g1r equivalent */ + g1m_usbpower_type_g2r = 0x62, + + /* g3m (fx-CG program) */ + g1m_usbpower_type_g3m = 0x75, + + /* g3p (fx-CG picture) */ + g1m_usbpower_type_g3p = 0x7d, + + /* add-in (compiled program) */ + g1m_usbpower_type_addin = 0xf3, +}; + +/* And here are Ly755 types: */ + +enum g1m_ly755_type { + /* language file */ + g1m_ly755_type_lang = 0x2c +}; + # pragma pack() /* After the Standard Header is read and the G1M type is read, we have parts, diff --git a/include/libg1m/internals/log.h b/include/libg1m/internals/log.h index ec7a28f..edb25aa 100644 --- a/include/libg1m/internals/log.h +++ b/include/libg1m/internals/log.h @@ -55,7 +55,7 @@ /* Functions prototypes */ void g1m_log_mem(const char *prefix, void *m, size_t n); -const char *g1m_get_type_string(int code); +const char *g1m_get_type_string(int main_id, int type); const char *g1m_get_mcs_ftype_string(int code); const char *g1m_get_eact_ltype_string(int code); diff --git a/src/core/log.c b/src/core/log.c index 21c623c..6526f73 100644 --- a/src/core/log.c +++ b/src/core/log.c @@ -135,17 +135,25 @@ void g1m_log_mem(const char *prefx, void *m, size_t n) * @return the string. */ -const char *g1m_get_type_string(int code) +const char *g1m_get_type_string(int main_id, int type) { - switch (code) { - case g1m_typ_addin_cg: return ("fx-CG addin"); - case g1m_typ_mcs: return ("mcs"); - case g1m_typ_eact: return ("e-activity"); - case g1m_typ_g2r: return ("mcs (g2r)"); - case g1m_typ_g3p: return ("g3p"); - case g1m_typ_addin: return ("addin"); - default: return ("unknown"); + switch (main_id) { + case g1m_mid_usbpower: + switch (type) { + case g1m_usbpower_type_addin_cg: return ("fx-CG addin"); + case g1m_usbpower_type_mcs: return ("mcs"); + case g1m_usbpower_type_eact: return ("e-activity"); + case g1m_usbpower_type_g2r: return ("mcs (g2r)"); + case g1m_usbpower_type_g3p: return ("g3p"); + case g1m_usbpower_type_addin: return ("addin"); + } + break; + case g1m_mid_ly755: + switch (type) { + case g1m_ly755_type_lang: return ("fx-CG language file"); + } } + return ("unknown"); } /** diff --git a/src/parse/main.c b/src/parse/main.c index 04d4ff6..966dda3 100644 --- a/src/parse/main.c +++ b/src/parse/main.c @@ -9,6 +9,23 @@ /* ************************************************************************** */ #include +/** + * get_main_id: + * Get numerical main ID based on the main ID string. + * + * @arg s the 8-bytes buffer containing the ID. + * @return the main ID or -1 if the main ID is unknown. + */ + +static int get_main_id(unsigned char *s) +{ + if (!memcmp(s, "USBPower", 8)) + return (g1m_mid_usbpower); + if (!memcmp(s, "Ly755 ", 8)) + return (g1m_mid_ly755); + return (-1); +} + /** * g1m_parse: * Parse a G1M file. @@ -50,37 +67,56 @@ int g1m_parse(g1m_t *handle, FILE *stream) return (g1m_error_magic); } + /* get the main ID */ + int main_id = get_main_id(hd.main_id); + if (main_id < 0) { + log_fatal("Main ID is unknown: '%.8s'", hd.main_id); + return (g1m_error_magic); + } + /* log some data */ log_info("Standard Header Main ID is '%.8s'", hd.main_id); log_info("Standard Header Type is '%s' (0x%02x)", - g1m_get_type_string(hd.type), hd.type); + g1m_get_type_string(main_id, hd.type), hd.type); log_info("Standard Header filesize is %uo", hd.filesize); log_info("Standard Header num is %d.", hd.number); /* subparse. */ handle->is_cg = 0; - switch (hd.type) { - case g1m_typ_addin: + switch (main_id) { + case g1m_mid_usbpower: + switch (hd.type) { + case g1m_usbpower_type_addin: handle->type = g1m_type_addin; return (g1m_parse_addin(handle, stream)); - case g1m_typ_addin_cg: + case g1m_usbpower_type_addin_cg: handle->type = g1m_type_addin; handle->is_cg = 1; return (g1m_parse_addin_cg(handle, stream, &hd)); - case g1m_typ_g2r: - case g1m_typ_mcs: + case g1m_usbpower_type_g2r: + case g1m_usbpower_type_mcs: handle->type = g1m_type_mcs; return (g1m_parse_mcs(handle, stream, hd.number)); - case g1m_typ_eact: + case g1m_usbpower_type_eact: handle->type = g1m_type_eact; return (g1m_parse_eact(handle, stream)); - case g1m_typ_g3p: + case g1m_usbpower_type_g3p: handle->type = g1m_type_pict; handle->is_cg = 1; return (g1m_parse_g3p(handle, stream, &hd)); default: log_info("Type not managed (yet?): 0x%02x", hd.type); + } + break; + case g1m_mid_ly755: + switch (hd.type) { + case g1m_ly755_type_lang: + log_info("Lang type isn't managed yet."); break; + default: + log_info("Type not managed (yet?): 0x%02x", hd.type); + } + break; } /* no error */