From 7eb6df5ac394cf3b759fb035bc84af69907c1b92 Mon Sep 17 00:00:00 2001 From: "Thomas \"Cakeisalie5\" Touhey" Date: Thu, 23 Mar 2017 20:41:49 +0100 Subject: [PATCH] Made a better job at describing CAS header/part format. --- include/libg1m/format.h | 14 ++- include/libg1m/format/cas.h | 117 ++++++++++++++++--------- include/libg1m/format/cas/cell.h | 48 ++++++++++ include/libg1m/format/cas/program.h | 49 +++++++++++ include/libg1m/format/cas/screenshot.h | 44 ++++++++++ include/libg1m/format/caspro.h | 99 --------------------- include/libg1m/mcs.h | 22 ++--- src/decode/cas.c | 31 +++---- src/decode/cas/cell.c | 117 +++++++++++++++++++++++++ src/decode/cas/program.c | 81 +++++++++++++++++ src/decode/cas/screenshot.c | 45 ++++++++++ src/decode/mcs/matrix.c | 38 -------- src/decode/mcs/picture.c | 32 ------- src/decode/mcs/program.c | 62 ------------- src/decode/mcs/var.c | 39 --------- 15 files changed, 493 insertions(+), 345 deletions(-) create mode 100644 include/libg1m/format/cas/cell.h create mode 100644 include/libg1m/format/cas/program.h create mode 100644 include/libg1m/format/cas/screenshot.h delete mode 100644 include/libg1m/format/caspro.h create mode 100644 src/decode/cas/cell.c create mode 100644 src/decode/cas/program.c create mode 100644 src/decode/cas/screenshot.c diff --git a/include/libg1m/format.h b/include/libg1m/format.h index d04fa30..0b3369f 100644 --- a/include/libg1m/format.h +++ b/include/libg1m/format.h @@ -29,19 +29,15 @@ /* ************************************************************************** */ /* This is the first file format used by the CASIO community; it was * more or less a dump of the communications protocol CASIO used until - * the fx-9860G (Graph 85) was announced, around 2004/2005. - * It was managed by the CaS software, made by Tom Wheeler with the help of - * other people like Tom Lynn. This software was developed around 1997. + * the fx-9860G (Graph 85) came out, around 2004/2005. * - * There is only one protocol, but with two different versions of the headers, - * leading to different CAS file specifications: there is the original header - * format, used on the CFX-9700G (called cas in libg1m), and the newer protocol, - * used on the CFX-9850G (called caspro in libg1m). + * It was mainly managed by the CaS software, made by Tom Wheeler with the help + * of other people like Tom Lynn. This software was developed around 1997. + * Other software did support the CAS protocol, such as cafix or Flash100. * - * Here are the two headers formats: */ + * You can find its description in the following header: */ # include -# include /* ************************************************************************** */ /* The FXI format */ /* ************************************************************************** */ diff --git a/include/libg1m/format/cas.h b/include/libg1m/format/cas.h index 8f677ac..070be1a 100644 --- a/include/libg1m/format/cas.h +++ b/include/libg1m/format/cas.h @@ -21,59 +21,98 @@ # include # pragma pack(1) -/* This is the first CASIOLINK format. It is more or less a raw dump of the - * communications protocol the 9700 uses. It is basically an MCS file. +/* See `libg1m/format.h` for general information about what the CASIOLINK + * format is. * - * A CASIOLINK-encoded file is made of one header and one or more parts. - * Each element is preceded by a 0x3A, and is a packet in the communications - * protocol interpretation. */ + * The CASIOLINK file format is linked to how the legacy (CAS) protocol works: + * one-byte packets are sent between the two machines (for initiating + * communication, ACKing, NAKing, ...), unless the sent/receiving byte is + * the double-colon ':' (0x3A) -- then it is the beginning of something + * that is more than one-byte long. CAS files do not include the one-byte + * packets, or repeated headers/parts (because of bad checksum or timeouts, + * for example). + * + * Actually, there are three main things that start with a ':'. The main type + * is a header, that describes the content that follows. A content can have + * no content part (e.g. END packet), one content part (e.g. programs), or + * more (e.g. width*height content parts for lists and matrixes, which + * represent the individual cells). These content parts have different formats + * according to the global content part. + * + * But I told you there were three things. The third is a little subtle: + * one header can correspond to several contents. Then we have what we + * call the CAS file*s* part (or heads part). + * An example is 'FN' (set of editor files): we receive the main head, + * with the count of editor files that are sent to us, then we receive one part + * indicating the size of each files, then for each file, we receive one part, + * which is the file content. + * + * We have one protocol, the CASIOLINK protocol (also called 'legacy protocol' + * in the libg1m scope), but we have two different type of headers. The two + * have a fixed width, so they are named by the number of bytes they occupy. + * Notice that, for what I know, content formats don't vary between header + * types. The checksuming technique neither. */ /* ************************************************************************** */ -/* Header */ +/* CAS40 header */ /* ************************************************************************** */ -/* The header is the following: */ +/* The first header to have appeared is the CAS40 (40 bytes long). + * It is known in CaS as the protocol the CFX-9700G uses. + * + * The header format is the following: */ -struct cas_header { - uint8_t data[2]; - uint8_t misc[5]; /* type-specific subheader (miscallaneous data) */ +struct cas40 { + uint8_t data[2]; /* data type -- see `type/cas.c`. */ + uint8_t misc[5]; /* type-specific subheader */ uint8_t filename[12]; /* editor filename. */ uint8_t password[12]; /* editor password. */ uint8_t _reserved[7]; /* 0xFFs */ uint8_t checksum; }; -/* For a program, the specific bytes are the following: */ - -# define casiolink_program_stats 0x02 /* store stats data */ -# define casiolink_program_matrix 0x04 /* matrix mode */ -# define casiolink_program_stddev 0x10 /* standard deviation mode */ -# define casiolink_program_linreg 0x20 /* linear regression mode */ -# define casiolink_program_basen 0x40 /* base-n mode */ -# define casiolink_program_drawst 0x80 /* draw stats graph */ - -struct cas_spe_program { - uint8_t _unknown; - uint16_t length; - uint8_t flags; - uint8_t _unknown2; -}; - -/* The specific bytes are the same for a set of programs, but `flags` is - * not used, and the length is the size of all of the programs put together. +/* The specific bytes are different according to the datatype, but its + * length is fixed. */ +/* ************************************************************************** */ +/* CAS50 header */ +/* ************************************************************************** */ +/* The CAS50 (50 bytes long) header appeared later. + * It is known in CaS as the protocol the CFX-9850G uses. * - * Now, here are the specific bytes for a screenshot: */ + * This format was previously named `caspro` in libg1m, before finally + * using the CAS50 name, which was more appropriate. + * Notice that most headers the Graph 100 (~2002) still used CAS40. + * + * The header format is the following: */ -struct cas_spe_screenshot { - uint8_t height; - uint8_t width; - uint8_t _unused[3]; +struct cas50 { + /* types */ + uint8_t type[4]; + uint8_t data[2]; + + /* data length */ + uint16_t width, height; + uint8_t name[8]; + + /* variable-related data */ + uint8_t prefix[8]; /* "Variable" for vars, 0xFFs otherwise */ + uint8_t aux[8]; /* variable: "R\x0A"/"C\x0A", editor: password */ + + /* something else (?) */ + uint8_t nl[2]; /* 'NL'? */ + uint8_t _reserved[12]; + + /* end of packet */ + uint8_t checksum; }; -/* The specific bytes for a number start with either "RA" or "CA", 'R' or 'C' - * meaning the number is complex or not. */ -/* ************************************************************************** */ -/* Content (parts) */ -/* ************************************************************************** */ -/* TODO */ +/* As you can guess, the two header formats are, in theory, incompatible. + * In practice, anyhow, they more or less are: libg1m reads the first 7 bytes + * from the header, then tried to read a CAS50 header; if it doesn't manage, + * it uses CAS40 as a fallback. + * + * Here are the content formats for the two header types: */ # pragma pack() +# include +# include /* list, matrix, variable */ +# include #endif /* LIBG1M_FORMAT_CAS_H */ diff --git a/include/libg1m/format/cas/cell.h b/include/libg1m/format/cas/cell.h new file mode 100644 index 0000000..8126808 --- /dev/null +++ b/include/libg1m/format/cas/cell.h @@ -0,0 +1,48 @@ +/* ***************************************************************************** + * libg1m/format/cas/cell.h -- description of the CAS cell 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_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. + * Lists are 1*size matrixes. + * TODO: check the specific subheader in CAS40 headers. + * + * There aren't any imaginary parts in matrixes and lists (this wasn't made + * possible until CASIOWIN 2.00, so a long time after). + * + * Each cell is sent as an independent content part, which has the following + * format: + * + * uint16_t y; + * The ordinate of the cell, starting from 1. + * uint16_t x; + * The abscissa of the cell, starting from 1. + * cas_bcd_t real; + * The real part of the variable. + * cas_bcd_t imgn; [ONLY IF REAL PART HAS SPECIAL FLAG SET] + * The imaginary part of the variable. + * uint8_t checksum; + * The checksum (calculated as for the header). + * + * The order is unknown to me yet. (XXX: todo) */ + +# pragma pack() +#endif /* LIBG1M_FORMAT_CAS_SCREENSHOT_H */ diff --git a/include/libg1m/format/cas/program.h b/include/libg1m/format/cas/program.h new file mode 100644 index 0000000..f800f35 --- /dev/null +++ b/include/libg1m/format/cas/program.h @@ -0,0 +1,49 @@ +/* ***************************************************************************** + * libg1m/format/cas/program.h -- description of the CAS program 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_PROGRAM_H +# define LIBG1M_FORMAT_CAS_PROGRAM_H +# pragma pack(1) + +/* ************************************************************************** */ +/* CAS40 specific header bytes */ +/* ************************************************************************** */ +/* In old CAS headers, the five specific bytes are the following: */ + +# define casiolink_program_stats 0x02 /* store stats data */ +# define casiolink_program_matrix 0x04 /* matrix mode */ +# define casiolink_program_stddev 0x10 /* standard deviation mode */ +# define casiolink_program_linreg 0x20 /* linear regression mode */ +# define casiolink_program_basen 0x40 /* base-n mode */ +# define casiolink_program_drawst 0x80 /* draw stats graph */ + +struct cas_spe_program { + uint8_t _unknown; + uint16_t length; + uint8_t flags; + uint8_t _unknown2; +}; + +/* ************************************************************************** */ +/* Content */ +/* ************************************************************************** */ +/* The content length is given in the CAS50 header/CAS40 specific bytes. + * It is made of multi-byte FONTCHARACTER characters. */ + +# pragma pack() +#endif /* LIBG1M_FORMAT_CAS_PROGRAM_H */ diff --git a/include/libg1m/format/cas/screenshot.h b/include/libg1m/format/cas/screenshot.h new file mode 100644 index 0000000..0660c58 --- /dev/null +++ b/include/libg1m/format/cas/screenshot.h @@ -0,0 +1,44 @@ +/* ***************************************************************************** + * libg1m/format/cas/screenshot.h -- description of the CAS screenshot 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_SCREENSHOT_H +# define LIBG1M_FORMAT_CAS_SCREENSHOT_H +# pragma pack(1) + +/* ************************************************************************** */ +/* CAS40 specific header bytes */ +/* ************************************************************************** */ +/* In old CAS headers, the five specific bytes are the following: */ + +struct cas_spe_screenshot { + uint8_t height; + uint8_t width; + uint8_t _unused[3]; +}; + +/* The specific bytes for a number start with either "RA" or "CA", 'R' or 'C' + * meaning the number is complex or not. */ +/* ************************************************************************** */ +/* Content */ +/* ************************************************************************** */ +/* The width and height are given in the CAS50 header/CAS40 specific bytes. + * The picture format is either `g1m_pictureformat_4bit_mono` or + * `g1m_pictureformat_4bit_color` -- see `libg1m/picture.h`. */ + +# pragma pack() +#endif /* LIBG1M_FORMAT_CAS_SCREENSHOT_H */ diff --git a/include/libg1m/format/caspro.h b/include/libg1m/format/caspro.h deleted file mode 100644 index 591a618..0000000 --- a/include/libg1m/format/caspro.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ***************************************************************************** - * libg1m/format/caspro.h -- the newer CAS file format description. - * 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_CASPRO_H -# define LIBG1M_FORMAT_CASPRO_H -# include -# pragma pack(1) - -/* This is the later CASIOLINK format. It is more or less a raw dump of the - * communications protocol the 9850 uses. It is basically an MCS file. - * - * A CASIOLINK-encoded file is made of one header and one or more parts. - * Each element is preceded by a 0x3A, and is a packet in the communications - * protocol interpretation. */ -/* ************************************************************************** */ -/* Header (first element) */ -/* ************************************************************************** */ -/* The header is the following: */ - -struct caspro_header { - /* types */ - uint8_t type[4]; - uint8_t data[3]; - - /* data length */ - uint8_t used; /* 0x00 if is reset/unused, 0x01 if used */ - uint16_t length; /* for a variable: same value as in `used` */ - uint8_t name[8]; - - /* variable-related data */ - uint8_t prefix[8]; /* "Variable" for vars, 0xFFs otherwise */ - uint8_t aux[8]; /* variable: "R\x0A"/"C\x0A", editor: password */ - - /* something else (?) */ - uint8_t nl[2]; /* 'NL'? */ - uint8_t _reserved[12]; - - /* end of packet */ - uint8_t checksum; -}; - -/* ************************************************************************** */ -/* Variable */ -/* ************************************************************************** */ -/* Variable has the following structure (described in a comment): - * - * uint8_t magic[4]; - * Four bytes, always {0x00, 0x01, 0x00, 0x01} for a variable; - * cas_bcd_t real; - * The real part of the variable. - * - * If the real part has the complex flag enabled, then the following is there: - * - * cas_bcd_t imgn; - * The imaginary part of the variable. - * - * Then finally, everytime: - * - * 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() -#endif /* LIBG1M_FORMAT_CASPRO_H */ diff --git a/include/libg1m/mcs.h b/include/libg1m/mcs.h index 05558d9..87a7cfe 100644 --- a/include/libg1m/mcs.h +++ b/include/libg1m/mcs.h @@ -82,20 +82,22 @@ typedef struct g1m_mcs_cell_s { /* ************************************************************************** */ /* Main structures */ /* ************************************************************************** */ -/* mcs file head flags */ +/* mcs file special 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 - * e.g. `head.flags & g1m_mcsmask_info == g1m_mcsinfo_g1m` */ +/* mcs file platform -- what type of raw information is there + * e.g. `g1m_mcsinfo(&head) == g1m_mcsinfo_mcs` */ # define g1m_mcsinfo(H) ((H)->flags & g1m_mcsmask_info) -# define g1m_mcsmask_info 0x0600 +# define g1m_mcsmask_info 0x0F00 # define g1m_mcsinfo_none 0x0000 -# define g1m_mcsinfo_mcs 0x0200 -# define g1m_mcsinfo_cas 0x0400 -# define g1m_mcsinfo_caspro 0x0600 +# define g1m_mcsinfo_mcs 0x0100 +# define g1m_mcsinfo_cas 0x0200 +# define g1m_mcsinfo_caspro 0x0400 + +/* mcs file content flags */ +# define g1m_mcsflag_complex 0x0001 /* is a complex variable */ /* mcs file head */ typedef struct g1m_mcshead_s { @@ -133,8 +135,8 @@ typedef struct g1m_mcsfile_s { char *content; /* variables */ - g1m_mcscell_t var; - g1m_mcscell_t *vars; + g1m_mcscell_t var; + g1m_mcscell_t *vars; g1m_mcscell_t **cells; /* for pictures and captures */ diff --git a/src/decode/cas.c b/src/decode/cas.c index 62b3e38..0a2ddd4 100644 --- a/src/decode/cas.c +++ b/src/decode/cas.c @@ -87,19 +87,19 @@ static void *lookup_cas_decode(g1m_mcstype_t type, int heads) * @return if there was an error, or not. */ -static int decode_caspro_head(g1m_mcshead_t *head, struct caspro_header *hd) +static int decode_caspro_head(g1m_mcshead_t *head, struct cas50 *hd) { /* log the raw header */ - log_info("Raw CASPRO header:"); - logm_info(hd, sizeof(struct caspro_header)); + log_info("Raw CAS50 (CASPRO) header:"); + logm_info(hd, sizeof(struct cas50)); /* check the checksum */ - uint8_t csum = ~g1m_checksum8(hd, sizeof(struct caspro_header) - 1) + 1; + uint8_t csum = ~g1m_checksum8(hd, sizeof(struct cas50) - 1) + 1; if (csum != hd->checksum) return (g1m_error_checksum); /* copy the basic information */ - head->size = be16toh(hd->length) - 2 /* checksum, colon */; + 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; memcpy(head->name, hd->name, len); head->name[len] = 0; @@ -115,17 +115,14 @@ static int decode_caspro_head(g1m_mcshead_t *head, struct caspro_header *hd) log_info("Is a program of %" PRIuFAST32 " bytes", head->size); break; case g1m_mcstype_variable: - if (hd->used) head->flags |= g1m_mcsflag_unfinished; /* 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; + head->height = be16toh(hd->height) & 0xFF; + head->width = be16toh(hd->width) & 0xFF; + head->count = head->height; + if (head->width && head->height) + head->flags |= g1m_mcsflag_unfinished; break; } @@ -150,7 +147,7 @@ int g1m_decode_casfile_head(g1m_mcshead_t *head, g1m_buffer_t *buffer) /* read beginning of the header, try to guess a newer header */ uint8_t buf[49]; READ(buf, 7) - struct caspro_header *phd = (void*)buf; + struct cas50 *phd = (void*)buf; if (!g1m_maketype_caspro(head, (char*)phd->type, (char*)phd->data)) { READ(&buf[7], 42) return (decode_caspro_head(head, phd)); @@ -158,9 +155,9 @@ int g1m_decode_casfile_head(g1m_mcshead_t *head, g1m_buffer_t *buffer) /* check the data type */ READ(&buf[7], 32) - struct cas_header *hd = (void*)buf; - log_info("Raw CAS header:"); - logm_info(hd, sizeof(struct cas_header)); + struct cas40 *hd = (void*)buf; + log_info("Raw CAS40 (CAS) header:"); + logm_info(hd, sizeof(struct cas40)); if (g1m_maketype_cas(head, (char*)hd->data)) return (g1m_error_unrecognized); diff --git a/src/decode/cas/cell.c b/src/decode/cas/cell.c new file mode 100644 index 0000000..92faa6c --- /dev/null +++ b/src/decode/cas/cell.c @@ -0,0 +1,117 @@ +/* ***************************************************************************** + * decode/cas/cell.c -- decode a CAS matrix/list/variable. + * 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 + +/* ************************************************************************** */ +/* Internal function */ +/* ************************************************************************** */ +/** + * decode_cell: + * Read a cell. + * + * @arg buffer the buffer to read from. + * @arg cell the cell to fill. + * @arg x the abscissa of the cell. + * @arg y the ordinate of the cell. + * @return the error code (0 if ok). + */ + +static int decode_cell(g1m_buffer_t *buffer, g1m_mcscell_t *cell, + unsigned int *x, unsigned int *y) +{ + uint8_t csum = 0; + cell->flags = g1m_mcscellflag_used; + + /* read position */ + uint16_t fx, fy; + READ(&fx, sizeof(uint16_t)) *x = be16toh(fx) - 1; + READ(&fy, sizeof(uint16_t)) *y = be16toh(fy) - 1; + csum += g1m_checksum8(&fx, sizeof(uint16_t)); + csum += g1m_checksum8(&fy, sizeof(uint16_t)); + + /* read the parts */ + DREAD(wkg, cas_bcd) + csum += g1m_checksum8(&wkg, sizeof(cas_bcd_t)); + if (g1m_bcd_fromcas(&wkg, &cell->real)) { + READ(&wkg, sizeof(cas_bcd_t)) + csum += g1m_checksum8(&wkg, sizeof(cas_bcd_t)); + g1m_bcd_fromcas(&wkg, &cell->imgn); + } + + /* read and check the checksum */ + uint8_t checksum; READ(&checksum, sizeof(uint8_t)) + if (~csum + 1 != checksum) + return (g1m_error_checksum); + + /* no prob'! */ + return (0); +} + +/* ************************************************************************** */ +/* Cell-reading CAS part decoding functions */ +/* ************************************************************************** */ +/** + * 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) +{ + /* read the cell */ + g1m_mcscell_t cell; unsigned int y, x; + int err = decode_cell(buffer, &cell, &x, &y); + if (err) return (err); + + /* save the cell (FIXME: secure) */ + handle->cells[y][x] = cell; + + /* check if its the last cell */ + if (y == handle->head.height - 1 + && x == handle->head.width - 1) + handle->head.flags &= ~g1m_mcsflag_unfinished; + + /* no error! */ + return (0); +} + +/** + * g1m_decode_caspart_var: + * Decode a CAS variable 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_var(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) +{ + /* read and save the cell */ + 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); + + /* no error! */ + handle->head.flags &= ~g1m_mcsflag_unfinished; + return (0); +} diff --git a/src/decode/cas/program.c b/src/decode/cas/program.c new file mode 100644 index 0000000..5ab77c2 --- /dev/null +++ b/src/decode/cas/program.c @@ -0,0 +1,81 @@ +/* ***************************************************************************** + * decode/cas/program.c -- decode a CAS program. + * 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 + +/** + * g1m_decode_cashpart_program: + * Decode a CAS heads program part. + * + * @arg head the general head. + * @arg heads the heads to contribute to. + * @arg buffer the buffer to read from. + * @return the error code (0 if ok). + */ + +int g1m_decode_cashpart_program(g1m_mcshead_t *head, g1m_mcshead_t *heads, + g1m_buffer_t *buffer) +{ + /* get content */ + struct cas_spe_program headers[head->count]; + READ(headers, sizeof(struct cas_spe_program) * head->count) + + /* check the sum */ + uint8_t checksum; READ(&checksum, 1) + uint8_t csum = ~g1m_checksum8(headers, + sizeof(struct cas_spe_program) * head->count) + 1; + if (csum != checksum) + return (g1m_error_checksum); + + /* initialize */ + for (int i = 0; i < head->count; i++) { + heads[i].size = be16toh(headers[i].length); + /* program type? */ + } + + /* everything went well :D */ + head->flags &= ~g1m_mcsflag_unfinished; + return (0); +} + +/** + * g1m_decode_caspart_program: + * Decode a CAS program 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_program(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) +{ + /* get content */ + READ(handle->content, handle->head.size) + log_info("Program content is:"); + logm_info(handle->content, handle->head.size); + + /* check the sum */ + uint8_t checksum; READ(&checksum, 1) + uint8_t csum = ~g1m_checksum8(handle->content, handle->head.size) + 1; + if (csum != checksum) + return (g1m_error_checksum); + + /* everything went well :) */ + handle->head.flags &= ~g1m_mcsflag_unfinished; + return (0); +} diff --git a/src/decode/cas/screenshot.c b/src/decode/cas/screenshot.c new file mode 100644 index 0000000..1d2cc28 --- /dev/null +++ b/src/decode/cas/screenshot.c @@ -0,0 +1,45 @@ +/* ***************************************************************************** + * decode/cas/screenshot.c -- decode a CAS screenshot. + * 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 + +/** + * g1m_decode_caspart_capture: + * Decode a CAS picture. + * + * @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_capture(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) +{ + /* read the picture data */ + unsigned int width = handle->head.width, height = handle->head.height; + size_t pic_size = g1m_picturesize_4bit_color(width, height); + uint8_t pic_data[pic_size]; READ(pic_data, pic_size) + + /* decode the picture data */ + int err = g1m_decode_picture(handle->pics[0], handle->head._picformat, + pic_data, width, height); + if (err) { g1m_free_mcsfile(handle); return (err); } + + /* no error */ + handle->head.flags &= ~g1m_mcsflag_unfinished; + return (0); +} diff --git a/src/decode/mcs/matrix.c b/src/decode/mcs/matrix.c index a95b6c1..2386f24 100644 --- a/src/decode/mcs/matrix.c +++ b/src/decode/mcs/matrix.c @@ -104,41 +104,3 @@ 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_mcscell_t){ - .real = bcd, - .imgn = {}, - .flags = g1m_mcscellflag_used - }; - - /* 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/decode/mcs/picture.c b/src/decode/mcs/picture.c index 282fec1..83d4bb3 100644 --- a/src/decode/mcs/picture.c +++ b/src/decode/mcs/picture.c @@ -18,9 +18,6 @@ * ************************************************************************** */ #include -/* ************************************************************************** */ -/* MCS files */ -/* ************************************************************************** */ /** * g1m_decode_mcs_capture: * Decode a capture. @@ -102,32 +99,3 @@ int g1m_decode_mcs_picture(g1m_mcsfile_t **handle, g1m_buffer_t *buffer, /* no error */ return (0); } - -/* ************************************************************************** */ -/* CAS files */ -/* ************************************************************************** */ -/** - * g1m_decode_caspart_capture: - * Decode a CAS picture. - * - * @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_capture(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) -{ - /* read the picture data */ - unsigned int width = handle->head.width, height = handle->head.height; - size_t pic_size = g1m_picturesize_4bit_color(width, height); - uint8_t pic_data[pic_size]; READ(pic_data, pic_size) - - /* decode the picture data */ - int err = g1m_decode_picture(handle->pics[0], handle->head._picformat, - pic_data, width, height); - if (err) { g1m_free_mcsfile(handle); return (err); } - - /* no error */ - handle->head.flags &= ~g1m_mcsflag_unfinished; - return (0); -} diff --git a/src/decode/mcs/program.c b/src/decode/mcs/program.c index 3d61ad2..58499a3 100644 --- a/src/decode/mcs/program.c +++ b/src/decode/mcs/program.c @@ -58,65 +58,3 @@ fail: *handle = NULL; return (err); } - -/** - * g1m_decode_cashpart_program: - * Decode a CAS heads program part. - * - * @arg head the general head. - * @arg heads the heads to contribute to. - * @arg buffer the buffer to read from. - * @return the error code (0 if ok). - */ - -int g1m_decode_cashpart_program(g1m_mcshead_t *head, g1m_mcshead_t *heads, - g1m_buffer_t *buffer) -{ - /* get content */ - struct cas_spe_program headers[head->count]; - READ(headers, sizeof(struct cas_spe_program) * head->count) - - /* check the sum */ - uint8_t checksum; READ(&checksum, 1) - uint8_t csum = ~g1m_checksum8(headers, - sizeof(struct cas_spe_program) * head->count) + 1; - if (csum != checksum) - return (g1m_error_checksum); - - /* initialize */ - for (int i = 0; i < head->count; i++) { - heads[i].size = be16toh(headers[i].length); - /* program type? */ - } - - /* everything went well :D */ - head->flags &= ~g1m_mcsflag_unfinished; - return (0); -} - -/** - * g1m_decode_caspart_program: - * Decode a CAS program 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_program(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) -{ - /* get content */ - READ(handle->content, handle->head.size) - log_info("Program content is:"); - logm_info(handle->content, handle->head.size); - - /* check the sum */ - uint8_t checksum; READ(&checksum, 1) - uint8_t csum = ~g1m_checksum8(handle->content, handle->head.size) + 1; - if (csum != checksum) - return (g1m_error_checksum); - - /* everything went well :) */ - handle->head.flags &= ~g1m_mcsflag_unfinished; - return (0); -} diff --git a/src/decode/mcs/var.c b/src/decode/mcs/var.c index 6cf5edb..0d0ec5b 100644 --- a/src/decode/mcs/var.c +++ b/src/decode/mcs/var.c @@ -53,42 +53,3 @@ int g1m_decode_mcs_var(g1m_mcsfile_t **handle, g1m_buffer_t *buffer, /* no problem, woop woop */ return (0); } - -/** - * g1m_decode_caspart_var: - * Decode a CAS variable 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_var(g1m_mcsfile_t *handle, g1m_buffer_t *buffer) -{ - /* read the magic and real part */ - uint8_t magic[4]; READ(magic, 4) - DREAD(rawreal, cas_bcd) - uint8_t csum = g1m_checksum8(magic, 4) - + g1m_checksum8(&rawreal, sizeof(cas_bcd_t)); - - /* read the imaginary part */ - g1m_bcd_t real, imgn = {}; - if (g1m_bcd_fromcas(&rawreal, &real)) { - DREAD(rawimgn, cas_bcd) - csum += g1m_checksum8(&rawimgn, sizeof(cas_bcd_t)); - g1m_bcd_fromcas(&rawimgn, &imgn); - } - - /* check the checksum */ - uint8_t checksum; READ(&checksum, 1) - if (~csum + 1 != checksum) - return (g1m_error_checksum); - if (memcmp(magic, "\0\1\0\1", 4)) - return (g1m_error_magic); - - /* set the values and return */ - handle->var.real = real; - handle->var.imgn = imgn; - handle->head.flags &= ~g1m_mcsflag_unfinished; - return (0); -}