180 lines
5.1 KiB
C
180 lines
5.1 KiB
C
/* ************************************************************************** */
|
|
/* _____ _ */
|
|
/* libg1m/format/mcs.h |_ _|__ _ _| |__ ___ _ _ */
|
|
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
|
|
/* | | (_) | |_| | | | | __/ |_| | */
|
|
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
|
/* Last updated: 2016/11/02 14:15:46 |___/ */
|
|
/* */
|
|
/* ************************************************************************** */
|
|
#ifndef LIBG1M_FORMAT_MCS_H
|
|
# define LIBG1M_FORMAT_MCS_H
|
|
# include <libg1m.h>
|
|
# 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, we'll deliver them to the user as is.
|
|
*
|
|
* So now we are not restricted to one part. Remember the `number` field in
|
|
* the Standard Header? We once thought it was the number of parts to come.
|
|
* But no. In general, we have one subpart per part, but in some case, we
|
|
* have more, like for the LISTFILEs. And that is how we realized the `number`
|
|
* in the Standard Header wasn't the number of parts, but the total number
|
|
* of subparts.
|
|
*
|
|
* Each part have a header, and here it is: */
|
|
|
|
struct mcs_subheader {
|
|
/* main ID ("PROGRAM", zero padded) */
|
|
uint8_t intname[16];
|
|
|
|
/* subitem count: haha, read what follows! */
|
|
uint32_t subcount;
|
|
};
|
|
|
|
/* Because yes, an part of an MCS G1M file has subparts!
|
|
* Each one of them represent a single file in the MCS.
|
|
* According to their type, they are in different directories: */
|
|
|
|
enum mcs_filetype {
|
|
mcs_ftype_program = 0x1,
|
|
mcs_ftype_list = 0x5,
|
|
mcs_ftype_mat = 0x6,
|
|
mcs_ftype_picture = 0x7,
|
|
mcs_ftype_capture = 0xa,
|
|
mcs_ftype_spreadsheet = 0xfe,
|
|
};
|
|
|
|
/* And they also have a directory name, which is less precise. Why?
|
|
* We don't know! That's the main thing with reverse engineering.
|
|
*
|
|
* For basic programs, it is: */
|
|
# define DIRNAME_PROGRAM "system"
|
|
/* For most alpha-mem elements (list, matrixes, pictures): */
|
|
# define DIRNAME_ALPHAMEM "main"
|
|
/* And for captures: */
|
|
# define DIRNAME_CAPTURE "@REV2"
|
|
|
|
/* Now all of this is said, each part has this header: */
|
|
|
|
struct mcs_fileheader {
|
|
/* the directory name (zero-padded).*/
|
|
uint8_t dirname[8];
|
|
|
|
/* the file name (item name) */
|
|
uint8_t filename[8];
|
|
|
|
/* the file type. */
|
|
uint8_t filetype;
|
|
|
|
/* the size of the part data, without the part header. */
|
|
uint32_t datalength;
|
|
|
|
/* some alignment */
|
|
uint8_t align[3];
|
|
};
|
|
|
|
/* Beneath that, we have specific subsubheaders for specific types.
|
|
* Here's what it is for programs: */
|
|
|
|
struct mcs_programheader {
|
|
/* the program password. not encrypted, anything */
|
|
uint8_t password[8];
|
|
|
|
/* and some alignment. */
|
|
uint8_t align[2];
|
|
};
|
|
|
|
/* And, well, spreadsheets are more complicated than that.
|
|
* There is a header, a column directory and a column definition table.
|
|
*
|
|
* The header mainly contains the column count: */
|
|
|
|
struct mcs_spreadsheetheader {
|
|
/* magic number? */
|
|
uint8_t magic;
|
|
|
|
/* column count (max: 26), on 24 bits and non-aligned */
|
|
uint32_t column_count : 24;
|
|
|
|
/* alignment or magic? {0, 0, 0, 0} */
|
|
uint8_t align[4];
|
|
|
|
/* number of column definitions */
|
|
uint32_t defs_size;
|
|
|
|
/* alignment or magic II? {0, 0, 0, 0} */
|
|
uint8_t align2[4];
|
|
};
|
|
|
|
/* The column definition table is the main definition. It contains the row
|
|
* directory, which is a 80-bytes long bitfield indicating if cells are empty
|
|
* or not, and the list of non-empty cells.
|
|
*
|
|
* Each cell is a BCD structure.
|
|
*
|
|
* The column directory is just a list of 4-bytes sizes of each column,
|
|
* counting the row directory and the cells. It's easier to naviguate to
|
|
* a column quicker.
|
|
*
|
|
* Now, what about captures? Well, their header is the following: */
|
|
|
|
struct mcs_captureheader {
|
|
/* the width (0x80) */
|
|
uint16_t width;
|
|
|
|
/* the height (0x40) */
|
|
uint16_t height;
|
|
};
|
|
|
|
/* Then the image follows (0x400 for a 0x80*0x40px image).
|
|
* A picture is the same that an capture, but without the header and containing
|
|
* two 128x64 images (0x800 bytes).
|
|
*
|
|
* Lists! (had no idea how to introduce them)
|
|
* After their header, they have `element_count` BCD list corresponding
|
|
* to the numbers real part.
|
|
* If at least one of the elements have an imaginary part, there is another
|
|
* list right behind of `element_count` BCDs, with all of the imaginary
|
|
* parts.
|
|
*
|
|
* Here's their header: */
|
|
|
|
struct mcs_listheader {
|
|
/* probably the title */
|
|
uint8_t title[8];
|
|
|
|
/* the elements count */
|
|
uint16_t element_count;
|
|
|
|
/* undocumented (always 0?) */
|
|
uint8_t undocumented[5];
|
|
|
|
/* undocumented (either 0x00 or 0x4F) */
|
|
uint8_t undocumented2;
|
|
};
|
|
|
|
/* Now, let's see matrixes! */
|
|
|
|
struct mcs_matheader {
|
|
/* undocumented */
|
|
uint8_t undocumented[8];
|
|
|
|
/* height */
|
|
uint16_t height;
|
|
|
|
/* width */
|
|
uint16_t width;
|
|
|
|
/* re-undocumented */
|
|
uint8_t undocumented2[4];
|
|
};
|
|
|
|
# pragma pack()
|
|
#endif /* LIBG1M_FORMAT_MCS_H */
|