Corrected comment style, added some Casemul documentation (unfinished)
This commit is contained in:
parent
14831b57f5
commit
160a8427f2
|
@ -35,7 +35,7 @@ typedef int g1m_color_t;
|
|||
# define g1m_color_yellow 0x6
|
||||
# define g1m_color_white 0x7
|
||||
|
||||
/* And some macros to help you out: */
|
||||
/* And some macros to help you out: */
|
||||
# define g1m_marker_color(C) (((C) & 0xf0) >> 4)
|
||||
# define g1m_char_color(C) ((C) & 0xf)
|
||||
# define g1m_character_color(C) g1m_char_color(C)
|
||||
|
|
|
@ -53,6 +53,22 @@
|
|||
|
||||
//# include <libg1m/format/fxi.h>
|
||||
/* ************************************************************************** */
|
||||
/* The Casemul format */
|
||||
/* ************************************************************************** */
|
||||
/* Casemul is a CASIO emulator for Microsoft Windows. It is an old software
|
||||
* which was not updated since 2005. It can import and export other files,
|
||||
* but save its files in its own format, which use the .cas extension
|
||||
* (like the CASIOLINK format, but the two formats are completely different).
|
||||
*
|
||||
* It starts with a four-letter magic string, "ACFS". In fact, it is
|
||||
* "CASF", like in "CasFile", the name of the real header. */
|
||||
|
||||
# define CASEMUL_MAGIC "ACFS"
|
||||
|
||||
/* Discover the rest in its own header: */
|
||||
|
||||
# include <libg1m/format/casemul.h>
|
||||
/* ************************************************************************** */
|
||||
/* The G1M/STD format */
|
||||
/* ************************************************************************** */
|
||||
/* Since around 2004, CASIO has adopted a single "superformat"; we call it
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/* *****************************************************************************
|
||||
* libg1m/format/casemul.h -- the Casemul 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_CASEMUL_H
|
||||
# define LIBG1M_FORMAT_CASEMUL_H
|
||||
# pragma pack(1)
|
||||
|
||||
/* Casemul files are made of an overall header, a source part and an
|
||||
* optional compiled part. One thing to know is that every header has an
|
||||
* internal header, which always has this structure: */
|
||||
|
||||
struct casemul_internal_header {
|
||||
/* this type was made using `MAKELONG`: you have to reverse the bytes in
|
||||
* each word (e.g. AC-FS -> CA-SF). */
|
||||
char type[4];
|
||||
|
||||
/* version (more or less 0xMMmm, where MM is the major and mm the minor) */
|
||||
uint32_t version;
|
||||
|
||||
/* header size */
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
/* The multi-byte values are always little-endian, expected from the
|
||||
* values made with `MAKELONG` (like the internal header type, which, in the
|
||||
* source, is a DWORD), because its funnier. */
|
||||
|
||||
|
||||
/* TODO: The separator between header and source header:
|
||||
* "\xFD\xB1\x7E" "\0\0\0\0\0\0\0"
|
||||
* "\x18" "\0\0\0\0\0\0\0"
|
||||
*/
|
||||
/* ************************************************************************** */
|
||||
/* Overall, source and compiled headers */
|
||||
/* ************************************************************************** */
|
||||
/* The overall header contains information about the other sections, and the
|
||||
* current state of the file (whether it contains the compiled part or not).
|
||||
*
|
||||
* Its internal header ID is "CAFS" (ACFS, used as the magic string).
|
||||
* The expected version is 1.00. */
|
||||
|
||||
# define casemul_compiled 0x80 /* if the compiled program is there */
|
||||
struct casemul_header {
|
||||
/* the flags */
|
||||
uint8_t flags;
|
||||
|
||||
/* offset of the sources */
|
||||
uint32_t source_offset;
|
||||
|
||||
/* compiled program offset */
|
||||
uint32_t compiled_offset;
|
||||
|
||||
/* some alignment? */
|
||||
uint8_t _align[3];
|
||||
};
|
||||
|
||||
/* At the beginning of the source part, we find the source header.
|
||||
* The source part contains the programs, pictures, matrixes and lists as four
|
||||
* blocks, uncompiled.
|
||||
*
|
||||
* Its internal header ID is "SRCE" (RSEC).
|
||||
* The expected version is 1.00. */
|
||||
|
||||
struct casemul_source_header {
|
||||
/* number of program records in the program block */
|
||||
uint8_t programs;
|
||||
|
||||
/* number of picture records in the program block */
|
||||
uint8_t pictures;
|
||||
|
||||
/* number of matrix records in the program block */
|
||||
uint8_t matrixes;
|
||||
|
||||
/* number of list records in the list block */
|
||||
uint8_t lists;
|
||||
|
||||
/* program block offset */
|
||||
uint32_t programs_offset;
|
||||
|
||||
/* picture block offset (length of the file before) */
|
||||
uint32_t pictures_offset;
|
||||
|
||||
/* matrix block offset */
|
||||
uint32_t matrixes_offset;
|
||||
|
||||
/* list block offset */
|
||||
uint32_t list_offset;
|
||||
|
||||
/* main program ID */
|
||||
uint8_t program_id;
|
||||
|
||||
/* alignment */
|
||||
uint8_t _align[3];
|
||||
};
|
||||
|
||||
/* At the beginning of the compiled part, we find the compiled header.
|
||||
* The compilation process is unknown (yet to read the sources to find out
|
||||
* what it is).
|
||||
*
|
||||
* Its internal header ID is "COMP" (OCPM).
|
||||
* The expected version is 1.00. */
|
||||
|
||||
struct casemul_comp_header {
|
||||
/* the number of instructions (size of the part) */
|
||||
uint32_t instructions_count;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Record */
|
||||
/* ************************************************************************** */
|
||||
/* For each element, there is record, with a header and a subheader. The
|
||||
* record header cannot easily be expressed as a structure, so here it is, in
|
||||
* the form of a comment:
|
||||
*
|
||||
* uint32_t name_length;
|
||||
* The name length.
|
||||
* uint8_t name[name_length];
|
||||
* The name.
|
||||
* uint32_t length;
|
||||
* The subheader+data length.
|
||||
*
|
||||
* Then expect an internal header, part of the subheader, that expresses the
|
||||
* type of it (expected version for all of them is 1.00). */
|
||||
/* ************************************************************************** */
|
||||
/* Program */
|
||||
/* ************************************************************************** */
|
||||
/* A program has type "PROG" (RPGO). Its subheader is the following: */
|
||||
|
||||
struct casemul_prog_header {
|
||||
/* program length after Casemul encoding */
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
/* Casemul makes use of tokens instead of FONTCHARACTERs or Unicode - this
|
||||
* should be documented in the FONTCHARACTER reference. */
|
||||
/* ************************************************************************** */
|
||||
/* Picture */
|
||||
/* ************************************************************************** */
|
||||
/* A picture has type "PICT" (IPTC), and has the following subheader: */
|
||||
|
||||
struct casemul_pict_header {
|
||||
/* size */
|
||||
uint8_t w, h;
|
||||
|
||||
/* ... aaaaand alignment. (you know, unchecked theory?) */
|
||||
uint8_t _align[2];
|
||||
};
|
||||
|
||||
/* Also, pixels are organized per _column_; this comes from the original code:
|
||||
*
|
||||
* BYTE m_TabPixels[DATAPICTURE_CX][DATAPICTURE_CY];
|
||||
*
|
||||
* Notice that DATAPICTURE_CX and DATAPICTURE_CY are actually macros,
|
||||
* which means there are always 128x64 pixels (or at least that Casemul
|
||||
* will only be able to open 128x64 pictures)... */
|
||||
/* ************************************************************************** */
|
||||
/* Matrix */
|
||||
/* ************************************************************************** */
|
||||
/* A matrix has type "MTRX" (TMXR) and its its subheader has the following
|
||||
* structure: */
|
||||
|
||||
struct casemul_mtrx_header {
|
||||
/* number of lines and columns
|
||||
* actually int-s in the original code... */
|
||||
uint32_t lines, columns;
|
||||
};
|
||||
|
||||
/* TODO: describe the matrix format more precisely. */
|
||||
/* ************************************************************************** */
|
||||
/* List */
|
||||
/* ************************************************************************** */
|
||||
/* A list has type "LIST" (ILTS) and has the following subheader structure: */
|
||||
|
||||
struct casemul_list_header {
|
||||
/* number of lines
|
||||
* actually int-s in the original code... */
|
||||
uint32_t lines;
|
||||
};
|
||||
|
||||
/* TODO: describe the list format more precisely. */
|
||||
|
||||
# pragma pack()
|
||||
#endif /* LIBG1M_FORMAT_CASEMUL_H */
|
|
@ -21,12 +21,12 @@
|
|||
# include <stdint.h>
|
||||
# pragma pack(1)
|
||||
|
||||
/* Add-ins are compiled programs. They only have one G1M part,
|
||||
* These add-ins usually have the `g1a`, `g3a` or `c1a` extension. */
|
||||
/* Add-ins are compiled programs. They only have one G1M part,
|
||||
* These add-ins usually have the `g1a`, `g3a` or `c1a` extension. */
|
||||
/* ************************************************************************** */
|
||||
/* Legacy fx systems add-ins (G1A) */
|
||||
/* ************************************************************************** */
|
||||
/* G1A subheader is the following: */
|
||||
/* G1A subheader is the following: */
|
||||
|
||||
# define G1A_ICON_WIDTH 30
|
||||
# define G1A_ICON_HEIGHT 17
|
||||
|
@ -76,15 +76,15 @@ struct g1a_subheader {
|
|||
uint8_t _spacing7[0xc];
|
||||
};
|
||||
|
||||
/* Then the G1A file will just contain the add-in code and stop. */
|
||||
/* Then the G1A file will just contain the add-in code and stop. */
|
||||
/* ************************************************************************** */
|
||||
/* Classpad and Prizm add-ins (C1A, G3A) */
|
||||
/* ************************************************************************** */
|
||||
/* The two formats are identified the same way in the standard header, but
|
||||
* some of the header parts are different, until the header just stops being
|
||||
* the same.
|
||||
/* The two formats are identified the same way in the standard header, but
|
||||
* some of the header parts are different, until the header just stops being
|
||||
* the same.
|
||||
*
|
||||
* Here's the common parts of their headers: */
|
||||
* Here's the common parts of their headers: */
|
||||
|
||||
struct addin_cp_subheader {
|
||||
/* byte checksum: 0x0000 to 0x001F (standard header)
|
||||
|
@ -145,8 +145,8 @@ struct addin_cp_subheader {
|
|||
uint8_t stamp[14];
|
||||
};
|
||||
|
||||
/* Then from here, the two formats diverge.
|
||||
* G3A subheader goes like this: */
|
||||
/* Then from here, the two formats diverge.
|
||||
* G3A subheader goes like this: */
|
||||
|
||||
# define G3A_ICON_WIDTH 92
|
||||
# define G3A_ICON_HEIGHT 64
|
||||
|
@ -178,7 +178,7 @@ struct g3a_subheader {
|
|||
uint8_t unselected_icon_image[0x3000];
|
||||
};
|
||||
|
||||
/* And the C1A header goes like this: */
|
||||
/* And the C1A header goes like this: */
|
||||
|
||||
# define C1A_ICON_WIDTH 46
|
||||
# define C1A_ICON_HEIGHT 30
|
||||
|
|
|
@ -20,30 +20,30 @@
|
|||
# define LIBG1M_FORMAT_STD_EACT_H
|
||||
# include <stdint.h>
|
||||
|
||||
/* E-Activities are the format CASIO uses for in-calc documents.
|
||||
* It is the funniest subformat the the libg1m can parse.
|
||||
/* E-Activities are the format CASIO uses for in-calc documents.
|
||||
* It is the funniest subformat the the libg1m can parse.
|
||||
*
|
||||
* There is only one part for e-activities.
|
||||
* The overall header has two zones:
|
||||
* - the special header, that keeps the global info;
|
||||
* - the setup area, that keeps one part of the calculator setup.
|
||||
* There is only one part for e-activities.
|
||||
* The overall header has two zones:
|
||||
* - the special header, that keeps the global info;
|
||||
* - the setup area, that keeps one part of the calculator setup.
|
||||
*
|
||||
* There are several types for E-Activies, identified by the extensions
|
||||
* CASIO give them.
|
||||
* The E-Act version in the header is 0x10100 for g1e, 0x10200 for g2e,
|
||||
* and 0x10400 for g3e. */
|
||||
* There are several types for E-Activies, identified by the extensions
|
||||
* CASIO give them.
|
||||
* The E-Act version in the header is 0x10100 for g1e, 0x10200 for g2e,
|
||||
* and 0x10400 for g3e. */
|
||||
|
||||
# define EACT_G1E 0x10100
|
||||
# define EACT_G2E 0x10200
|
||||
# define EACT_G3E 0x10400
|
||||
|
||||
/* The differences between these formats are the following:
|
||||
* - On g1e, the OS version is always 0x5061636B, where on g2e/g3e,
|
||||
* the OS version is the version of the OS on which the file was written.
|
||||
* - On g1e/g2e, the setup directory is 0x10-bytes long, where on g3e,
|
||||
* the setup directory is 0x2C-bytes long.
|
||||
/* The differences between these formats are the following:
|
||||
* - On g1e, the OS version is always 0x5061636B, where on g2e/g3e,
|
||||
* the OS version is the version of the OS on which the file was written.
|
||||
* - On g1e/g2e, the setup directory is 0x10-bytes long, where on g3e,
|
||||
* the setup directory is 0x2C-bytes long.
|
||||
*
|
||||
* So the main header is: */
|
||||
* So the main header is: */
|
||||
|
||||
struct eact_header {
|
||||
/* the filesize */
|
||||
|
@ -59,8 +59,8 @@ struct eact_header {
|
|||
uint32_t os_version;
|
||||
};
|
||||
|
||||
/* And now, the funniest part: the content.
|
||||
* So a content has this header: */
|
||||
/* And now, the funniest part: the content.
|
||||
* So a content has this header: */
|
||||
|
||||
struct eact_contentheader {
|
||||
/* content type: @EACT, @RUNMAT, ... */
|
||||
|
@ -76,18 +76,18 @@ struct eact_contentheader {
|
|||
uint8_t align2[4];
|
||||
};
|
||||
|
||||
/* There are several types of contents.
|
||||
* The most basic one is also called "@EACT".
|
||||
* It has this content subheader: */
|
||||
/* There are several types of contents.
|
||||
* The most basic one is also called "@EACT".
|
||||
* It has this content subheader: */
|
||||
|
||||
struct eact_eactheader {
|
||||
/* line count */
|
||||
uint32_t line_count;
|
||||
};
|
||||
|
||||
/* And after, lines come. First of all, there is a line descriptor table,
|
||||
* that contain the line type and the line offset from the subheader begin.
|
||||
* A line type can have these types: */
|
||||
/* And after, lines come. First of all, there is a line descriptor table,
|
||||
* that contain the line type and the line offset from the subheader begin.
|
||||
* A line type can have these types: */
|
||||
|
||||
enum eact_linetype {
|
||||
/* contains a calculation */
|
||||
|
@ -113,7 +113,7 @@ enum eact_linetype {
|
|||
eact_ltype_code = 0x82
|
||||
};
|
||||
|
||||
/* And here's the line descriptor structure: */
|
||||
/* And here's the line descriptor structure: */
|
||||
|
||||
struct line_descriptor {
|
||||
/* the entry type */
|
||||
|
@ -123,12 +123,12 @@ struct line_descriptor {
|
|||
uint32_t entry_offset :24;
|
||||
};
|
||||
|
||||
/* And there is only one content after the main header, and it's a content
|
||||
* of EACT type. But hey, why the heck have we defined several types and stuff?
|
||||
* Well, that's the funniest thing of E-Activities:
|
||||
/* And there is only one content after the main header, and it's a content
|
||||
* of EACT type. But hey, why the heck have we defined several types and stuff?
|
||||
* Well, that's the funniest thing of E-Activities:
|
||||
*
|
||||
* they are RECURSIVE. [drama alert]
|
||||
* they are RECURSIVE. [drama alert]
|
||||
*
|
||||
* Which means in each node, there can be a content to parse. */
|
||||
* Which means in each node, there can be a content to parse. */
|
||||
|
||||
#endif /* LIBG1M_FORMAT_STD_EACT_H */
|
||||
|
|
|
@ -21,18 +21,18 @@
|
|||
# include <libg1m.h>
|
||||
# pragma pack(1)
|
||||
|
||||
/* Function keys are the little boxes at the bottom with text in it, to tell
|
||||
* you what you're going to access if you press F1-F6. */
|
||||
/* Function keys are the little boxes at the bottom with text in it, to tell
|
||||
* you what you're going to access if you press F1-F6. */
|
||||
/* ************************************************************************** */
|
||||
/* G1N - Function-keys files for fx calculators */
|
||||
/* ************************************************************************** */
|
||||
/* In G1Ns, function keys are 19x8 1-bit with fill bits images.
|
||||
/* In G1Ns, function keys are 19x8 1-bit with fill bits images.
|
||||
*
|
||||
* TODO: it is unknown yet how to identify G1N files, as no non-community-made
|
||||
* one of them was found and the calculator software just skips
|
||||
* StandardHeader. It has to be found for a correct integration in libg1m!
|
||||
* TODO: it is unknown yet how to identify G1N files, as no non-community-made
|
||||
* one of them was found and the calculator software just skips
|
||||
* StandardHeader. It has to be found for a correct integration in libg1m!
|
||||
*
|
||||
* The format looks a lot like G1L files. The header is the following: */
|
||||
* The format looks a lot like G1L files. The header is the following: */
|
||||
|
||||
# define FKEY_WIDTH 24
|
||||
# define FKEY_HEIGHT 8
|
||||
|
@ -47,20 +47,20 @@ struct g1n_subheader {
|
|||
uint16_t fkey_count;
|
||||
};
|
||||
|
||||
/* Then there is a table of 16-bits offsets (iconXXX - icon0), then the icons.
|
||||
* The first "icon" is in fact the name of the language. */
|
||||
/* Then there is a table of 16-bits offsets (iconXXX - icon0), then the icons.
|
||||
* The first "icon" is in fact the name of the language. */
|
||||
/* ************************************************************************** */
|
||||
/* G3L-N - Function-keys files for CG calculators */
|
||||
/* ************************************************************************** */
|
||||
/* G3L-N have exactly the same header and subheader as G3Ls, except
|
||||
* the magic field is "0201" and not "0401" like for "normal" G3Ls.
|
||||
/* G3L-N have exactly the same header and subheader as G3Ls, except
|
||||
* the magic field is "0201" and not "0401" like for "normal" G3Ls.
|
||||
*
|
||||
* TODO: it is unknown yet how to identify G3N files using the StandardHeader,
|
||||
* as no non-community-made one of them was found and the calculator software
|
||||
* just skips StandardHeader. It has to be found for a correct integration
|
||||
* in libg1m!
|
||||
* TODO: it is unknown yet how to identify G3N files using the StandardHeader,
|
||||
* as no non-community-made one of them was found and the calculator software
|
||||
* just skips StandardHeader. It has to be found for a correct integration
|
||||
* in libg1m!
|
||||
*
|
||||
* In G3L-Ns, function keys are 64x24 1-bit images. */
|
||||
* In G3L-Ns, function keys are 64x24 1-bit images. */
|
||||
|
||||
# define FKEY3_WIDTH 64
|
||||
# define FKEY3_HEIGHT 24
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
/* ************************************************************************** */
|
||||
/* G1L - Language files for fx calculators */
|
||||
/* ************************************************************************** */
|
||||
/* It all starts with a header: */
|
||||
/* It all starts with a header: */
|
||||
|
||||
struct g1l_subheader {
|
||||
/* identifier: is "PowerUSB" on original things */
|
||||
|
@ -41,19 +41,19 @@ struct g1l_subheader {
|
|||
uint16_t message_count;
|
||||
};
|
||||
|
||||
/* Then comes a list of offsets, and the messages.
|
||||
/* Then comes a list of offsets, and the messages.
|
||||
*
|
||||
* Each element of the offsets list is 16-bytes long.
|
||||
* It is relative to the first element (which starts right after the
|
||||
* offsets list - no alignment).
|
||||
* Each element of the offsets list is 16-bytes long.
|
||||
* It is relative to the first element (which starts right after the
|
||||
* offsets list - no alignment).
|
||||
*
|
||||
* The messages are null-terminated - once you get the offsets, you get
|
||||
* them completely. */
|
||||
* The messages are null-terminated - once you get the offsets, you get
|
||||
* them completely. */
|
||||
/* ************************************************************************** */
|
||||
/* G3L - Language files for Prizm */
|
||||
/* ************************************************************************** */
|
||||
/* Thanks to amazonka for his (minimalist) description of the G3L format
|
||||
* at Cemetech. So the G3L format starts off with a header: */
|
||||
/* Thanks to amazonka for his (minimalist) description of the G3L format
|
||||
* at Cemetech. So the G3L format starts off with a header: */
|
||||
|
||||
struct g3l_subheader {
|
||||
/* a checksum */
|
||||
|
@ -110,8 +110,8 @@ struct g3l_subheader {
|
|||
uint8_t undocumented4[308];
|
||||
};
|
||||
|
||||
/* Then there is something amazonka names the "executable code section".
|
||||
* This is in fact the message zone. */
|
||||
/* Then there is something amazonka names the "executable code section".
|
||||
* This is in fact the message zone. */
|
||||
|
||||
struct g3l_lang_header {
|
||||
/* sequence: '4C 59 37 35 35 00 00 00 02' (LY755 ) */
|
||||
|
@ -127,17 +127,17 @@ struct g3l_lang_header {
|
|||
uint8_t unused2[2];
|
||||
};
|
||||
|
||||
/* Then we have offsets of all messages (4 bytes each),
|
||||
* then messages themselves, zero-terminated.
|
||||
/* Then we have offsets of all messages (4 bytes each),
|
||||
* then messages themselves, zero-terminated.
|
||||
*
|
||||
* The four last bytes of the files are a little footer, which is: */
|
||||
* The four last bytes of the files are a little footer, which is: */
|
||||
|
||||
struct g3l_footer {
|
||||
/* copy of the first checksum in the subheader */
|
||||
uint32_t checksum;
|
||||
};
|
||||
|
||||
/* This footer is not counted as part of the file. */
|
||||
/* This footer is not counted as part of the file. */
|
||||
|
||||
# pragma pack()
|
||||
#endif /* LIBG1M_FORMAT_STD_LANG_H */
|
||||
|
|
|
@ -21,22 +21,22 @@
|
|||
# include <stdint.h>
|
||||
# pragma pack(1)
|
||||
|
||||
/* MCS is the main filesystem on CASIO calculators. They contain settings,
|
||||
* programs, lists, pictures, captures, matrixes, and other data CASIO
|
||||
* calculators own.
|
||||
* Keep in mind that all numbers in the MCS format are BCD-encoded.
|
||||
* Because of some precision issue (0.3), we'll deliver them to the user as is.
|
||||
/* MCS is the main filesystem on CASIO calculators. They contain settings,
|
||||
* programs, lists, pictures, captures, matrixes, and other data CASIO
|
||||
* calculators own.
|
||||
* Keep in mind that all numbers in the MCS format are BCD-encoded.
|
||||
* Because of some precision issue (0.3), we'll deliver them to the user as is.
|
||||
*
|
||||
* MCS files have a group, a directory, a name and a type. This type depends
|
||||
* on the group it's in. So for example, the 0xFE type in the 'S-SHEET' group
|
||||
* will correspond to a spreadsheet! In an MCS G1M file, files are more or less
|
||||
* regrouped by their group (but sometimes they're not, there are several
|
||||
* 'PROGRAM' groups with one element for example).
|
||||
* MCS files have a group, a directory, a name and a type. This type depends
|
||||
* on the group it's in. So for example, the 0xFE type in the 'S-SHEET' group
|
||||
* will correspond to a spreadsheet! In an MCS G1M file, files are more or less
|
||||
* regrouped by their group (but sometimes they're not, there are several
|
||||
* 'PROGRAM' groups with one element for example).
|
||||
*
|
||||
* The `number` field in the Standard Header corresponds to the total number
|
||||
* of MCS files, not group instances!
|
||||
* The `number` field in the Standard Header corresponds to the total number
|
||||
* of MCS files, not group instances!
|
||||
*
|
||||
* Each group instance have a header, and here it is: */
|
||||
* Each group instance have a header, and here it is: */
|
||||
|
||||
struct mcs_subheader {
|
||||
/* group name (e.g. "PROGRAM", zero padded) */
|
||||
|
@ -46,8 +46,8 @@ struct mcs_subheader {
|
|||
uint32_t subcount;
|
||||
};
|
||||
|
||||
/* Then follows the files, with their headers and contents.
|
||||
* And the header iiiiiiis: */
|
||||
/* Then follows the files, with their headers and contents.
|
||||
* And the header iiiiiiis: */
|
||||
|
||||
struct mcs_fileheader {
|
||||
/* the directory name (zero-padded).*/
|
||||
|
@ -68,8 +68,8 @@ struct mcs_fileheader {
|
|||
|
||||
# pragma pack()
|
||||
|
||||
/* Beneath the file header, the file have different structures according to
|
||||
* their group name and MCS type. Pick your poison, once again! */
|
||||
/* Beneath the file header, the file have different structures according to
|
||||
* their group name and MCS type. Pick your poison, once again! */
|
||||
|
||||
# include <libg1m/format/mcs/list.h>
|
||||
# include <libg1m/format/mcs/matrix.h>
|
||||
|
|
|
@ -23,18 +23,18 @@
|
|||
/* ************************************************************************** */
|
||||
/* G3P: pictures for Prizm */
|
||||
/* ************************************************************************** */
|
||||
/* G3P are pictures for fx-CG. They only have one part.
|
||||
* This mysteries over this format have been unraveled by many, but I'm using
|
||||
* Simon Lothar's documentation and Kerm Martian's articles.
|
||||
/* G3P are pictures for fx-CG. They only have one part.
|
||||
* This mysteries over this format have been unraveled by many, but I'm using
|
||||
* Simon Lothar's documentation and Kerm Martian's articles.
|
||||
*
|
||||
* Some color depth things: */
|
||||
* Some color depth things: */
|
||||
|
||||
enum g3p_colorsize {
|
||||
g3p_color_4bit = 0x03,
|
||||
g3p_color_16bit = 0x10
|
||||
};
|
||||
|
||||
/* So, after the header, here is the G3P subheader: */
|
||||
/* So, after the header, here is the G3P subheader: */
|
||||
|
||||
struct g3p_subheader {
|
||||
/* some magic sequence: "CP0100Ly755"
|
||||
|
@ -57,9 +57,9 @@ struct g3p_subheader {
|
|||
uint8_t undocumented_gap[124];
|
||||
};
|
||||
|
||||
/* What is after the G3P subheader is the image (data).
|
||||
/* What is after the G3P subheader is the image (data).
|
||||
*
|
||||
* The image has a header, some data and a footer. Here is the header: */
|
||||
* The image has a header, some data and a footer. Here is the header: */
|
||||
|
||||
struct g3p_imageheader {
|
||||
/* magic sequence? is: 0x00, 0x01, 0x00, 0x00 */
|
||||
|
@ -87,33 +87,33 @@ struct g3p_imageheader {
|
|||
uint32_t data_size;
|
||||
};
|
||||
|
||||
/* Then there is the image data and the footer.
|
||||
/* Then there is the image data and the footer.
|
||||
*
|
||||
* At the beginning of the image data, there is a 2-byte ID.
|
||||
* 0x3c1b is the ID for "Casio Provided" images with no footers (?).
|
||||
* At the beginning of the image data, there is a 2-byte ID.
|
||||
* 0x3c1b is the ID for "Casio Provided" images with no footers (?).
|
||||
*
|
||||
* The image is deflated using the DEFLATE algorithm.
|
||||
* The image is deflated using the DEFLATE algorithm.
|
||||
*
|
||||
* For some images, CASIO added some obfuscation. To check if the image is
|
||||
* encrypted, according to syscalls, you have to check standard header data.
|
||||
* Image is encrypted if:
|
||||
* For some images, CASIO added some obfuscation. To check if the image is
|
||||
* encrypted, according to syscalls, you have to check standard header data.
|
||||
* Image is encrypted if:
|
||||
*
|
||||
* [0x1C] != [0x08] + [0x12] + [0x13] + 0x7B
|
||||
* [0x1C] != [0x08] + [0x12] + [0x13] + 0x7B
|
||||
*
|
||||
* Which, simplified and with our structures, is:
|
||||
* Which, simplified and with our structures, is:
|
||||
*
|
||||
* (std.obfuscated + 8) & 0xff != (std.filesize & 0xff00) >> 8
|
||||
* (std.obfuscated + 8) & 0xff != (std.filesize & 0xff00) >> 8
|
||||
*
|
||||
* then the deflated image is encrypted.
|
||||
* then the deflated image is encrypted.
|
||||
*
|
||||
* If this is the case, before passing the data to the INFLATE algorithm,
|
||||
* you have to apply this on each byte of the deflated image:
|
||||
* If this is the case, before passing the data to the INFLATE algorithm,
|
||||
* you have to apply this on each byte of the deflated image:
|
||||
*
|
||||
* 0b76543210 -> 0b21076543,
|
||||
* which, in C, is: (byte >> 3) | ((byte & 0x7) << 5)
|
||||
* 0b76543210 -> 0b21076543,
|
||||
* which, in C, is: (byte >> 3) | ((byte & 0x7) << 5)
|
||||
*
|
||||
* The footer contains the Adler32 checksum of the raw and unobfuscated data.
|
||||
* Here it is: */
|
||||
* The footer contains the Adler32 checksum of the raw and unobfuscated data.
|
||||
* Here it is: */
|
||||
|
||||
struct g3p_imagefooter {
|
||||
/* checksum */
|
||||
|
@ -123,7 +123,7 @@ struct g3p_imagefooter {
|
|||
/* ************************************************************************** */
|
||||
/* C2P: Images for Classpads */
|
||||
/* ************************************************************************** */
|
||||
/* C2P are images for fx-CP400 calculators. It starts of with this header: */
|
||||
/* C2P are images for fx-CP400 calculators. It starts of with this header: */
|
||||
|
||||
struct c2p_subheader {
|
||||
/* magic field: "CC0100" */
|
||||
|
@ -166,11 +166,11 @@ struct c2p_subheader {
|
|||
uint32_t unknown_size3;
|
||||
};
|
||||
|
||||
/* Then there is the zlib header with default compression.
|
||||
* The pixels format is R5G6B5.
|
||||
/* Then there is the zlib header with default compression.
|
||||
* The pixels format is R5G6B5.
|
||||
*
|
||||
* After the image, there is a footer, which is mainly undocumented, but
|
||||
* here is what we've got: */
|
||||
* After the image, there is a footer, which is mainly undocumented, but
|
||||
* here is what we've got: */
|
||||
|
||||
struct c2p_footer {
|
||||
/* "0100", again */
|
||||
|
|
|
@ -19,23 +19,23 @@
|
|||
#ifndef LIBG1M_FORMAT_STD_STORAGE_H
|
||||
# define LIBG1M_FORMAT_STD_STORAGE_H
|
||||
|
||||
/* Storage backup files (G1S) contain backups of the storage memory.
|
||||
* It corresponds exactly to the on-calc storage memory structure.
|
||||
/* Storage backup files (G1S) contain backups of the storage memory.
|
||||
* It corresponds exactly to the on-calc storage memory structure.
|
||||
*
|
||||
* According to Simon Lothar, the files contain zeroes up to 0x00270000
|
||||
* (including the StandardHeader; this is the location of the SMEM in real
|
||||
* fx-9860 calculators), then it has the same structure than the one
|
||||
* used by the calculator.
|
||||
* According to Simon Lothar, the files contain zeroes up to 0x00270000
|
||||
* (including the StandardHeader; this is the location of the SMEM in real
|
||||
* fx-9860 calculators), then it has the same structure than the one
|
||||
* used by the calculator.
|
||||
*
|
||||
* It looks like these files are not managed by the calculator (not directly);
|
||||
* however, they are managed by FA-124. */
|
||||
* It looks like these files are not managed by the calculator (not directly);
|
||||
* however, they are managed by FA-124. */
|
||||
/* ************************************************************************** */
|
||||
/* Directory list */
|
||||
/* ************************************************************************** */
|
||||
/* The SMEM (content of the G1S file once 0x270000 bytes were skipped) starts
|
||||
* with a big entry list. An entry is 32-bytes long: it starts with a common
|
||||
* part, then with a type-specific part (then unused bytes if the subheader
|
||||
* is less than 28-bytes long). Here is its structure: */
|
||||
/* The SMEM (content of the G1S file once 0x270000 bytes were skipped) starts
|
||||
* with a big entry list. An entry is 32-bytes long: it starts with a common
|
||||
* part, then with a type-specific part (then unused bytes if the subheader
|
||||
* is less than 28-bytes long). Here is its structure: */
|
||||
|
||||
struct storage_entry {
|
||||
/* the type number - see below */
|
||||
|
@ -51,9 +51,9 @@ struct storage_entry {
|
|||
uint8_t raw_subheader[28];
|
||||
};
|
||||
|
||||
/* The `type` is composed of three nibbles of identification (`type & 0xFFF`)
|
||||
* and a (high) nibble of special properties, keep that in mind.
|
||||
* Here are the known types: */
|
||||
/* The `type` is composed of three nibbles of identification (`type & 0xFFF`)
|
||||
* and a (high) nibble of special properties, keep that in mind.
|
||||
* Here are the known types: */
|
||||
|
||||
enum storage_entry_type {
|
||||
storage_entrytype_sector = 0x200,
|
||||
|
@ -62,39 +62,39 @@ enum storage_entry_type {
|
|||
storage_entrytype_fragment = 0x130,
|
||||
};
|
||||
|
||||
/* The special nibble is usually zero when deleted, and non-zero when active.
|
||||
* According to Simon Lothar, this is because it is possible to clear bits
|
||||
* on the flash by flashwriting a short value only; but when it comes to
|
||||
* set bits, it becomes more tricky.
|
||||
/* The special nibble is usually zero when deleted, and non-zero when active.
|
||||
* According to Simon Lothar, this is because it is possible to clear bits
|
||||
* on the flash by flashwriting a short value only; but when it comes to
|
||||
* set bits, it becomes more tricky.
|
||||
*
|
||||
* This is also why optimizing is not done straight away (to save the flash
|
||||
* a little).
|
||||
* This is also why optimizing is not done straight away (to save the flash
|
||||
* a little).
|
||||
*
|
||||
* The list can have to 0x800 entries, and occupies the first sector.
|
||||
* Simon Lothar says the list can expand to the second sector (which is used
|
||||
* only if there is no space in the index sector or the other data sectors).
|
||||
* Entries with the 0xFFFF type should not be read.
|
||||
* The list can have to 0x800 entries, and occupies the first sector.
|
||||
* Simon Lothar says the list can expand to the second sector (which is used
|
||||
* only if there is no space in the index sector or the other data sectors).
|
||||
* Entries with the 0xFFFF type should not be read.
|
||||
*
|
||||
* Some entry types can have parents. In this case, they have parent type,
|
||||
* and parent number fields. This is because elements with different types
|
||||
* follow different numerations; so the type field is here on which numeration
|
||||
* to search for the member. If the parent type is 0xFFFF (or -1, as some say),
|
||||
* then there is no parent.
|
||||
* Some entry types can have parents. In this case, they have parent type,
|
||||
* and parent number fields. This is because elements with different types
|
||||
* follow different numerations; so the type field is here on which numeration
|
||||
* to search for the member. If the parent type is 0xFFFF (or -1, as some say),
|
||||
* then there is no parent.
|
||||
*
|
||||
* For now, only directories as parents for files have been encountered. */
|
||||
* For now, only directories as parents for files have been encountered. */
|
||||
/* ************************************************************************** */
|
||||
/* Sectors */
|
||||
/* ************************************************************************** */
|
||||
/* Sectors represent the physical sectors of the storage memory (space!).
|
||||
* They are 64 KiB large.
|
||||
/* Sectors represent the physical sectors of the storage memory (space!).
|
||||
* They are 64 KiB large.
|
||||
*
|
||||
* Simon Lothar says that there are 27 entries for them (or 14 on the AU models
|
||||
* because of australian exam regulations). If the logical number
|
||||
* is 0xFFFFFFFF, the sector is unused. (sometimes the logical number field
|
||||
* contains gibberish, I don't know why yet)
|
||||
* Simon Lothar says that there are 27 entries for them (or 14 on the AU models
|
||||
* because of australian exam regulations). If the logical number
|
||||
* is 0xFFFFFFFF, the sector is unused. (sometimes the logical number field
|
||||
* contains gibberish, I don't know why yet)
|
||||
*
|
||||
* Their special nibble is either 0x04 or 0x00, the signification of it is not
|
||||
* known to me yet. Here is their subheader structure: */
|
||||
* Their special nibble is either 0x04 or 0x00, the signification of it is not
|
||||
* known to me yet. Here is their subheader structure: */
|
||||
|
||||
struct storage_sector {
|
||||
/* the sector start address - 0xFF */
|
||||
|
@ -108,10 +108,10 @@ struct storage_sector {
|
|||
/* ************************************************************************** */
|
||||
/* Directories */
|
||||
/* ************************************************************************** */
|
||||
/* After the sectors come the directories.
|
||||
/* After the sectors come the directories.
|
||||
*
|
||||
* Their special nibble is either 0x05 if active or 0x00 if deleted.
|
||||
* Here is their subheader structure: */
|
||||
* Their special nibble is either 0x05 if active or 0x00 if deleted.
|
||||
* Here is their subheader structure: */
|
||||
|
||||
struct storage_directory {
|
||||
/* the parent type and id */
|
||||
|
@ -125,10 +125,10 @@ struct storage_directory {
|
|||
/* ************************************************************************** */
|
||||
/* Files */
|
||||
/* ************************************************************************** */
|
||||
/* After the directories come the files (interrupted by fragments - see after).
|
||||
/* After the directories come the files (interrupted by fragments - see after).
|
||||
*
|
||||
* Their special nibble have the same meaning that for directories.
|
||||
* Here is their subheader structure: */
|
||||
* Their special nibble have the same meaning that for directories.
|
||||
* Here is their subheader structure: */
|
||||
|
||||
struct storage_file {
|
||||
/* the parent type and id (not functional?) */
|
||||
|
@ -142,15 +142,15 @@ struct storage_file {
|
|||
/* ************************************************************************** */
|
||||
/* File fragments */
|
||||
/* ************************************************************************** */
|
||||
/* After each file entry comes the corresponding fragments entries.
|
||||
* Fragments are in fact links to the sectors, with some more info.
|
||||
/* After each file entry comes the corresponding fragments entries.
|
||||
* Fragments are in fact links to the sectors, with some more info.
|
||||
*
|
||||
* Their special nibble have the same meaning that for files... but are not
|
||||
* always accurate, so only check on files!
|
||||
* Their special nibble have the same meaning that for files... but are not
|
||||
* always accurate, so only check on files!
|
||||
*
|
||||
* The first fragment corresponding to a file contain this file's type,
|
||||
* probably detected when the file is transferred. Here are the
|
||||
* known values: */
|
||||
* The first fragment corresponding to a file contain this file's type,
|
||||
* probably detected when the file is transferred. Here are the
|
||||
* known values: */
|
||||
|
||||
enum storage_file_type {
|
||||
g1m_storage_filetype_unknown = 0x01,
|
||||
|
@ -159,8 +159,8 @@ enum storage_file_type {
|
|||
g1m_storage_filetype_g2r = 0x2E, /* G1R */
|
||||
};
|
||||
|
||||
/* Why is the file type here and not in the file header? I don't know.
|
||||
* And here is the fragments' subheader structure: */
|
||||
/* Why is the file type here and not in the file header? I don't know.
|
||||
* And here is the fragments' subheader structure: */
|
||||
|
||||
struct storage_fragment {
|
||||
/* the parent (file node) type and id */
|
||||
|
|
Reference in New Issue