From a4ff04232d639a39524e4a3c8bd5020a11a8b449 Mon Sep 17 00:00:00 2001 From: "Thomas \"Cakeisalie5\" Touhey" Date: Thu, 30 Mar 2017 14:30:48 +0200 Subject: [PATCH] Arranged some things, corrected GRC decoding. --- include/libg1m.h | 2 +- include/libg1m/bcd.h | 1 - include/libg1m/fontcharacter.h | 36 ++++ include/libg1m/format/cas.h | 11 +- include/libg1m/format/cas/backup.h | 30 +++ include/libg1m/format/cas/cell.h | 2 - include/libg1m/format/cas/gmem.h | 70 +++++++ include/libg1m/format/cas/graph.h | 44 ++++ .../format/cas/{screenshot.h => picture.h} | 9 +- include/libg1m/format/cas/program.h | 14 +- include/libg1m/format/casemul.h | 1 + include/libg1m/format/fxi.h.draft | 1 - include/libg1m/format/mcs/cells.h | 1 + include/libg1m/format/mcs/picture.h | 1 + include/libg1m/format/mcs/program.h | 3 +- include/libg1m/format/mcs/spreadsheet.h | 1 + include/libg1m/format/std/eact.h | 2 + include/libg1m/format/std/fkey.h | 2 +- include/libg1m/format/std/lang.h | 2 +- include/libg1m/mcs.h | 4 +- src/decode/cas.c | 60 +++++- src/decode/cas/cell.c | 2 +- src/decode/cas/program.c | 10 +- src/decode/mcs.c | 195 ++++++++++++++++++ src/decode/std/eact.c | 4 +- src/decode/std/mcs.c | 178 ---------------- src/manage/mcsfile.c | 3 +- src/type/cas/app.c | 16 +- src/type/cas/datatype.c | 20 +- src/type/mcs.c | 6 +- 30 files changed, 492 insertions(+), 239 deletions(-) create mode 100644 include/libg1m/fontcharacter.h create mode 100644 include/libg1m/format/cas/backup.h create mode 100644 include/libg1m/format/cas/gmem.h create mode 100644 include/libg1m/format/cas/graph.h rename include/libg1m/format/cas/{screenshot.h => picture.h} (90%) create mode 100644 src/decode/mcs.c diff --git a/include/libg1m.h b/include/libg1m.h index 67dfaf2..9db9c66 100644 --- a/include/libg1m.h +++ b/include/libg1m.h @@ -31,7 +31,7 @@ # include # include # include -# include +# include # include # include # include diff --git a/include/libg1m/bcd.h b/include/libg1m/bcd.h index 28f777f..14fb413 100644 --- a/include/libg1m/bcd.h +++ b/include/libg1m/bcd.h @@ -110,7 +110,6 @@ typedef struct bcd { unsigned char BCDval[9]; unsigned char _align[3]; } mcs_bcd_t; - /* ************************************************************************** */ /* Conversion utilities */ /* ************************************************************************** */ diff --git a/include/libg1m/fontcharacter.h b/include/libg1m/fontcharacter.h new file mode 100644 index 0000000..041aafe --- /dev/null +++ b/include/libg1m/fontcharacter.h @@ -0,0 +1,36 @@ +/* ***************************************************************************** + * libg1m/fontcharacter.h -- libg1m FONTCHARACTER-related utilities. + * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey + * + * This file is part of libg1m. + * libg1m 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. + * + * libg1m 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 libg1m; if not, see . + * ************************************************************************** */ +#ifndef LIBG1M_FONTCHARACTER_H +# define LIBG1M_FONTCHARACTER_H +# include + +/* All FONTCHARACTER-related utilities that used to be there were moved into + * a separate library, libfontcharacter, which also takes care of the + * translations (multi-byte/fixed-width, unicode, tokens). + * + * This header is there so the usage of FONTCHARACTER-related utilities in + * libg1m can be more modular. + * + * Here are macros, for later change. */ + +# define g1m_wctomb(S, WC) (fc_wctomb((S), (WC))) +# define g1m_wcstombs(DST, SRC, N) (fc_wcstombs((DST), (SRC), (N))) +# define g1m_mbtowc(PWC, S, N) (fc_mbtowc((PWC), (S), (N))) +# define g1m_mbstowcs(DST, SRC, N) (fc_mbstowcs((DST), (SRC), (N))) +#endif /* LIBG1M_FONTCHARACTER_H */ diff --git a/include/libg1m/format/cas.h b/include/libg1m/format/cas.h index 32e7d17..c158f8f 100644 --- a/include/libg1m/format/cas.h +++ b/include/libg1m/format/cas.h @@ -87,8 +87,8 @@ struct cas40 { * pieces of documentation, here are the extension types I could find: */ # define casdyn_ext_9850 0x00 /* 50 bytes long */ -# define casdyn_ext_end 0xFF /* 46 bytes long, used with the END packet - * described by Casetta */ +# define casdyn_ext_end 0xFF /* yet an alias to `casdyn_ext_9850`, + * used by the END packet. */ # define casdyn_ext_g100 0x31 /* 40 bytes long */ /* Here are the common fields to all packets: */ @@ -188,7 +188,10 @@ struct _cas100_info { * Here are the content formats for the two header types: */ # pragma pack() -# include +# include /* programs, f-mem */ # include /* list, matrix, variable */ -# include +# include +# include +# include +# include #endif /* LIBG1M_FORMAT_CAS_H */ diff --git a/include/libg1m/format/cas/backup.h b/include/libg1m/format/cas/backup.h new file mode 100644 index 0000000..7816d17 --- /dev/null +++ b/include/libg1m/format/cas/backup.h @@ -0,0 +1,30 @@ +/* ***************************************************************************** + * libg1m/format/cas/backup.h -- description of the CAS backup format. + * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey + * + * This file is part of libg1m. + * libg1m 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. + * + * libg1m 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 libg1m; if not, see . + * ************************************************************************** */ +#ifndef LIBG1M_FORMAT_CAS_BACKUP_H +# define LIBG1M_FORMAT_CAS_BACKUP_H + +/* Backups are raw backups from the calculator. + * + * The CAS40 specific subheader is basically "TYPE". + * For example, a backup from a CFX-98600G has the "TYPEA" subheader, + * and the editor filename is "02". + * + * TODO: find out the content format. */ + +#endif /* LIBG1M_FORMAT_CAS_BACKUP_H */ diff --git a/include/libg1m/format/cas/cell.h b/include/libg1m/format/cas/cell.h index 8126808..62a06e5 100644 --- a/include/libg1m/format/cas/cell.h +++ b/include/libg1m/format/cas/cell.h @@ -18,7 +18,6 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_CAS_MATRIX_H # define LIBG1M_FORMAT_CAS_MATRIX_H -# pragma pack(1) /* Lists, matrixes and variables are sent/stored the same way. * Variables are either 1*1 matrixes, or 0*0 matrixes if unused. @@ -44,5 +43,4 @@ * * The order is unknown to me yet. (XXX: todo) */ -# pragma pack() #endif /* LIBG1M_FORMAT_CAS_SCREENSHOT_H */ diff --git a/include/libg1m/format/cas/gmem.h b/include/libg1m/format/cas/gmem.h new file mode 100644 index 0000000..0712c66 --- /dev/null +++ b/include/libg1m/format/cas/gmem.h @@ -0,0 +1,70 @@ +/* ***************************************************************************** + * libg1m/format/cas/gmem.h -- description of the CAS G-MEM format. + * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey + * + * This file is part of libg1m. + * libg1m 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. + * + * libg1m 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 libg1m; if not, see . + * ************************************************************************** */ +#ifndef LIBG1M_FORMAT_CAS_GMEM_H +# define LIBG1M_FORMAT_CAS_GMEM_H +# include +# pragma pack(1) + +/* You can save some graph function's expression inside a graph memory (G-MEM). + * The data size is stored in CAS50's `length` field. + * TODO: find out the equivalent with CAS40 headers? + * + * It starts with 20 graph entries, which have this format: */ + +struct cas_gmem_entry { + /* function type code */ + uint8_t type; + + /* flags */ + uint8_t flags; +}; + +/* Where the function types are the following: */ + +# define cas_gmem_type_ye 0x00 /* Y= */ +# define cas_gmem_type_re 0x40 /* r= */ +# define cas_gmem_type_yg 0x0C /* Y> */ +# define cas_gmem_type_yl 0x0D /* Y< */ +# define cas_gmem_type_yge 0x0E /* Y>= */ +# define cas_gmem_type_yle 0x0F /* Y<= */ + +/* And the flags are the following: */ + +# define cas_gmem_flag_orange 0x01 +# define cas_gmem_flag_blue 0x02 +# define cas_gmem_flag_green 0x04 +# define cas_gmem_flag_sel 0x80 +# define cas_gmem_flag_eqsel 0xB0 + +/* If there are no flags (`entry.flags == 0`), then the function is not defined. + * If the function type is one of: Y=, r=, Param (?) + * Then use `cas_gmem_flag_eqsel` instead of `cas_gmem_flag_sel`. + * + * Then what we have after is the real content of the G-MEM (Y=DATA). + * Each function's expression is separated from the others by a 0xFF character. + * Casetta's documentation says the data is reversed, I don't know what they + * mean (order? bitwise not?). + * + * There are 90 characters at the end of the content. It seems that they don't + * change if you have one or more Y= function defined (independently of the + * function expression). + * TODO: find out what these are. */ + +# pragma pack() +#endif /* LIBG1M_FORMAT_CAS_GMEM_H */ diff --git a/include/libg1m/format/cas/graph.h b/include/libg1m/format/cas/graph.h new file mode 100644 index 0000000..bb77406 --- /dev/null +++ b/include/libg1m/format/cas/graph.h @@ -0,0 +1,44 @@ +/* ***************************************************************************** + * libg1m/format/cas/graph.h -- description of the CAS graph function format. + * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey + * + * This file is part of libg1m. + * libg1m 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. + * + * libg1m 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 libg1m; if not, see . + * ************************************************************************** */ +#ifndef LIBG1M_FORMAT_CAS_GRAPH_H +# define LIBG1M_FORMAT_CAS_GRAPH_H + +/* This is the data type used for the expression of each function which can be + * used to draw a graph. They are sent when you select 'Y=Data' in the + * transfer menu. + * TODO: find out if these have a CAS40 version. + * + * The length of the graph function is stored in `height`. + * The `name` field is the function type, the type and subtype/equality type. + * The type can be one of these: Y, r, Param, X(constant), Y graph function + * The equ. type can be one of these: =, >, <, >=, <=. + * + * Then, possibly at `prefix` (the doc is unclear about this), you have a + * string like 'GR BL SLD YBL NSGT BL NS': + * - 'GR' means graph function; + * - 'BL' is the color code (BL: blue, OR: orange, GR: green); + * - 'SLD' is whether it's selected or not (SLD: selected, NSD: not selected); + * - 'YBL' is another color code (see previous 'BL'); + * - 'NSGT' indicates presence of a variable? (sometimes SLGT); + * - 'BL' is another color code (see previous 'BL'); + * - 'NS' is linked to 'NSGT' ('NSGT' -> 'NS', 'SLGT' -> 'SL'). + * + * The function is FONTCHARACTER-encoded. */ + +#endif /* LIBG1M_FORMAT_CAS_GRAPH_H */ diff --git a/include/libg1m/format/cas/screenshot.h b/include/libg1m/format/cas/picture.h similarity index 90% rename from include/libg1m/format/cas/screenshot.h rename to include/libg1m/format/cas/picture.h index 0660c58..27b8125 100644 --- a/include/libg1m/format/cas/screenshot.h +++ b/include/libg1m/format/cas/picture.h @@ -1,5 +1,5 @@ /* ***************************************************************************** - * libg1m/format/cas/screenshot.h -- description of the CAS screenshot format. + * libg1m/format/cas/picture.h -- description of the CAS picture format. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -16,8 +16,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with libg1m; if not, see . * ************************************************************************** */ -#ifndef LIBG1M_FORMAT_CAS_SCREENSHOT_H -# define LIBG1M_FORMAT_CAS_SCREENSHOT_H +#ifndef LIBG1M_FORMAT_CAS_PICTURE_H +# define LIBG1M_FORMAT_CAS_PICTURE_H +# include # pragma pack(1) /* ************************************************************************** */ @@ -41,4 +42,4 @@ struct cas_spe_screenshot { * `g1m_pictureformat_4bit_color` -- see `libg1m/picture.h`. */ # pragma pack() -#endif /* LIBG1M_FORMAT_CAS_SCREENSHOT_H */ +#endif /* LIBG1M_FORMAT_CAS_PICTURE_H */ diff --git a/include/libg1m/format/cas/program.h b/include/libg1m/format/cas/program.h index f800f35..0df58c0 100644 --- a/include/libg1m/format/cas/program.h +++ b/include/libg1m/format/cas/program.h @@ -18,12 +18,11 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_CAS_PROGRAM_H # define LIBG1M_FORMAT_CAS_PROGRAM_H +# include # pragma pack(1) -/* ************************************************************************** */ -/* CAS40 specific header bytes */ -/* ************************************************************************** */ -/* In old CAS headers, the five specific bytes are the following: */ +/* TODO: describe programs to the newcomer. + * The CAS40 specific header is the following: */ # define casiolink_program_stats 0x02 /* store stats data */ # define casiolink_program_matrix 0x04 /* matrix mode */ @@ -39,11 +38,8 @@ struct cas_spe_program { uint8_t _unknown2; }; -/* ************************************************************************** */ -/* Content */ -/* ************************************************************************** */ -/* The content length is given in the CAS50 header/CAS40 specific bytes. - * It is made of multi-byte FONTCHARACTER characters. */ +/* Then the program, using the multi-byte FONTCHARACTER encoding, comes. + * F-MEM (saves of series of commands) are stored like very small programs. */ # pragma pack() #endif /* LIBG1M_FORMAT_CAS_PROGRAM_H */ diff --git a/include/libg1m/format/casemul.h b/include/libg1m/format/casemul.h index b057483..be8b0a0 100644 --- a/include/libg1m/format/casemul.h +++ b/include/libg1m/format/casemul.h @@ -18,6 +18,7 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_CASEMUL_H # define LIBG1M_FORMAT_CASEMUL_H +# include # include # pragma pack(1) diff --git a/include/libg1m/format/fxi.h.draft b/include/libg1m/format/fxi.h.draft index 330c901..ae5d1c1 100644 --- a/include/libg1m/format/fxi.h.draft +++ b/include/libg1m/format/fxi.h.draft @@ -18,7 +18,6 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_FXI_H # define LIBG1M_FORMAT_FXI_H -# include # include # pragma pack(1) diff --git a/include/libg1m/format/mcs/cells.h b/include/libg1m/format/mcs/cells.h index 251e119..370a3cd 100644 --- a/include/libg1m/format/mcs/cells.h +++ b/include/libg1m/format/mcs/cells.h @@ -18,6 +18,7 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_MCS_CELLS_H # define LIBG1M_FORMAT_MCS_CELLS_H +# include # include # pragma pack(1) diff --git a/include/libg1m/format/mcs/picture.h b/include/libg1m/format/mcs/picture.h index 2b212f3..ddbeb03 100644 --- a/include/libg1m/format/mcs/picture.h +++ b/include/libg1m/format/mcs/picture.h @@ -18,6 +18,7 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_MCS_PICTURE_H # define LIBG1M_FORMAT_MCS_PICTURE_H +# include # pragma pack(1) /* Captures start with a simple header: */ diff --git a/include/libg1m/format/mcs/program.h b/include/libg1m/format/mcs/program.h index 82573bf..09bf9d5 100644 --- a/include/libg1m/format/mcs/program.h +++ b/include/libg1m/format/mcs/program.h @@ -18,7 +18,8 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_MCS_PROGRAM_H # define LIBG1M_FORMAT_MCS_PROGRAM_H -# include +# include +# include # pragma pack(1) /* Programs have a simple header: */ diff --git a/include/libg1m/format/mcs/spreadsheet.h b/include/libg1m/format/mcs/spreadsheet.h index c85b14a..eaff23e 100644 --- a/include/libg1m/format/mcs/spreadsheet.h +++ b/include/libg1m/format/mcs/spreadsheet.h @@ -18,6 +18,7 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_MCS_SPREADSHEET_H # define LIBG1M_FORMAT_MCS_SPREADSHEET_H +# include # include # pragma pack(1) diff --git a/include/libg1m/format/std/eact.h b/include/libg1m/format/std/eact.h index 579f486..a0aa320 100644 --- a/include/libg1m/format/std/eact.h +++ b/include/libg1m/format/std/eact.h @@ -19,6 +19,7 @@ #ifndef LIBG1M_FORMAT_STD_EACT_H # define LIBG1M_FORMAT_STD_EACT_H # include +# pragma pack(1) /* E-Activities are the format CASIO uses for in-calc documents. * It is the funniest subformat the the libg1m can parse. @@ -131,4 +132,5 @@ struct line_descriptor { * * Which means in each node, there can be a content to parse. */ +# pragma pack() #endif /* LIBG1M_FORMAT_STD_EACT_H */ diff --git a/include/libg1m/format/std/fkey.h b/include/libg1m/format/std/fkey.h index 0b61fcb..5321756 100644 --- a/include/libg1m/format/std/fkey.h +++ b/include/libg1m/format/std/fkey.h @@ -18,7 +18,7 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_STD_FKEY_H # define LIBG1M_FORMAT_STD_FKEY_H -# include +# include # pragma pack(1) /* Function keys are the little boxes at the bottom with text in it, to tell diff --git a/include/libg1m/format/std/lang.h b/include/libg1m/format/std/lang.h index 261a48d..6748bd9 100644 --- a/include/libg1m/format/std/lang.h +++ b/include/libg1m/format/std/lang.h @@ -18,7 +18,7 @@ * ************************************************************************** */ #ifndef LIBG1M_FORMAT_STD_LANG_H # define LIBG1M_FORMAT_STD_LANG_H -# include +# include # pragma pack(1) /* ************************************************************************** */ diff --git a/include/libg1m/mcs.h b/include/libg1m/mcs.h index ce06dce..70dbd97 100644 --- a/include/libg1m/mcs.h +++ b/include/libg1m/mcs.h @@ -77,8 +77,8 @@ typedef unsigned int g1m_mcsinfo_t; g1m_mcstype_list | g1m_mcstype_mat | g1m_mcstype_vct | \ g1m_mcstype_pict | g1m_mcstype_capt | g1m_mcstype_string) || \ ((H)->type == g1m_mcstype_var && (H)->count == 1))) -# define g1m_get_id_major(I) ((I) >> 5) -# define g1m_get_id_minor(I) ((I) & 31) +# define g1m_get_id_major(I) ((I) >> 6) +# define g1m_get_id_minor(I) ((I) & 0x3F) /* ************************************************************************** */ /* Helpers */ /* ************************************************************************** */ diff --git a/src/decode/cas.c b/src/decode/cas.c index a51f796..f085060 100644 --- a/src/decode/cas.c +++ b/src/decode/cas.c @@ -22,10 +22,17 @@ #include #define FUNC(NAME) g1m_decode_caspart_##NAME #define HFUNC(NAME) g1m_decode_cashpart_##NAME +#define READGSIZE() if (grc) { \ + uint16_t size; READ(&size, 2) \ + log_info("GraphCard next buffer size was: 0x%04X", be16toh(size)); } #define READCOLON() { \ + READGSIZE() \ uint8_t colon; GREAD(&colon, 1) \ err = g1m_error_magic; \ - if (colon != ':') goto fail; } + if (colon != ':') { \ + log_error("Expected ':', got '%c' (0x%02X)", colon, colon); \ + goto fail; \ + }} /* ************************************************************************** */ /* Type correspondance list */ @@ -83,7 +90,7 @@ static void *lookup_cas_decode(g1m_mcstype_t type, int heads) * Decode a CASIOLINK Protocol header. * * @arg head the head to fill. - * @arg hd the header. + * @arg buffer the buffer to read from. * @arg csum the current checksum. * @return if there was an error, or not. */ @@ -98,10 +105,15 @@ static int decode_cas50(g1m_mcshead_t *head, g1m_buffer_t *buffer, uint8_t csum) /* check the checksum */ csum += g1m_checksum8(&hd, sizeof(struct _cas50) - 1); - if (~csum + 1 != hd.checksum) + csum = ~csum + 1; + if (csum != hd.checksum) { + log_error("Checksum mismatch: expected 0x%02X, got 0x%02X", + hd.checksum, csum); return (g1m_error_checksum); + } /* copy the basic information */ + g1m_maketype_cas(head, (char*)hd.data); head->size = be16toh(hd.height) - 2 /* checksum, colon */; char *end = memchr(hd.name, 0xFF, 8); size_t len = end ? (size_t)(end - (char*)hd.name) : 8; @@ -238,10 +250,10 @@ int g1m_decode_casfile_part(g1m_mcsfile_t *file, g1m_buffer_t *buffer) } /* ************************************************************************** */ -/* File decoding function */ +/* Main file decoding function */ /* ************************************************************************** */ /** - * g1m_decode_cas: + * decode_cas: * Decode a CAS file. * * Is also sort of a guide for using the CAS MCS files. @@ -249,16 +261,20 @@ int g1m_decode_casfile_part(g1m_mcsfile_t *file, g1m_buffer_t *buffer) * * @arg h the handle to create. * @arg buffer the buffer to read from. + * @arg grc is a graphcard file. * @return the libg1m error. */ -int g1m_decode_cas(g1m_handle_t **h, g1m_buffer_t *buffer) +static int decode_cas(g1m_handle_t **h, g1m_buffer_t *buffer, int grc) { /* make the handle */ int err = g1m_make_mcs(h, 0); if (err) return (err); g1m_handle_t *handle = *h; + /* read first colon */ + if (grc) READCOLON() /* FIXME: read this in graphcard magic? */ + /* read each */ for (handle->count = 0;;) { /* read the head */ @@ -317,6 +333,23 @@ fail: return (err); } +/* ************************************************************************** */ +/* Public decoding functions */ +/* ************************************************************************** */ +/** + * g1m_decode_cas: + * Decode a CAS file. + * + * @arg handle the handle to make. + * @arg buffer the buffer to read from. + * @return the libg1m error. + */ + +int g1m_decode_cas(g1m_handle_t **handle, g1m_buffer_t *buffer) +{ + return (decode_cas(handle, buffer, 0)); +} + /** * g1m_decode_grc: * Decode Graph Card file. @@ -328,7 +361,16 @@ fail: int g1m_decode_grc(g1m_handle_t **handle, g1m_buffer_t *buffer) { - uint8_t intro[2]; READ(intro, 2) /* probably the file count? */ - uint8_t colon; READ(&colon, 1) /* read first colon */ - return (g1m_decode_cas(handle, buffer)); + /* file decoding */ + int err = decode_cas(handle, buffer, 1); + if (err) return (err); + + /* read final size */ + uint16_t final; GREAD(&final, sizeof(uint16_t)) + if (final != 0) return (g1m_error_magic); + return (0); + +fail: + g1m_free(*handle); *handle = NULL; + return (err); } diff --git a/src/decode/cas/cell.c b/src/decode/cas/cell.c index 92faa6c..27745a5 100644 --- a/src/decode/cas/cell.c +++ b/src/decode/cas/cell.c @@ -109,7 +109,7 @@ int g1m_decode_caspart_var(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) unsigned int x, y; int err = decode_cell(buffer, &handle->var, &x, &y); if (err) return (err); - if (x != 0 || y != 0) return (g1m_error_magic); + if (x != 1 || y != 1) return (g1m_error_magic); /* no error! */ handle->head.flags &= ~g1m_mcsflag_unfinished; diff --git a/src/decode/cas/program.c b/src/decode/cas/program.c index 5ab77c2..8d8f163 100644 --- a/src/decode/cas/program.c +++ b/src/decode/cas/program.c @@ -39,8 +39,11 @@ int g1m_decode_cashpart_program(g1m_mcshead_t *head, g1m_mcshead_t *heads, uint8_t checksum; READ(&checksum, 1) uint8_t csum = ~g1m_checksum8(headers, sizeof(struct cas_spe_program) * head->count) + 1; - if (csum != checksum) + if (csum != checksum) { + log_error("Checksum mismatch: expected 0x%02X, got 0x%02X", + csum, checksum); return (g1m_error_checksum); + } /* initialize */ for (int i = 0; i < head->count; i++) { @@ -72,8 +75,11 @@ int g1m_decode_caspart_program(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) /* check the sum */ uint8_t checksum; READ(&checksum, 1) uint8_t csum = ~g1m_checksum8(handle->content, handle->head.size) + 1; - if (csum != checksum) + if (csum != checksum) { + log_error("Checksum mismatch: expected 0x%02X, got 0x%02X", + csum, checksum); return (g1m_error_checksum); + } /* everything went well :) */ handle->head.flags &= ~g1m_mcsflag_unfinished; diff --git a/src/decode/mcs.c b/src/decode/mcs.c new file mode 100644 index 0000000..f05b48d --- /dev/null +++ b/src/decode/mcs.c @@ -0,0 +1,195 @@ +/* ***************************************************************************** + * decode/mcs.c -- decode an MCS file. + * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey + * + * This file is part of libg1m. + * libg1m 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. + * + * libg1m 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 libg1m; if not, see . + * ************************************************************************** */ +#include +#include +#define FUNC(NAME) g1m_decode_mcs_##NAME + +/* ************************************************************************** */ +/* Type correspondance list */ +/* ************************************************************************** */ +/* MCS file parsing function type */ +typedef int (*mcs_decode_func_t)(g1m_mcsfile_t**, g1m_buffer_t*, + g1m_mcshead_t*); + +/* Correspondance type */ +struct mcs_corresp { + unsigned int type; + mcs_decode_func_t decode; +}; + +/* All correspondances */ +#define TTERM {0, NULL} +static struct mcs_corresp mcs_types[] = { + {g1m_mcstype_program, FUNC(program)}, + {g1m_mcstype_list, FUNC(cells)}, + {g1m_mcstype_mat, FUNC(cells)}, + {g1m_mcstype_vct, FUNC(cells)}, + {g1m_mcstype_spreadsheet, FUNC(spreadsheet)}, + {g1m_mcstype_pict, FUNC(picture)}, + {g1m_mcstype_capt, FUNC(capture)}, + {g1m_mcstype_string, FUNC(string)}, + {g1m_mcstype_setup, FUNC(setup)}, + {g1m_mcstype_alphamem, FUNC(var)}, + {g1m_mcstype_variable, FUNC(var)}, + TTERM +}; + +/** + * lookup_mcsfile_decode: + * Lookup for a parsing function for an MCS file type. + * + * @arg type the libg1m MCS file type. + * @return the function (NULL if not found). + */ + +static mcs_decode_func_t lookup_mcsfile_decode(g1m_mcstype_t type) +{ + /* lookup for the type */ + struct mcs_corresp *c = mcs_types; + while (c->decode) { + if (type == c->type) + break; + c++; + } + + /* return the function */ + return (c->decode); +} + +/* ************************************************************************** */ +/* Head decoding function */ +/* ************************************************************************** */ +/** + * g1m_decode_mcsfile_head: + * Decode MCS file head. + * + * @arg head the head to fill. + * @arg raw_type the raw file type. + * @arg groupname the groupname (up to 16 bytes). + * @arg dirname the directory name (up to 8 bytes). + * @arg filename the filename (up to 8 bytes). + * @arg filesize the data length. + * @return 0 if the head was filled with success, -1 otherwise. + */ + +int g1m_decode_mcsfile_head(g1m_mcshead_t *head, + int raw_type, const unsigned char *groupname, + const unsigned char *dirname, const unsigned char *filename, + uint_fast32_t filesize) +{ + /* check that we have a head, lol */ + if (!head) return (-1); + + /* look for the raw type */ + g1m_maketype_mcs(head, (char*)groupname, (char*)dirname, + (char*)filename, raw_type); + head->size = filesize; + log_info("libg1m file type is 0x%08" PRIXMCSTYPE, head->type); +#if LOGLEVEL <= ll_info + if (g1m_mcshead_uses_id(head)) { + log_info("libg1m file id is (%d, %d)", g1m_get_id_major(head->id), + g1m_get_id_minor(head->id)); + } +#endif + + /* everything went well! */ + return (0); +} + +/* ************************************************************************** */ +/* File decoding functions */ +/* ************************************************************************** */ +/** + * g1m_decode_mcsfile: + * Decode MCS file content. + * + * Part of the public API because of the Protocol 7, where file is sent + * without its header (only with specific subheaders). + * + * @arg handle the handle to make. + * @arg head the head to use. + * @arg buffer the buffer to read from. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcsfile(g1m_mcsfile_t **handle, const g1m_mcshead_t *head, + g1m_buffer_t *buffer) +{ + int err = 0; + + /* check that the head is there */ + if (!head) return (g1m_error_op); + g1m_mcshead_t h = *head; + + /* look for the decoding function */ + mcs_decode_func_t decode = lookup_mcsfile_decode(head->type); + if (!decode) { + log_error("No dedicated decoding function for this type was found!"); + goto notparsing; + } + + /* decode */ + if (!head->size) err = (*decode)(handle, buffer, &h); + else { + g1m_buffer_t lbuf = LIMBUFFER(buffer, head->size); + err = (*decode)(handle, &lbuf, &h); + if (lbuf._offset < head->size) SKIP(head->size - lbuf._offset) + } + + /* oh yeah, and go away. */ + if (err) goto fail; + return (0); + +notparsing: + /* allocate enough space */ + if ((err = g1m_make_mcsfile(handle, &h))) + return (err); + + /* read the content */ + GREAD((*handle)->content, h.size) + + /* log */ + log_info("File content:"); + logm_info((*handle)->content, h.size); + + /* saved normally */ + return (0); + +fail: + g1m_free_mcsfile(*handle); + return (err); +} + +/** + * g1m_decode_mcsfile_data: + * Decode a MCS file content from raw memory. + * + * @arg handle the file handle. + * @arg head the file head. + * @arg data the buffer data. + * @arg size the buffer size. + * @return the libg1m error. + */ + +int g1m_decode_mcsfile_data(g1m_mcsfile_t **handle, + const g1m_mcshead_t *head, const unsigned char *data, size_t size) +{ + g1m_buffer_t membuf = MEMBUFFER(data, size); + return (g1m_decode_mcsfile(handle, head, &membuf)); +} diff --git a/src/decode/std/eact.c b/src/decode/std/eact.c index 158c6c5..24f0d15 100644 --- a/src/decode/std/eact.c +++ b/src/decode/std/eact.c @@ -297,13 +297,13 @@ static int eact_decode_line_picture(g1m_line_t *handle, uint8_t *buf, while (*(++p)) *p = be16toh(*p); /* get the size of the multi-byte string */ - size_t sz = fc_wcstombs(NULL, s, 0); + size_t sz = g1m_wcstombs(NULL, s, 0); if (sz == (size_t)-1) return (g1m_error_magic); /* make the string */ handle->content = malloc(sizeof(FONTCHARACTER) * (sz + 1)); if (!handle->content) return (g1m_error_alloc); - fc_wcstombs(handle->content, s, 0); + g1m_wcstombs(handle->content, s, 0); /* don't forget to set the handle type! */ handle->type = g1m_linetype_picture; diff --git a/src/decode/std/mcs.c b/src/decode/std/mcs.c index 7a0d394..74248ea 100644 --- a/src/decode/std/mcs.c +++ b/src/decode/std/mcs.c @@ -18,185 +18,7 @@ * ************************************************************************** */ #include #include -#define FUNC(NAME) g1m_decode_mcs_##NAME -/* ************************************************************************** */ -/* Type correspondance list */ -/* ************************************************************************** */ -/* MCS file parsing function type */ -typedef int (*mcs_decode_func_t)(g1m_mcsfile_t**, g1m_buffer_t*, - g1m_mcshead_t*); - -/* Correspondance type */ -struct mcs_corresp { - unsigned int type; - mcs_decode_func_t decode; -}; - -/* All correspondances */ -#define TTERM {0, NULL} -static struct mcs_corresp mcs_types[] = { - {g1m_mcstype_program, FUNC(program)}, - {g1m_mcstype_list, FUNC(cells)}, - {g1m_mcstype_mat, FUNC(cells)}, - {g1m_mcstype_vct, FUNC(cells)}, - {g1m_mcstype_spreadsheet, FUNC(spreadsheet)}, - {g1m_mcstype_pict, FUNC(picture)}, - {g1m_mcstype_capt, FUNC(capture)}, - {g1m_mcstype_string, FUNC(string)}, - {g1m_mcstype_setup, FUNC(setup)}, - {g1m_mcstype_alphamem, FUNC(var)}, - {g1m_mcstype_variable, FUNC(var)}, - TTERM -}; - -/** - * lookup_mcsfile_decode: - * Lookup for a parsing function for an MCS file type. - * - * @arg type the libg1m MCS file type. - * @return the function (NULL if not found). - */ - -static mcs_decode_func_t lookup_mcsfile_decode(g1m_mcstype_t type) -{ - /* lookup for the type */ - struct mcs_corresp *c = mcs_types; - while (c->decode) { - if (type == c->type) - break; - c++; - } - - /* return the function */ - return (c->decode); -} - -/* ************************************************************************** */ -/* Head decoding function */ -/* ************************************************************************** */ -/** - * g1m_decode_mcsfile_head: - * Decode MCS file head. - * - * @arg head the head to fill. - * @arg raw_type the raw file type. - * @arg groupname the groupname (up to 16 bytes). - * @arg dirname the directory name (up to 8 bytes). - * @arg filename the filename (up to 8 bytes). - * @arg filesize the data length. - * @return 0 if the head was filled with success, -1 otherwise. - */ - -int g1m_decode_mcsfile_head(g1m_mcshead_t *head, - int raw_type, const unsigned char *groupname, - const unsigned char *dirname, const unsigned char *filename, - uint_fast32_t filesize) -{ - /* check that we have a head, lol */ - if (!head) return (-1); - - /* look for the raw type */ - g1m_maketype_mcs(head, (char*)groupname, (char*)dirname, - (char*)filename, raw_type); - head->size = filesize; - log_info("libg1m file type is 0x%08" PRIXMCSTYPE, head->type); -#if LOGLEVEL <= ll_info - if (g1m_mcshead_uses_id(head)) { - log_info("libg1m file id is (%d, %d)", g1m_get_id_major(head->id), - g1m_get_id_minor(head->id)); - } -#endif - - /* everything went well! */ - return (0); -} - -/* ************************************************************************** */ -/* File decoding functions */ -/* ************************************************************************** */ -/** - * g1m_decode_mcsfile: - * Decode MCS file content. - * - * Part of the public API because of the Protocol 7, where file is sent - * without its header (only with specific subheaders). - * - * @arg handle the handle to make. - * @arg head the head to use. - * @arg buffer the buffer to read from. - * @return the error code (0 if ok). - */ - -int g1m_decode_mcsfile(g1m_mcsfile_t **handle, const g1m_mcshead_t *head, - g1m_buffer_t *buffer) -{ - int err = 0; - - /* check that the head is there */ - if (!head) return (g1m_error_op); - g1m_mcshead_t h = *head; - - /* look for the decoding function */ - mcs_decode_func_t decode = lookup_mcsfile_decode(head->type); - if (!decode) { - log_error("No dedicated decoding function for this type was found!"); - goto notparsing; - } - - /* decode */ - if (!head->size) err = (*decode)(handle, buffer, &h); - else { - g1m_buffer_t lbuf = LIMBUFFER(buffer, head->size); - err = (*decode)(handle, &lbuf, &h); - if (lbuf._offset < head->size) SKIP(head->size - lbuf._offset) - } - - /* oh yeah, and go away. */ - if (err) goto fail; - return (0); - -notparsing: - /* allocate enough space */ - if ((err = g1m_make_mcsfile(handle, &h))) - return (err); - - /* read the content */ - GREAD((*handle)->content, h.size) - - /* log */ - log_info("File content:"); - logm_info((*handle)->content, h.size); - - /* saved normally */ - return (0); - -fail: - g1m_free_mcsfile(*handle); - return (err); -} - -/** - * g1m_decode_mcsfile_data: - * Decode a MCS file content from raw memory. - * - * @arg handle the file handle. - * @arg head the file head. - * @arg data the buffer data. - * @arg size the buffer size. - * @return the libg1m error. - */ - -int g1m_decode_mcsfile_data(g1m_mcsfile_t **handle, - const g1m_mcshead_t *head, const unsigned char *data, size_t size) -{ - g1m_buffer_t membuf = MEMBUFFER(data, size); - return (g1m_decode_mcsfile(handle, head, &membuf)); -} - -/* ************************************************************************** */ -/* Main file function */ -/* ************************************************************************** */ /** * g1m_decode_std_mcs: * Decode an MCS file, after the Standard Header. diff --git a/src/manage/mcsfile.c b/src/manage/mcsfile.c index f7610bf..96e3fd4 100644 --- a/src/manage/mcsfile.c +++ b/src/manage/mcsfile.c @@ -115,8 +115,7 @@ int g1m_make_mcsfile(g1m_mcsfile_t **handle, const g1m_mcshead_t *rawhead) /* finish */ return (0); fail: - free(h); - *handle = NULL; + free(*handle); *handle = NULL; return (g1m_error_alloc); } diff --git a/src/type/cas/app.c b/src/type/cas/app.c index 7a2ba53..6b36f4c 100644 --- a/src/type/cas/app.c +++ b/src/type/cas/app.c @@ -34,6 +34,9 @@ struct ext_corresp { /* identification */ int value; + /* things */ + g1m_mcsinfo_t info; + /* app correspondances */ struct app_corresp *apps; }; @@ -47,7 +50,7 @@ struct ext_corresp { #define ETERM {NULL} static struct ext_corresp apps[] = { /* CFX-9850G headers (very first headers with this extension system?) */ - {casdyn_ext_9850, (struct app_corresp[]){ + {casdyn_ext_9850, g1m_mcsinfo_cas50, (struct app_corresp[]){ {"TXT"}, /* editor */ {"VAL"}, /* RUN? */ {"IMG"}, /* screen shooter? */ @@ -55,15 +58,15 @@ static struct ext_corresp apps[] = { ETERM }}, - /* some sort of format only used with the END packet, I suppose? */ - {casdyn_ext_end, (struct app_corresp[]){ + /* CFX-9850G header alias, used with the END packet only */ + {casdyn_ext_end, g1m_mcsinfo_cas50, (struct app_corresp[]){ {"END"}, /* end packet... used in the same period than 9850G packets? */ ETERM }}, /* Graph 100 (Algebra FX) headers */ - {casdyn_ext_g100, (struct app_corresp[]){ + {casdyn_ext_g100, g1m_mcsinfo_cas100, (struct app_corresp[]){ {"ADN"}, /* ? */ {"MCS"}, /* ? */ {"MDL"}, /* model info? */ @@ -73,7 +76,7 @@ static struct ext_corresp apps[] = { }}, /* sentinel */ - {0, NULL} + {0, 0, NULL} }; /* ************************************************************************** */ @@ -109,7 +112,8 @@ int g1m_maketype_casapp(g1m_mcshead_t *head, /* copy raw information */ memset(head, 0, sizeof(g1m_mcshead_t)); - head->info = g1m_mcsinfo_graph100; /* FIXME */ + head->info = e->info; /* FIXME */ + log_info("Head info is 0x%04X", e->info); strncpy((char*)head->_appname, app, 3); head->_appname[3] = 0; diff --git a/src/type/cas/datatype.c b/src/type/cas/datatype.c index c98e191..e9d0e5d 100644 --- a/src/type/cas/datatype.c +++ b/src/type/cas/datatype.c @@ -58,30 +58,28 @@ static struct type_corresp cas_groups[] = { /* programs */ {"P", arg | arg_is_num, g1m_mcstype_program, 0}, - {"PZ", mult | noarg, g1m_mcstype_program, 0}, + {"PZ", mult | noarg, g1m_mcstype_program, 0}, /* 38 programs: 0-9,A-Z,... */ /* captures */ CAPT("DC", g1m_pictureformat_4bit_color), CAPT("DD", g1m_pictureformat_4bit_mono), - /* not implemented yet */ + /* decoding is being implemented */ + UNIMPLEMENTED("GF"), /* graph zoom factor (graph function?) */ UNIMPLEMENTED("AA"), /* dynamic graph functions */ + UNIMPLEMENTED("BU"), /* backup */ + + /* not implemented yet */ UNIMPLEMENTED("AD"), /* variable memory */ UNIMPLEMENTED("AL"), /* all */ UNIMPLEMENTED("AM"), /* alpha variable memory */ - UNIMPLEMENTED("BU"), /* backup */ UNIMPLEMENTED("DM"), /* defined memory */ UNIMPLEMENTED("EN"), /* one editor file */ - UNIMPLEMENTED("FN"), /* set of editor files */ UNIMPLEMENTED("FT"), /* ??? (cafix) */ UNIMPLEMENTED("F1"), /* one function memory */ - UNIMPLEMENTED("F6"), /* set of function memories */ - UNIMPLEMENTED("GA"), /* set of graph functions */ - UNIMPLEMENTED("GF"), /* graph zoom factor (graph function?) */ UNIMPLEMENTED("GM"), /* gmem (cafix) */ UNIMPLEMENTED("GR"), /* graph range */ UNIMPLEMENTED("GT"), /* function table */ - UNIMPLEMENTED("MA"), /* set of matrices */ UNIMPLEMENTED("PC"), /* picture from 9xxx (cafix) */ UNIMPLEMENTED("PD"), /* polynomial equations */ UNIMPLEMENTED("RF"), /* ??? (cafix) */ @@ -94,6 +92,12 @@ static struct type_corresp cas_groups[] = { UNIMPLEMENTED("TR"), /* ??? (cafix) */ UNIMPLEMENTED("WD"), /* window data (cafix) */ + /* sets */ + UNIMPLEMENTED("FN"), /* set of editor files */ + UNIMPLEMENTED("F6"), /* set of function memories */ + UNIMPLEMENTED("GA"), /* set of graph functions */ + UNIMPLEMENTED("MA"), /* set of matrices */ + /* terminating entry */ TTERM }; diff --git a/src/type/mcs.c b/src/type/mcs.c index f38d68a..483220f 100644 --- a/src/type/mcs.c +++ b/src/type/mcs.c @@ -131,14 +131,12 @@ static struct group_corresp mcs_groups[] = { TTERM }}, - /* more or less main memory */ + /* application-specific data */ {"CAPT ", arg | arg_is_num, (struct type_corresp[]){ {0x0A, "CAPT", arg | arg_is_num, "@REV2", "capture", g1m_mcstype_capt}, TTERM }}, - - /* application-specific data */ {"SYSTEM", noarg, (struct type_corresp[]){ {0xFE, NULL /* REPLAY/RUN2D1 */, 0, "@RUNMAT", "replay", 0x00}, @@ -360,7 +358,7 @@ int g1m_maketype_mcs(g1m_mcshead_t *head, && get_number(&fname[fl], &fid, t->flags & arg_is_num)) continue; if (t->flags & weight_by_gid) - fid |= (gid << 5); + fid |= (gid << 6); } break; }