Made a better job at describing CAS header/part format.
This commit is contained in:
parent
281dec029a
commit
7eb6df5ac3
|
@ -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 <libg1m/format/cas.h>
|
||||
# include <libg1m/format/caspro.h>
|
||||
/* ************************************************************************** */
|
||||
/* The FXI format */
|
||||
/* ************************************************************************** */
|
||||
|
|
|
@ -21,59 +21,98 @@
|
|||
# include <stdint.h>
|
||||
# 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 <libg1m/format/cas/program.h>
|
||||
# include <libg1m/format/cas/cell.h> /* list, matrix, variable */
|
||||
# include <libg1m/format/cas/screenshot.h>
|
||||
#endif /* LIBG1M_FORMAT_CAS_H */
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* *****************************************************************************
|
||||
* libg1m/format/cas/cell.h -- description of the CAS cell format.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#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 */
|
|
@ -0,0 +1,49 @@
|
|||
/* *****************************************************************************
|
||||
* libg1m/format/cas/program.h -- description of the CAS program format.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#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 */
|
|
@ -0,0 +1,44 @@
|
|||
/* *****************************************************************************
|
||||
* libg1m/format/cas/screenshot.h -- description of the CAS screenshot format.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#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 */
|
|
@ -1,99 +0,0 @@
|
|||
/* *****************************************************************************
|
||||
* libg1m/format/caspro.h -- the newer CAS file format description.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#ifndef LIBG1M_FORMAT_CASPRO_H
|
||||
# define LIBG1M_FORMAT_CASPRO_H
|
||||
# include <stdint.h>
|
||||
# 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/* *****************************************************************************
|
||||
* decode/cas/cell.c -- decode a CAS matrix/list/variable.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* 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);
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/* *****************************************************************************
|
||||
* decode/cas/program.c -- decode a CAS program.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/* *****************************************************************************
|
||||
* decode/cas/screenshot.c -- decode a CAS screenshot.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* 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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Reference in New Issue