cake
/
libg1m
Archived
1
0
Fork 0

Continued o/

This commit is contained in:
Thomas Touhey 2017-02-25 03:14:52 +01:00
parent 1b5cfee715
commit c10d90ee90
18 changed files with 710 additions and 101 deletions

View File

@ -50,8 +50,9 @@ extern "C" {
# define g1m_noerror 0x00
/* Then, the miscallenous errors */
# define g1m_error_alloc 0x01
# define g1m_error_op 0x02
# define g1m_error_unknown 0x01
# define g1m_error_alloc 0x02
# define g1m_error_op 0x03
/* Then, the stream errors */
# define g1m_error_nostream 0x10
@ -83,17 +84,18 @@ typedef struct g1m_mcs_cell_s {
/* MCS file type */
typedef unsigned int g1m_mcsfile_type_t;
# define g1m_mcstype_unknown 0x000
# define g1m_mcstype_program 0x001
# define g1m_mcstype_list 0x002
# define g1m_mcstype_mat 0x004
# define g1m_mcstype_pict 0x008
# define g1m_mcstype_capt 0x010
# define g1m_mcstype_spreadsheet 0x020
# define g1m_mcstype_string 0x040
# define g1m_mcstype_setup 0x080
# define g1m_mcstype_alphamem 0x100
# define g1m_mcstype_vct 0x200
# define g1m_mcstype_unknown 0x0000
# define g1m_mcstype_program 0x0001
# define g1m_mcstype_list 0x0002
# define g1m_mcstype_mat 0x0004
# define g1m_mcstype_pict 0x0008
# define g1m_mcstype_capt 0x0010
# define g1m_mcstype_spreadsheet 0x0020
# define g1m_mcstype_string 0x0040
# 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
@ -107,24 +109,29 @@ typedef unsigned int g1m_mcsfile_type_t;
# define g1m_get_id_major(I) ((I) >> 5)
# define g1m_get_id_minor(I) ((I) & 31)
/* mcs file head */
typedef struct g1m_mcshead_s {
/* file main information */
unsigned int type;
char name[9]; int id;
/* content size */
uint_fast32_t size;
/* raw data */
unsigned int _rawtype;
unsigned char _group[17], _dirname[9];
} g1m_mcshead_t;
/* mcs file */
# define g1m_has_password(F) (F)->password[0]
# define g1m_remove_password(F) (F)->password[0] = 0
typedef struct g1m_mcsfile_s {
/* file type */
unsigned int type;
/* file name or id */
char name[9];
int id;
/* for unknown files: the group and the directory */
char _group[17];
char _dirname[9];
/* head */
g1m_mcshead_t head;
/* content (useful when not read) */
char *content;
size_t content_size;
/* for programs: the password */
char password[9];
@ -271,11 +278,18 @@ int g1m_open(g1m_t **handle, const char *path,
int g1m_fopen(g1m_t **handle, const char *path, FILE *stream,
g1m_type_t expected_type);
/* open MCS handle (this one is mainly for `libp7`) */
int g1m_decode_mcsfile_content(g1m_mcsfile_t **handle, g1m_buffer_t *buffer,
/* open MCS head/file */
int g1m_decode_mcsfile_head(g1m_mcshead_t *head,
int raw_type, const unsigned char *groupname,
const unsigned char *dirname, const unsigned char *filename,
uint_fast32_t filesize);
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(g1m_mcsfile_t **handle,
const g1m_mcshead_t *head, g1m_buffer_t *buffer);
/* free handles */
void g1m_free(g1m_t *handle);

View File

@ -21,8 +21,42 @@
# include <stdint.h>
# pragma pack(1)
/* Welcome on this new episode of Monster Circus! Today we'll present to you
* something that you might not be able to forget: the G1M format.
/* Welcome on this new episode of the Monster Circus show! Today we'll present
* to you the different formats surrounding CASIO calculators: open or closed,
* legacy or legacy, obfuscated or not, I hope you'll enjoy them as much
* as I don't! */
/* ************************************************************************** */
/* The CASIOLINK (CAS) format */
/* ************************************************************************** */
/* This is the basic file format that CASIO used until around 2004, when the
* fx-9860G (Graph 85) came out. It is linked with the legacy protocol, which
* cannot be implemented with a good management of this format.
*
* All of the useful structures and constants are in the specific header.
* The function to get the libg1m MCS type out of the string types is in
* `libg1m/formatutils.h`. */
# include <libg1m/format/cas.h>
/* ************************************************************************** */
/* The FXI format */
/* ************************************************************************** */
/* fx-Interface, an old but well done proprietary interface by CASIO, has its
* own format: the FXI format. It's an obfuscated format (althrough the
* obfuscation algorithm has been found).
*
* It starts with the following obfuscated string: */
# define FXI_OBF_MAGIC "\x32\x30" "\xF8\xA1"
# define FXI_DEC_MAGIC "\xD5\xD7" "\x1F\x46" "FX-INTERFACE - YELLOW COMPUTING"
/* Followed by loads of zero, then, the content. The description of the rest
* of the format is described in this header: */
# include <libg1m/format/fxi.h>
/* ************************************************************************** */
/* The G1M format */
/* ************************************************************************** */
/* The most recent format is made by CASIO: we call it the G1M format.
*
* This format is used by CASIO with its calculator for storing things
* like add-ins (compiled programs), MCS (main memory saves), and others.

View File

@ -0,0 +1,51 @@
/* *****************************************************************************
* libg1m/format/cas.h -- the 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_CAS_H
# define LIBG1M_FORMAT_CAS_H
# include <libg1m.h>
# include <stdint.h>
# pragma pack(1)
/* The CASIOLINK format is linked to the legacy communication protocol.
* It is basically a MCS file.
*
* The file has two main parts.
* It starts with a header: */
struct casiolink_header {
/* types */
uint8_t type[4];
uint8_t data[4];
/* data length */
uint16_t length;
uint8_t name[8];
/* variable-related data */
uint8_t prefix[8]; /* "Variable"? */
uint8_t real; /* 'R' for real, 'C' for complex */
uint8_t magic; /* 0x0A */
/* alignment */
uint8_t _ffs[21];
uint8_t checksum;
};
# pragma pack()
#endif /* LIBG1M_FORMAT_CAS_H */

View File

@ -0,0 +1,28 @@
/* *****************************************************************************
* libg1m/format/fxi.h -- the FXI 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_FXI_H
# define LIBG1M_FORMAT_FXI_H
# include <libg1m.h>
# include <stdint.h>
# pragma pack(1)
/* TODO, I guess? */
# pragma pack()
#endif

View File

@ -40,4 +40,7 @@ int g1m_mcstype_getlib(const char *groupname, const char *filename,
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);
#endif /* LIBG1M_FORMATUTILS_H */

View File

@ -75,7 +75,7 @@
}
/* ************************************************************************** */
/* Specific parsing functions */
/* Specific decoding functions */
/* ************************************************************************** */
typedef int (g1m_decode_function)(g1m_t*, g1m_buffer_t*,
struct standard_header*);
@ -92,6 +92,9 @@ g1m_decode_function g1m_decode_lang_cg;
g1m_decode_function g1m_decode_fkey;
g1m_decode_function g1m_decode_storage;
/* independant functions */
int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer);
/* others */
int g1m_decode_fkey_cg_content(g1m_t *handle, g1m_buffer_t *buffer,
uint_fast32_t zonesize, uint32_t *pchecksum);

26
src/decode/cafix.c Normal file
View File

@ -0,0 +1,26 @@
/* *****************************************************************************
* decode/cafix.c -- decode a Cafix file.
* 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/>.
*
* Cafix is a free software that communicates with old CASIO calculators using
* the legacy protocol. Its format is documented in the cafix source code,
* and a little by the Casetta project documentation:
* https://casetta.tuxfamily.org/formats/cafix
* ************************************************************************** */
#include <libg1m/internals.h>
/* TODO */

87
src/decode/cas.c Normal file
View File

@ -0,0 +1,87 @@
/* *****************************************************************************
* decode/cas.c -- decode a CASIOLINK file.
* 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/>.
*
* Based on the Casetta project documentation:
* https://casetta.tuxfamily.org/formats/cas
* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* Direct subfile decoding functions */
/* ************************************************************************** */
/**
* g1m_decode_casfile_head:
* Decode the CAS file head.
*
* @arg head the head to decode.
* @arg buffer the buffer to read from.
* @return the error code (0 if ok).
*/
int g1m_decode_casfile_head(g1m_mcshead_t *head, g1m_buffer_t *buffer)
{
/* 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);
/* fill the handle */
memcpy(head->name, hd.name, 8); head->name[8] = 0;
head->size = hd.length;
/* no error! */
return (0);
}
/* ************************************************************************** */
/* File decoding function */
/* ************************************************************************** */
/**
* g1m_decode_cas:
* Decode a CAS file. TODO.
*
* @arg handle the handle to create.
* @arg buffer the buffer to read from.
* @return the libg1m error.
*/
int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer)
{
int err;
g1m_mcshead_t head;
if ((err = g1m_decode_casfile_head(&head, buffer)))
return (err);
return (0);
}

24
src/decode/casemul.c Normal file
View File

@ -0,0 +1,24 @@
/* *****************************************************************************
* decode/casemul.c -- decode a Casemul file.
* 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/>.
*
* Based on the Casetta project documentation:
* https://casetta.tuxfamily.org/formats/casemul
* ************************************************************************** */
#include <libg1m/internals.h>
/* TODO */

25
src/decode/cat.c Normal file
View File

@ -0,0 +1,25 @@
/* *****************************************************************************
* decode/cat.c -- decode a CAT file.
* 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/>.
*
* CAT is a proprietary format by CASIO. It is a text-based format.
* A description of it is available in the Casetta project documentation:
* https://casetta.tuxfamily.org/formats/cat
* ************************************************************************** */
#include <libg1m/internals.h>
/* TODO */

25
src/decode/ctf.c Normal file
View File

@ -0,0 +1,25 @@
/* *****************************************************************************
* decode/ctf.c -- decode the calculator text 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/>.
*
* This format is a community-made, open and documented format. The
* description of it is on CASPRO's website:
* http://www.spiderpixel.co.uk/caspro/ctfindex.html
* ************************************************************************** */
#include <libg1m/internals.h>
/* TODO */

140
src/decode/fxi.c.draft Normal file
View File

@ -0,0 +1,140 @@
/* *****************************************************************************
* decode/fxi.c -- decode a fx-Interface file.
* 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/>.
*
* FXI is the official fx-Interface format. It is an obfuscated, binary format.
* It is partially described in the Casetta project documentation:
* https://casetta.tuxfamily.org/formats/fxi
* ************************************************************************** */
#include <libg1m/internals.h>
#define FREAD(TO, SZ) { \
READ(TO, SZ) \
deobf(TO, SZ); }
#define FDREAD(NAM, TYPE) { \
DREAD(NAM, TYPE) \
obf(&NAM, sizeof(struct TYPE)); }
/* ************************************************************************** */
/* Obfuscation-related functions */
/* ************************************************************************** */
/**
* obf:
* Obfuscate AND de-obfuscate a string.
*
* The formula was found by Lephenixnoir, from Planète Casio, out of an array
* found by Alexis Soulard, from Casioland (with a 14-years time lapse, yay!).
*
* The formula is an involution, which means the obfuscation and
* de-obfuscation is done using the same formula.
*
* @arg s the string to deobfuscate.
* @arg n the string length.
*/
#define deobf(S, N) obf(S, N)
static void obf(unsigned char *s, size_t n)
{
while (n--)
*s++ ^= ~24;
}
/* ************************************************************************** */
/* File header */
/* ************************************************************************** */
static unsigned char header =
"\xD5\xD7\x1F" "f" "FX-INTERFACE - YELLOW COMPUTING"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\x06"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\x07" /* entries total? */
"\0\xFF\xFF" "\0\0\x0F\0"
"CY" "CFXListItem"
"NP\0\0" "\x00" "\0\0\0" "\x00\0" "\x03\0"
"\x15\x18" "\0\0\x00" "\0\x00" "\xA4\xA0"
"\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\x01\x80\0\0" "\x01" "\0\0\0" "\x01\0" "\x03\0"
"\x55\x1A" "\0\0\x04" "\0\x00" "\x5B\x80"
"\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\x01\x80\0\0" "\x02" "\0\0\0" "\x02\0" "\x00\0"
"\x08\x13" "\0\0\x22" "\0\x00" "\x83\x80"
"\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\x01\x80\0\0" "\x03" "\0\0\0" "\x01\0" "\x03\0"
"\x55\x1A" "\0\0\x20" "\0\x00" "\x1F\x81"
"\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\x01\x80\0\0" "\x04" "\0\0\0" "\x02\0" "\x00\0"
"\x08\x13" "\0\0\x21" "\0\x00" "\x83\x80"
"\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\x01\x80\0\0" "\x05" "\0\0\0" "\x00\0" "\x02\0"
"\x58\x10" "\0\0\x1E" "\0\x00" "\xCC\x80"
"\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\x01\x80\0\0" "\x06" "\0\0\0" "\x01\0" "\x00\0"
"\x08\x11" "\0\0\x1E" "\0\x00" "\x83\x80"
"\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
/* from here, it is a real file, SpeedSnk.fxi */
"\x01" /* number of records? */ "\x00"
"\x01\x80\0\0" "\x00" "\0\0\0" "\x02\0" "\x01\0"
"\xBA\x1E" "\0\0\x22" "\0" "\x08" /* >program name size */
"SpeedSnk" "\x83\x80" "\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0" "SpeedSnk"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
/* subheader? */
"\0\0\0\0\0\0\0" "\0\1\0\1" "\0" "\xAF\x12"
/* text file header */
"TXT\0PG\0\0\x12\x81" "SpeedSnk"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"NL" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
/* ... program content */
"\xFF" "\0\0\0\0\0\0"
;

