cake
/
libg1m
Archived
1
0
Fork 0

Made a better job at describing CAS header/part format.

This commit is contained in:
Thomas Touhey 2017-03-23 20:41:49 +01:00
parent 281dec029a
commit 7eb6df5ac3
15 changed files with 493 additions and 345 deletions

View File

@ -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 */
/* ************************************************************************** */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

117
src/decode/cas/cell.c Normal file
View File

@ -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);
}

81
src/decode/cas/program.c Normal file
View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}