Corrected CAS management... I should read more before coding.
This commit is contained in:
parent
b0564bb32b
commit
3f000c4f30
|
@ -94,7 +94,8 @@ int g1m_decode_mcsfile(g1m_mcsfile_t **handle,
|
|||
const g1m_mcshead_t *head, g1m_buffer_t *buffer);
|
||||
|
||||
/* open CAS head/file */
|
||||
int g1m_decode_casfile_head(g1m_mcshead_t *head, g1m_buffer_t *buffer);
|
||||
int g1m_decode_casfile_head(g1m_mcshead_t *head,
|
||||
const char *datatype, const char *filename, const char *specific);
|
||||
int g1m_decode_casfile(g1m_mcsfile_t **handle,
|
||||
const g1m_mcshead_t *head, g1m_buffer_t *buffer);
|
||||
|
||||
|
|
|
@ -22,13 +22,57 @@
|
|||
# include <stdint.h>
|
||||
# pragma pack(1)
|
||||
|
||||
/* The CASIOLINK format is linked to the legacy communication protocol.
|
||||
* It is basically a MCS file.
|
||||
/* The CASIOLINK format looks a lot like the legacy communication protocol,
|
||||
* but the two are to distinguish. A CASIOLINK-encoded file is basically
|
||||
* a set of one or more MCS files of the same type.
|
||||
*
|
||||
* The file has two main parts.
|
||||
* The file has two parts, each starting with a 0x3A (':').
|
||||
* It starts with a header: */
|
||||
|
||||
struct casiolink_header {
|
||||
uint8_t data[2];
|
||||
uint8_t _specific[5]; /* type-specific subheader */
|
||||
uint8_t filename[12]; /* unused chars are filled with 0xFFs. */
|
||||
uint8_t _unused[19]; /* 0xFFs. */
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
/* For a program, the specific bytes are the following: */
|
||||
|
||||
# define casiolink_program_uk0 0x01 /* <unknown> */
|
||||
# define casiolink_program_stats 0x02 /* store stats data */
|
||||
# define casiolink_program_matrix 0x04 /* matrix mode */
|
||||
# define casiolink_program_uk1 0x08 /* <unknown */
|
||||
# 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 casiolink_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.
|
||||
*
|
||||
* Now, here are the specific bytes for a screenshot: */
|
||||
|
||||
struct casiolink_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. */
|
||||
|
||||
/* This should be put somewhere else, as it represents the packets in
|
||||
* a legacy protocol communication. (FIXME: maybe the new CAS header?) */
|
||||
|
||||
struct casiolink_new_header {
|
||||
/* types */
|
||||
uint8_t type[4];
|
||||
uint8_t data[4];
|
||||
|
|
|
@ -41,6 +41,6 @@ int g1m_mcstype_toraw(unsigned int type, int id,
|
|||
char *name, char *dirname, char *groupname);
|
||||
|
||||
/* get cas type data */
|
||||
int g1m_castype_get(const char *rawtype, const char *data, unsigned int *type);
|
||||
int g1m_castype_get(const char *datatype, unsigned int *type);
|
||||
|
||||
#endif /* LIBG1M_FORMATUTILS_H */
|
||||
|
|
|
@ -139,6 +139,7 @@ void g1m_free_line_content(g1m_line_t *line);
|
|||
int g1m_skip(g1m_buffer_t *buffer, size_t size, uint_fast32_t *checksum);
|
||||
|
||||
/* Checksum-ing */
|
||||
uint8_t g1m_checksum8(void *mem, size_t size);
|
||||
uint32_t g1m_checksum32(void *mem, size_t size, uint32_t checksum);
|
||||
|
||||
/* File buffer */
|
||||
|
|
|
@ -40,7 +40,6 @@ typedef unsigned int g1m_mcstype_t;
|
|||
# define g1m_mcstype_setup 0x0080
|
||||
# define g1m_mcstype_alphamem 0x0100
|
||||
# define g1m_mcstype_vct 0x0200
|
||||
# define g1m_mcstype_end 0x0400
|
||||
|
||||
/* MCS file type aliases */
|
||||
# define g1m_mcstype_picture g1m_mcstype_pict
|
||||
|
@ -71,7 +70,7 @@ typedef struct g1m_mcs_cell_s {
|
|||
typedef struct g1m_mcshead_s {
|
||||
/* file main information */
|
||||
g1m_mcstype_t type;
|
||||
char name[9]; int id;
|
||||
char name[13]; int id;
|
||||
|
||||
/* content size */
|
||||
uint_fast32_t size;
|
||||
|
|
|
@ -29,36 +29,33 @@
|
|||
* Decode the CAS file head.
|
||||
*
|
||||
* @arg head the head to decode.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg datatype the raw data type (at least 2 bytes).
|
||||
* @arg filename the file name (at least 12 bytes).
|
||||
* @arg specific the specific bytes (at least 5 bytes).
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_casfile_head(g1m_mcshead_t *head, g1m_buffer_t *buffer)
|
||||
int g1m_decode_casfile_head(g1m_mcshead_t *head, const char *datatype,
|
||||
const char *filename, const char *specific)
|
||||
{
|
||||
/* check that the head exists */
|
||||
if (!head) return (-1);
|
||||
|
||||
/* Declare the header */
|
||||
struct casiolink_header hd;
|
||||
uint8_t * const uhd = (void*)&hd;
|
||||
|
||||
/* get the type and datatype */
|
||||
READ(&hd, 8)
|
||||
if (g1m_castype_get((char*)hd.type, (char*)hd.data, &head->type))
|
||||
return (g1m_error_unknown);
|
||||
|
||||
/* finish reading
|
||||
* FIXME: sometimes, packet isn't 49 bytes long! */
|
||||
READ(&uhd[8], 41)
|
||||
|
||||
/* check the sum */
|
||||
uint8_t checksum = 0;
|
||||
for (int i = 0; i < 48; i++) checksum += uhd[i];
|
||||
if (checksum != hd.checksum) return (g1m_error_magic);
|
||||
/* check the data type */
|
||||
if (g1m_castype_get(datatype, &head->type))
|
||||
return (g1m_error_unrecognized);
|
||||
|
||||
/* fill the handle */
|
||||
memcpy(head->name, hd.name, 8); head->name[8] = 0;
|
||||
head->size = hd.length;
|
||||
memset(head->_dirname, 0, 9);
|
||||
memset(head->_group, 0, 17);
|
||||
memcpy(head->name, filename, 12); head->name[12] = 0;
|
||||
|
||||
/* type specific */
|
||||
if (head->type == g1m_mcstype_program) {
|
||||
struct casiolink_spe_program *spe = (void*)specific;
|
||||
head->size = be16toh(spe->length);
|
||||
/* TODO: store flags? */
|
||||
}
|
||||
|
||||
/* no error! */
|
||||
return (0);
|
||||
|
@ -82,8 +79,17 @@ int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
{
|
||||
int err;
|
||||
|
||||
/* read the header */
|
||||
DREAD(hd, casiolink_header)
|
||||
if (g1m_checksum8(&hd, sizeof(struct casiolink_header) - 1) != hd.checksum)
|
||||
return (g1m_error_checksum);
|
||||
|
||||
/* decrypt it */
|
||||
g1m_mcshead_t head;
|
||||
if ((err = g1m_decode_casfile_head(&head, buffer)))
|
||||
if ((err = g1m_decode_casfile_head(&head, (char*)hd.data,
|
||||
(char*)hd.filename, (char*)hd._specific)))
|
||||
return (err);
|
||||
|
||||
/* everything went fine :) */
|
||||
return (0);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
/* Correspondance type */
|
||||
struct type_corresp {
|
||||
/* identification */
|
||||
const char *rawtype;
|
||||
const char *rawdata;
|
||||
const char *datatype;
|
||||
|
||||
/* libg1m MCS file type */
|
||||
unsigned int type;
|
||||
|
@ -39,10 +38,48 @@ struct type_corresp {
|
|||
* - Correspondances with a NULL data type means the data type isn't to be
|
||||
* read. */
|
||||
|
||||
#define TTERM {NULL, NULL, 0}
|
||||
#define TTERM {NULL, 0}
|
||||
static struct type_corresp cas_groups[] = {
|
||||
{"TXT", "PG", g1m_mcstype_program},
|
||||
{"END", NULL, g1m_mcstype_end},
|
||||
/* not implemented yet types, described by Tom Wheeley and Tom Lynn */
|
||||
{"AA", 0}, // dynamic graph functions
|
||||
{"AD", 0}, // variable memory
|
||||
{"AL", 0}, // all
|
||||
{"AM", 0}, // alpha variable memory
|
||||
{"BU", 0}, // backup
|
||||
{"DM", 0}, // defined memory
|
||||
{"DD", 0}, // screenshot
|
||||
{"EN", 0}, // one editor file
|
||||
{"FN", 0}, // set of editor files
|
||||
{"F1", 0}, // one function memory
|
||||
{"F6", 0}, // set of function memories
|
||||
{"GA", 0}, // set of graph functions
|
||||
{"GF", 0}, // graph zoom factor (graph function?)
|
||||
{"GR", 0}, // graph range
|
||||
{"GT", 0}, // function table
|
||||
{"MA", 0}, // set of matrices
|
||||
{"PD", 0}, // polynomial equations
|
||||
{"P1", 0}, // one program
|
||||
{"PZ", 0}, // set of programs
|
||||
{"RT", 0}, // recursion table
|
||||
{"SD", 0}, // simultaneous equations
|
||||
{"SR", 0}, // linear regression data
|
||||
{"SS", 0}, // standard deviation data
|
||||
|
||||
/* not implemented yet types, described in libcafix */
|
||||
{"FT", 0}, // ???
|
||||
{"GM", 0}, // G-Mem?
|
||||
{"LT", 0}, // List
|
||||
{"MT", 0}, // Matrix
|
||||
{"PC", 0}, // Picture
|
||||
{"RF", 0}, // ???
|
||||
{"RR", 0}, // ???
|
||||
{"SE", 0}, // Equation?
|
||||
{"TR", 0}, // ???
|
||||
{"VM", 0}, // Variable (A-Z, etc)
|
||||
{"WD", 0}, // window data
|
||||
|
||||
/* implemented types */
|
||||
{"PG", g1m_mcstype_program},
|
||||
TTERM
|
||||
};
|
||||
|
||||
|
@ -53,31 +90,28 @@ static struct type_corresp cas_groups[] = {
|
|||
* g1m_castype_get:
|
||||
* Get the libg1m MCS type from raw CAS identification data.
|
||||
*
|
||||
* @arg rawtype the raw type string.
|
||||
* @arg data the data type string.
|
||||
* @arg datatype the data type string.
|
||||
* @arg type[out] the libg1m MCS type.
|
||||
* @return the error (if any).
|
||||
*/
|
||||
|
||||
int g1m_castype_get(const char *rawtype, const char *data, unsigned int *type)
|
||||
int g1m_castype_get(const char *datatype, unsigned int *type)
|
||||
{
|
||||
struct type_corresp *c = cas_groups - 1;
|
||||
while ((++c)->rawtype) {
|
||||
if (strncmp(rawtype, c->rawtype, 4))
|
||||
continue;
|
||||
if (c->rawdata && strncmp(data, c->rawdata, 4))
|
||||
while ((++c)->datatype) {
|
||||
if (c->datatype && strncmp(datatype, c->datatype, 4))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (!c->rawtype) goto notfound;
|
||||
if (!c->type) goto notfound;
|
||||
|
||||
/* fill in info and return */
|
||||
if (type) *type = c->type;
|
||||
return (0);
|
||||
|
||||
notfound:
|
||||
log_info("Type with '%.4s' type string and '%.4s' data string "
|
||||
"wasn't recognized.", rawtype, data);
|
||||
log_info("Type with '%.4s' data string was not implemented or not "
|
||||
"recognized.", datatype);
|
||||
if (type) *type = 0;
|
||||
return (1);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* *****************************************************************************
|
||||
* utils/checksum32.c -- make a checksum on 32-bits out of a memory zone.
|
||||
* utils/checksum.c -- checksum utilities.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* This file is part of libg1m.
|
||||
|
@ -18,6 +18,24 @@
|
|||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/**
|
||||
* g1m_checksum8:
|
||||
* Make a simple 8-bit checksum.
|
||||
*
|
||||
* @arg mem the memory zone.
|
||||
* @arg size the memory zone size.
|
||||
* @return the checksum
|
||||
*/
|
||||
|
||||
uint8_t g1m_checksum8(void *mem, size_t size)
|
||||
{
|
||||
uint8_t *m = mem, c = 0;
|
||||
|
||||
while (size--)
|
||||
c += *m++;
|
||||
return (c);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_checksum32:
|
||||
* Make checksums great again.
|
Reference in New Issue