View File

@ -102,7 +102,7 @@ static int mcs_decode_program(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
size_t content_size = length - sizeof(struct mcs_programheader);
log_info("Getting program content (%" PRIuSIZE "o)", content_size);
handle->content = malloc(content_size + 1);
handle->content_size = content_size + 1;
handle->head.size = content_size + 1;
if (!handle->content) return (g1m_error_alloc);
READ(handle->content, content_size);
handle->content[content_size] = 0;
@ -608,7 +608,7 @@ struct mcs_corresp {
/* All correspondances */
static struct mcs_corresp mcs_types[] = {
{g1m_mcstype_program, mcs_decode_program,},
{g1m_mcstype_program, mcs_decode_program},
{g1m_mcstype_list, mcs_decode_list},
{g1m_mcstype_mat, mcs_decode_matrix},
{g1m_mcstype_vct, mcs_decode_matrix},
@ -644,92 +644,125 @@ static mcs_decode_func_t lookup_mcsfile_decode(unsigned int type)
}
/* ************************************************************************** */
/* Public API functions */
/* Public file functions */
/* ************************************************************************** */
/**
* g1m_decode_mcsfile_content:
* g1m_decode_mcsfile_head:
* Decode MCS file head.
*
* @arg head the head to fill.
* @arg raw_type the raw file type.
* @arg groupname the groupname (up to 16 bytes).
* @arg dirname the directory name (up to 8 bytes).
* @arg filename the filename (up to 8 bytes).
* @arg filesize the data length.
* @return 0 if the head was filled with success, -1 otherwise.
*/
int g1m_decode_mcsfile_head(g1m_mcshead_t *head,
int raw_type, const unsigned char *groupname,
const unsigned char *dirname, const unsigned char *filename,
uint_fast32_t filesize)
{
/* check that we have a head, lol */
if (!head) return (-1);
/* look for the raw type */
if (g1m_mcstype_getlib((char*)groupname, (char*)filename, raw_type,
&head->type, &head->id))
head->type = g1m_mcstype_unknown;
log_info("libg1m file type is 0x%04X", head->type);
#if LOGLEVEL <= ll_info
if (g1m_mcstype_uses_id(head->type)) {
log_info("libg1m file id is (%d, %d)", g1m_get_id_major(head->id),
g1m_get_id_minor(head->id));
}
#endif
/* copy the name and size */
memcpy(head->name, filename, 8); head->name[8] = 0;
head->size = filesize;
/* save raw data */
head->_rawtype = raw_type;
memcpy(head->_group, groupname, 16); head->_group[16] = 0;
memcpy(head->_dirname, dirname, 8); head->_dirname[8] = 0;
/* everything went well! */
return (0);
}
/**
* g1m_decode_mcsfile:
* Decode MCS file content.
*
* Part of the public API because of the Protocol 7, where file is sent
* without its header (only with specific subheaders).
*
* @arg handle the handle.
* @arg handle the handle to make.
* @arg head the head to use.
* @arg buffer the buffer to read from.
* @arg raw_type the raw file type.
* @arg groupname the groupname (up to 16 bytes to read).
* @arg dirname the directory name (up to 8 bytes are read).
* @arg filename the filename (up to 8 bytes are read).
* @arg filesize the data length.
* @return the error code (0 if ok).
*/
int g1m_decode_mcsfile_content(g1m_mcsfile_t **handle, g1m_buffer_t *buffer,
int raw_type, const unsigned char *groupname,
const unsigned char *dirname, const unsigned char *filename,
uint_fast32_t filesize)
int g1m_decode_mcsfile(g1m_mcsfile_t **handle, const g1m_mcshead_t *head,
g1m_buffer_t *buffer)
{
int err = 0;
/* check that the head is there */
if (!head) return (g1m_error_op);
/* create handle */
*handle = malloc(sizeof(g1m_mcsfile_t));
if (!handle) return (g1m_error_alloc);
/* save data */
g1m_mcsfile_t *h = *handle;
h->type = 0;
strncpy(h->name, (char*)filename, 8);
memset(h, 0, sizeof(g1m_mcsfile_t));
/* copy raw data */
h->_group[16] = 0; strncpy(h->_group, (char*)groupname, 16);
h->_dirname[8] = 0; strncpy(h->_dirname, (char*)dirname, 8);
h->name[8] = 0; strncpy(h->name, (char*)filename, 8);
/* look for the raw type */
unsigned int type;
if (g1m_mcstype_getlib(h->_group, h->name, raw_type, &type, &h->id))
goto notparsing;
log_info("libg1m file type is 0x%02x", type);
if (g1m_mcstype_uses_id(type)) {
log_info("libg1m file id is (%d, %d)", g1m_get_id_major(h->id),
g1m_get_id_minor(h->id));
}
/* copy the head */
memcpy(&h->head, head, sizeof(g1m_mcshead_t));
/* look for the parsing function */
mcs_decode_func_t decode = lookup_mcsfile_decode(type);
mcs_decode_func_t decode = lookup_mcsfile_decode(head->type);
if (!decode) {
log_error("No dedicated parsing function for this type was found!");
goto notparsing;
}
/* read it */
h->type = type;
strncpy(h->name, (char*)filename, 8);
int err = (*decode)(h, buffer, filesize);
/* decode */
err = (*decode)(h, buffer, head->size);
if (err) goto fail;
/* free if error, and return */
if (err) {
free(*handle);
*handle = NULL;
}
return (err);
/* no error :D */
return (0);
notparsing:
/* allocate enough space */
h->content = malloc(head->size);
err = g1m_error_alloc;
if (!h->content) goto fail;
notparsing:;
/* read the content */
uint8_t buf[filesize];
READ(buf, filesize)
/* save the content */
h->content = malloc(filesize);
if (!h->content) return (g1m_error_alloc);
memcpy(h->content, buf, filesize);
h->content_size = filesize;
GREAD(h->content, head->size)
/* log */
log_info("File content:");
logm_info(h->content, h->content_size);
logm_info(h->content, head->size);
/* saved normally */
return (0);
fail:
if (h) {
if (h->content) free(h->content);
free(h);
}
*handle = NULL;
return (err);
}
/* ************************************************************************** */
/* Main file function */
/* ************************************************************************** */
/**
* g1m_decode_mcs:
* Decode an MCS file, after the Standard Header.
@ -783,11 +816,15 @@ int g1m_decode_mcs(g1m_t *handle, g1m_buffer_t *buffer,
log_info("[%" PRIuFAST32 "] data length is %" PRIu32,
i, fhd.datalength);
/* decode the head */
g1m_mcshead_t head;
g1m_decode_mcsfile_head(&head, fhd.filetype, hd.intname,
fhd.dirname, fhd.filename, fhd.datalength);
/* decode */
handle->files[handle->count] = NULL;
err = g1m_decode_mcsfile_content(&handle->files[handle->count],
buffer, fhd.filetype, hd.intname, fhd.dirname,
fhd.filename, fhd.datalength);
err = g1m_decode_mcsfile(&handle->files[handle->count],
&head, buffer);
if (err) return (err);
handle->count++;
}

26
src/decode/newcat.c Normal file
View File

@ -0,0 +1,26 @@
/* *****************************************************************************
* decode/newcat.c -- decode a Casetta file.
* 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/>.
*
* Newcat is the official format of Casetta. It is inspired from the CASIOLINK
* format (CAS), and it is an open and documented format. The documentation
* is here:
* https://casetta.tuxfamily.org/spec/newcat/newcat.0.3.0.txt
* ************************************************************************** */
#include <libg1m/internals.h>
/* TODO */

View File

@ -50,12 +50,14 @@ void g1m_free_line_content(g1m_line_t *line)
void g1m_free_mcsfile_content(g1m_mcsfile_t *handle)
{
unsigned int type = handle->head.type;
/* free content for unknown files */
if (!handle->type)
if (!type)
free(handle->content);
/* free cells */
if (handle->type & (g1m_mcstype_mat | g1m_mcstype_vct | g1m_mcstype_list
if (type & (g1m_mcstype_mat | g1m_mcstype_vct | g1m_mcstype_list
| g1m_mcstype_spreadsheet)
&& handle->columns && handle->rows) {
free(handle->cells[0]);
@ -63,18 +65,18 @@ void g1m_free_mcsfile_content(g1m_mcsfile_t *handle)
}
/* free the images */
if (handle->type & (g1m_mcstype_pict | g1m_mcstype_capt)) {
if (type & (g1m_mcstype_pict | g1m_mcstype_capt)) {
free(handle->image);
if (handle->type & g1m_mcstype_pict)
if (type & g1m_mcstype_pict)
free(handle->second_image);
}
/* free the vars */
if (handle->type & g1m_mcstype_alphamem)
if (type & g1m_mcstype_alphamem)
free(handle->vars);
/* free the content */
if (handle->type & g1m_mcstype_program)
if (type & g1m_mcstype_program)
free(handle->content);
}

View File

@ -46,8 +46,8 @@ static g1m_mcsfile_t *find_space_for_file(g1m_t *handle,
continue;
}
if ((file->type & type)
&& (id ? file->id == id : !strcmp(file->name, name))) {
if ((file->head.type & type)
&& (id ? file->head.id == id : !strcmp(file->head.name, name))) {
g1m_free_mcsfile_content(file);
pfile = &handle->files[i];
goto found;
@ -71,11 +71,12 @@ static g1m_mcsfile_t *find_space_for_file(g1m_t *handle,
found:;
/* don't forget to copy basic things */
g1m_mcsfile_t *file = *pfile;
if (name) strncpy(file->name, name, 8);
file->id = id;
if (name) strncpy(file->head.name, name, 8);
file->head.id = id;
/* and use mcstype utilities to copy other info */
g1m_mcstype_toraw(type, id, file->name, file->_dirname, file->_group);
g1m_mcstype_toraw(type, id, file->head.name,
(char*)file->head._dirname, (char*)file->head._group);
/* return it */
return (file);
@ -107,9 +108,9 @@ int g1m_putmcs_program(g1m_t *handle, g1m_mcsfile_t **pfile,
if (!file) return (g1m_error_alloc);
/* set content */
file->content_size = strlen(content);
if (!(file->content = malloc(file->content_size))) return (g1m_error_alloc);
memcpy(file->content, content, file->content_size);
file->head.size = strlen(content);
if (!(file->content = malloc(file->head.size))) return (g1m_error_alloc);
memcpy(file->content, content, file->head.size);
/* set password */
if (password) strncpy(file->password, password, 8);

83
src/utils/castype.c Normal file
View File

@ -0,0 +1,83 @@
/* *****************************************************************************
* utils/castypes.c -- get the CAS type and data types out of raw
* identification data.
* 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>
/* ************************************************************************** */
/* Local types */
/* ************************************************************************** */
/* Correspondance type */
struct type_corresp {
/* identification */
const char *rawtype;
const char *rawdata;
/* libg1m MCS file type */
unsigned int type;
};
/* ************************************************************************** */
/* Correspondances */
/* ************************************************************************** */
/* All correspondances. Remarks:
* - Correspondances with a NULL data type means the data type isn't to be
* read. */
#define TTERM {NULL, NULL, 0}
static struct type_corresp cas_groups[] = {
{"TXT", "PG", g1m_mcstype_program},
{"END", NULL, g1m_mcstype_end},
TTERM
};
/* ************************************************************************** */
/* Main functions */
/* ************************************************************************** */
/**
* 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 type[out] the libg1m MCS type.
* @return the error (if any).
*/
int g1m_castype_get(const char *rawtype, const char *data, 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))
continue;
break;
}
if (!c->rawtype) 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);
if (type) *type = 0;
return (1);
}

View File

@ -37,7 +37,7 @@ struct type_corresp {
const char *dirname;
const char *info;
/* libg1m type */
/* libg1m MCS file type */
unsigned int type;
};
@ -283,7 +283,7 @@ int g1m_mcstype_getlib(const char *gname, const char *fname,
notfound:
log_info("Type with '%s' group, '%s' name and 0x%02x type "
"wasn't recognized.", gname, fname, rawtype);
if (type) *type = 0x00;
if (type) *type = 0;
if (id) *id = 0;
return (1);
}