/* ************************************************************************** */ /* _____ _ */ /* libg1m/format/mcs.h |_ _|__ _ _| |__ ___ _ _ */ /* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */ /* | | (_) | |_| | | | | __/ |_| | */ /* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ /* Last updated: 2016/11/02 14:15:46 |___/ */ /* */ /* ************************************************************************** */ #ifndef LIBG1M_FORMAT_MCS_H # define LIBG1M_FORMAT_MCS_H # include # include # 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 */