diff --git a/configure b/configure index 9144d46..c18015e 100755 --- a/configure +++ b/configure @@ -128,7 +128,7 @@ esac; done #******************************************************************************# for arg ; do case "$arg" in --make-full-log) make_full_log=yes ;; ---maintainer) more_warnings=yes; loglevel=info ;; +--maintainer) more_warnings=yes; loglevel=info; install_manpages= ;; --target=*) target="${arg#*=}" ;; --static) static=y ;; --windows) windows=y ;; diff --git a/include/libg1m.h b/include/libg1m.h index 89f99a6..e0b2342 100644 --- a/include/libg1m.h +++ b/include/libg1m.h @@ -57,7 +57,7 @@ extern "C" { /* Then, the stream errors */ # define g1m_error_nostream 0x10 # define g1m_error_noread 0x11 -# define g1m_error_noseek 0x12 +# define g1m_error_noseek 0x12 /* unused for now */ # define g1m_error_nowrite 0x13 # define g1m_error_read 0x14 # define g1m_error_write 0x15 @@ -149,9 +149,23 @@ extern int g1m_decode_casfile_part(g1m_mcsfile_t *file, g1m_buffer_t *buffer); /* create and insert an MCS file into a MCS archive */ extern int g1m_mcs_insert(g1m_t *handle, g1m_mcsfile_t **tofile, const g1m_mcshead_t *head); + +/* sort an MCS archive for encoding, + * compare two MCS files (utility function used by the first) */ +extern int g1m_mcs_sort(g1m_t *handle); +extern int g1m_compare_mcsfiles(const g1m_mcsfile_t *first_file, + const g1m_mcsfile_t *second_file); /* ************************************************************************** */ /* Miscallaneous utilities */ /* ************************************************************************** */ +/* Picture decoding/encoding */ +extern int g1m_decode_picture(uint32_t **pixels, + g1m_pictureformat_t format, const unsigned char *raw, + unsigned int width, unsigned int height); +extern int g1m_encode_picture(const uint32_t **pixels, + g1m_pictureformat_t format, unsigned char *raw, + unsigned int width, unsigned int height); + /* Version decoding/encoding */ extern int g1m_decode_version(const char *raw, g1m_version_t *version); extern int g1m_encode_version(const g1m_version_t *version, char *raw); diff --git a/include/libg1m/format/std.h b/include/libg1m/format/std.h index 7e91ad8..a60886f 100644 --- a/include/libg1m/format/std.h +++ b/include/libg1m/format/std.h @@ -199,7 +199,44 @@ struct _classpad_subheader { * file, which is only made of a 32-bit checksum that should be equal to * the subheader checksum. * - * Then, where do you want to start? Pick your poison. */ + * Picture formats (C2P, G3P) have a common picture standard subheader, which + * is the following: */ + +struct standard_picheader { + /* magic sequence: "CC" for the Classpad, "CP" for the Prizm */ + uint8_t cp[2]; + + /* "0100", either in raw (0x00, 0x01) for G3P + * or in ASCII (0x30, 0x31) for C2P */ + uint8_t magic[4]; + + /* magic sequences: + * - "ColorCP\0" for the C2P; + * - "LY755\0\0\0" for the G3P. */ + uint8_t magic2[8]; + + /* unknown byte: 0x02 on the G3P, 0x00 on the C2P */ + uint8_t _unknown0; + + /* unused byte */ + uint8_t _unused; + + /* filesize after the StandardHeader */ + uint32_t filesize; + + /* "Always contains the 32-bit big-endian integer 0x00000001" */ + uint32_t _alwaysone; + + /* subsize (what's after the standard picture header) */ + uint32_t subsize; + + /* unknown gap */ + uint8_t _unknown2[0x7C]; +}; + +/* Then we have the specific header -- see `libg1m/format/std/picture.h`. + * + * Where do you want to go next? Pick your poison. */ # pragma pack() # include diff --git a/include/libg1m/format/std/mcs.h b/include/libg1m/format/std/mcs.h index 624ef34..ba5787d 100644 --- a/include/libg1m/format/std/mcs.h +++ b/include/libg1m/format/std/mcs.h @@ -25,7 +25,8 @@ * 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. + * Because of some precision issue (0.3), we'll deliver them to the user + * almost 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 diff --git a/include/libg1m/format/std/picture.h b/include/libg1m/format/std/picture.h index 136b304..7276a0d 100644 --- a/include/libg1m/format/std/picture.h +++ b/include/libg1m/format/std/picture.h @@ -19,55 +19,25 @@ #ifndef LIBG1M_FORMAT_STD_PICTURE_H # define LIBG1M_FORMAT_STD_PICTURE_H # include +# pragma pack(1) /* ************************************************************************** */ /* G3P: pictures for Prizm */ /* ************************************************************************** */ -/* G3P are pictures for fx-CG. They only have one part. +/* G3P are pictures for fx-CG. They start with a Standard Header, and + * a Standard Picture Header. + * * 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: */ + * Prizm pictures (G3P) support several image depths (encodings): */ -enum g3p_colorsize { - g3p_color_4bit = 0x03, - g3p_color_16bit = 0x10 -}; +# define g3p_color_4bit 0x03 +# define g3p_color_16bit 0x10 -/* So, after the header, here is the G3P subheader: */ +/* After the standard headers, comes the specific header: */ struct g3p_subheader { - /* some magic sequence: "CP0100" - * "CP" is checked by a syscall */ - uint8_t type[6]; - - /* some magic sequence: '4C 59 37 35 35 00 00 00' (LY755 ) */ - uint8_t magic[8]; - - /* unknown: 0x02 */ - uint8_t _unknown; - - /* unused */ - uint8_t _unused; - - /* size of the file after standard header */ - uint32_t g3p_size; - - /* undocumented */ - uint8_t unknown[4]; - - /* size of the image data + 0x18 bytes of header */ - uint32_t image_size; - - /* undocumented gap */ - uint8_t undocumented_gap[124]; -}; - -/* What is after the G3P subheader is the image (data). - * - * The image has a header, some data and a footer. Here is the header: */ - -struct g3p_imageheader { /* magic sequence? is: 0x00, 0x01, 0x00, 0x00 */ uint8_t magic[4]; @@ -75,7 +45,7 @@ struct g3p_imageheader { uint32_t df_size; /* w0t */ - uint16_t unknown2; + uint8_t _unknown0[2]; /* width */ uint16_t width; @@ -87,74 +57,59 @@ struct g3p_imageheader { uint16_t color_depth; /* undocumented, again */ - uint32_t undocumented; + uint8_t _unknown1[4]; - /* length of image + footer */ + /* length of the image data + 6 + * the 6 bytes are: + * - the 16-bit generator ID at the beginning; + * - the 32-bit checksum at the end of the data. */ uint32_t data_size; + + /* Generator ID */ + uint16_t generator_id; }; -/* 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 (?). - * - * 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: - * - * [0x1C] != [0x08] + [0x12] + [0x13] + 0x7B - * - * Which, simplified and with our structures, is: - * - * (std.obfuscated + 8) & 0xff != (std.filesize & 0xff00) >> 8 - * - * 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: - * - * 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 generator ID is a 16-bit ID giving information about the picture + * generator. The known IDs are the following: */ -struct g3p_imagefooter { - /* checksum */ - uint32_t checksum; -}; +# define g3p_id_casio 0x3C1B +# define g3p_id_unknown0 0x388D +# define g3p_id_unknown1 0x789C +# define g3p_id_unknown2 0x3E93 +/* Then we have the deflated image data, which is `data_size - 6` sized + * (see the `data_size` comment above for more explanation). + * + * Before inflating, you should check if the image is obfuscated (Simon Lothar + * says 'encrypted', I suppose that's more polite). It is if: + * + * (std.obfuscated + 8) & 0xFF != (std.filesize & 0xff00) >> 8 + * + * If it is, then in order to de-obfuscate, you should do the following + * operation: + * + * byte = ~((byte << 5) | (byte >> 3)) & 0xFF; + * + * Then you can inflate. + * Once this is done, you can get the next four bytes, also considered as + * part of the data: the 32-bit adler32 checksum. It is a checksum over the + * raw, uncompressed data (and is appended to it before deflating/obfuscating). + * + * TODO: footers */ /* ************************************************************************** */ /* C2P: Images for Classpads */ /* ************************************************************************** */ -/* C2P are images for fx-CP400 calculators. It starts of with this header: */ +/* C2P are pictures for CASIO Classpad calculators (fx-CP*). They start with + * a Standard Header, followed by a Standard Picture Header. + * + * Then comes the specific subheader: */ struct c2p_subheader { - /* magic field: "CC0100" */ - uint8_t magic1[6]; - - /* second magic: "ColorCP\0\0\0" */ - uint8_t color_cp[10]; - - /* filesize without standard header */ - uint32_t c2p_size; - - /* unknown */ - uint32_t unknown; - - /* filesize - 0x234 */ - uint32_t unknown_size; - - /* undocumented */ - uint8_t undocumented[124]; - /* "0100" */ - uint8_t zero_one_zero_zero[4]; + uint8_t magic[4]; - /* filesize - 0x254 */ - uint32_t unknown_size2; + /* footer offset? `filesize - 0x254` */ + uint32_t footer_offset; /* unknown */ uint16_t unknown2; @@ -180,10 +135,10 @@ struct c2p_subheader { struct c2p_footer { /* "0100", again */ - uint8_t zero_one_zero_zero[4]; + uint8_t magic[4]; /* and some undocumented stuff */ - uint8_t undocumented[358]; + uint8_t undocumented[0xE4]; }; # pragma pack() diff --git a/include/libg1m/formatutils.h b/include/libg1m/formatutils.h index 70447c6..55c11ab 100644 --- a/include/libg1m/formatutils.h +++ b/include/libg1m/formatutils.h @@ -37,7 +37,8 @@ extern "C" { /* Standard header */ # define g1m_stdflag_check1 0x0001 /* check first control value */ # define g1m_stdflag_check2 0x0002 /* check second control value */ -# define g1m_stdflag_sub 0x0004 /* is followed by a prizm_subheader */ +# define g1m_stdflag_sub 0x0004 /* is followed by a standard subheader */ +# define g1m_stdflag_pic 0x0008 /* is followed by a picture subheader */ extern int g1m_maketype_std(const char *path, unsigned char *main_id, unsigned char *subtype, const char **info, unsigned int *flags, diff --git a/include/libg1m/internals.h b/include/libg1m/internals.h index 846e8f1..4a8c7a7 100644 --- a/include/libg1m/internals.h +++ b/include/libg1m/internals.h @@ -124,10 +124,11 @@ extern int g1m_decode_std_cg_##NAME(g1m_t **handle, g1m_buffer_t *buffer, \ extern int g1m_decode_std_cp_##NAME(g1m_t **handle, g1m_buffer_t *buffer, \ struct standard_header *std, struct standard_subheader *sub, \ struct _classpad_subheader *cp, uint32_t *check); +# define G1M_PICFUNC(NAME) \ +extern int g1m_decode_std_##NAME(g1m_t **handle, g1m_buffer_t *buffer, \ + struct standard_header *std, struct standard_picheader *pic); /* standard funcs */ -G1M_STDFUNC(g3p) -G1M_STDFUNC(c2p) G1M_STDFUNC(mcs) G1M_STDFUNC(eact) G1M_STDFUNC(addin) @@ -139,6 +140,8 @@ G1M_CPFUNC(addin) G1M_PRIZMFUNC(addin) G1M_PRIZMFUNC(lang) G1M_PRIZMFUNC(fkey) +G1M_PICFUNC(g3p) +G1M_PICFUNC(c2p) /* ************************************************************************** */ /* MCS-specific decoding functions */ /* ************************************************************************** */ diff --git a/include/libg1m/picture.h b/include/libg1m/picture.h index 9f9afa9..0694804 100644 --- a/include/libg1m/picture.h +++ b/include/libg1m/picture.h @@ -18,10 +18,10 @@ * ************************************************************************** */ #ifndef LIBG1M_PICTURE_H # define LIBG1M_PICTURE_H -# ifdef __cplusplus -extern "C" { -# endif +/* ************************************************************************** */ +/* Picture formats */ +/* ************************************************************************** */ /* picture format */ typedef int g1m_pictureformat_t; # define g1m_pictureformat_1bit 0x0100 @@ -36,7 +36,9 @@ typedef int g1m_pictureformat_t; # define g1m_pictureformat_4bit_mono 0x0430 # define g1m_pictureformat_16bit 0x1000 -/* get size of the raw buffer */ +/* ************************************************************************** */ +/* Picture sizes */ +/* ************************************************************************** */ # define g1m_picturesize_1bit(W, H) \ ((((W) / 8) + !!((W) % 8)) * (H)) # define g1m_picturesize_1bit_packed(W, H) \ @@ -45,6 +47,7 @@ typedef int g1m_pictureformat_t; g1m_picturesize_1bit_packed(W, H) # define g1m_picturesize_1bit_packed_old(W, H) \ g1m_picturesize_1bit_packed(W, H) + # define g1m_picturesize_4bit_color(W, H) \ (4 * g1m_picturesize_1bit_packed_old(W, H)) # define g1m_picturesize_4bit_mono(W, H) \ @@ -63,15 +66,4 @@ typedef int g1m_pictureformat_t; # define g1m_picturesize_16bit(W, H) \ ((W) * (H) * 2) -/* encoding and decoding functions */ -extern int g1m_decode_picture(uint32_t **pixels, - g1m_pictureformat_t format, const unsigned char *raw, - unsigned int width, unsigned int height); -extern int g1m_encode_picture(const uint32_t **pixels, - g1m_pictureformat_t format, unsigned char *raw, - unsigned int width, unsigned int height); - -# ifdef __cplusplus -} -# endif #endif /* LIBG1M_PICTURE_H */ diff --git a/src/decode/std.c b/src/decode/std.c index e118650..c073df6 100644 --- a/src/decode/std.c +++ b/src/decode/std.c @@ -191,6 +191,34 @@ int g1m_decode_std(g1m_t **handle, const char *path, g1m_buffer_t *buffer, return (0); } + /* check if there is a standard picture header */ + if (mflags & g1m_stdflag_pic) { + log_info("Has a Standard Picture Header!"); + DREAD(hd, standard_picheader) + + /* correct the type; TODO: hardcode less */ + type = g1m_type_picture; + if (!memcmp(hd.cp, "CC", 2)) + platform = g1m_platform_cp; + else if (!memcmp(hd.cp, "CP", 2)) + platform = g1m_platform_cg; + else { + log_error("Unknown magic sequence: '%.2s'", hd.cp); + return (g1m_error_magic); + } + + /* find the decode function */ + if (find_decode_function(platform, type, &rd)) + return (g1m_error_magic); + + /* call it */ + err = (*rd)(handle, buffer, std, &hd); + if (err) return (err); + + /* no error! */ + return (0); + } + /* find the decode function */ if (find_decode_function(platform, type, &rd)) return (g1m_error_magic); diff --git a/src/decode/std/picture.c b/src/decode/std/picture.c index a38214f..c746600 100644 --- a/src/decode/std/picture.c +++ b/src/decode/std/picture.c @@ -19,6 +19,9 @@ #include #include +/* ************************************************************************** */ +/* Obfuscation-related functions */ +/* ************************************************************************** */ /** * g3p_deobfuscate: * De-obfuscate the image data. @@ -31,10 +34,13 @@ static void g3p_deobfuscate(uint8_t *buf, size_t n) { while (n--) { int byte = *buf; - *buf++ = (byte >> 3) | ((byte & 0x7) << 5); + *buf++ = ~((byte << 5) | (byte >> 3)) & 0xFF; } } +/* ************************************************************************** */ +/* Prizm Picture decoding function */ +/* ************************************************************************** */ /** * g1m_decode_std_g3p: * Decode a G3P file. @@ -42,93 +48,80 @@ static void g3p_deobfuscate(uint8_t *buf, size_t n) * @arg handle the handle. * @arg buffer the buffer to read from. * @arg std the standard header. + * @arg pic the standard picture header. * @return the error code (0 if ok). */ int g1m_decode_std_g3p(g1m_t **h, g1m_buffer_t *buffer, - struct standard_header *std) + struct standard_header *std, struct standard_picheader *pic) { int err; *h = NULL; uint8_t *defbuf = NULL, *infbuf = NULL; - /* get the G3P global header */ - DREAD(hd, g3p_subheader) - hd.g3p_size = be32toh(hd.g3p_size); - - /* check magic */ - if (memcmp(hd.magic, "CP", 2)) { - log_fatal("could not read 'CP'."); - return (g1m_error_magic); - } - /* start a checksum */ uint32_t check = g1m_checksum32((void*)std, sizeof(struct standard_header), 0); + check = g1m_checksum32((void*)pic, + sizeof(struct standard_picheader), check); /* read the image header */ - DREAD(ihd, g3p_imageheader) - check = g1m_checksum32(&ihd, sizeof(struct g3p_imageheader), check); - ihd.df_size = be32toh(ihd.df_size); - ihd.width = be16toh(ihd.width); - ihd.height = be16toh(ihd.height); - ihd.color_depth = be16toh(ihd.color_depth); - ihd.data_size = be32toh(ihd.data_size); - - /* check some little things */ - int is_obfuscated = - ((std->obfuscated + 8) & 0xff) != ((std->filesize & 0xff00) >> 8); - int has_footer = 1; /* might change? */ - size_t deflated_image_size = ihd.data_size; + DREAD(ihd, g3p_subheader) + check = g1m_checksum32(&ihd, sizeof(struct g3p_subheader), check); + unsigned int width = be16toh(ihd.width), height = be16toh(ihd.height); + int color_depth = be16toh(ihd.color_depth); /* log info */ - log_info("Width: %" PRIu16 "px, height: %" PRIu16 "px", - ihd.width, ihd.height); + log_info("Width: %upx, height: %upx", width, height); log_info("Pixel depth: %s", - (ihd.color_depth == g3p_color_4bit) ? "4-bit" : "16-bit"); - log_info("Deflated image length: %" PRIuSIZE "o", deflated_image_size); - log_info("Is obfuscated: %s", is_obfuscated ? "yes" : "no"); + (color_depth == g3p_color_4bit) ? "4-bit" : "16-bit"); + log_info("Generator ID: 0x%04X", be16toh(ihd.generator_id)); + log_info("-"); - /* read image: FIXME allocate in heap? */ + /* read deflated image */ + size_t deflated_image_size = be32toh(ihd.data_size) - 6; + log_info("Reading %" PRIuSIZE "B of deflated data", deflated_image_size); err = g1m_error_alloc; defbuf = malloc(deflated_image_size); if (!defbuf) goto fail; READ(defbuf, deflated_image_size) - /* read footer and check sum */ - if (has_footer) { - DREAD(ft, g3p_imagefooter); - ft.checksum = be32toh(ft.checksum); - - uLong adl = adler32(0, defbuf, deflated_image_size); - if (adl != ft.checksum) { - log_fatal("Incorrect Adler32 checksum!"); - log_fatal("Expected %" PRIu32 ", got %lu", - ft.checksum, adl); - return (g1m_error_magic); - } + /* unobfuscate if required */ + int is_obfuscated = + ((std->obfuscated + 8) & 0xff) != ((std->filesize & 0xff00) >> 8); + if (is_obfuscated) { + log_info("Is obfuscated, let's deobfuscate!"); + g3p_deobfuscate(defbuf, deflated_image_size); } - /* unobfuscate if required */ - if (is_obfuscated) g3p_deobfuscate(defbuf, deflated_image_size); - /* make the destination buffer */ - size_t rawsize = ihd.color_depth == g3p_color_4bit - ? g1m_picturesize_4bit_code(ihd.width, ihd.height) - : g1m_picturesize_16bit(ihd.width, ihd.height); + size_t rawsize = color_depth == g3p_color_4bit + ? g1m_picturesize_4bit_code(width, height) + : g1m_picturesize_16bit(width, height); err = g1m_error_alloc; infbuf = malloc(rawsize); if (!infbuf) goto fail; /* uncompress */ - err = g1m_error_alloc; uLongf inflated_size = 0L; // rawsize? int z_err = uncompress(infbuf, &inflated_size, defbuf, deflated_image_size); if (z_err) { log_fatal("Zlib error: error #%d", z_err); + err = g1m_error_magic; goto fail; } free(defbuf); defbuf = NULL; + /* check the checksum */ + uint32_t checksum; READ(&checksum, sizeof(uint32_t)) + uLong adl = adler32(0, defbuf, deflated_image_size); + if (adl != (uLong)checksum) { + log_fatal("Incorrect Adler32 checksum!"); + log_fatal("Expected 0x%08" PRIX32 ", got 0x%08lX", + checksum, adl); + err = g1m_error_checksum; + goto fail; + } + /* make the handle */ err = g1m_make_picture(h, ihd.width, ihd.height); if (err) goto fail; @@ -150,24 +143,27 @@ fail: return (err); } +/* ************************************************************************** */ +/* Classpad Picture decoding function */ +/* ************************************************************************** */ /** * g1m_decode_std_c2p: * Decode Classpad images. * * @arg handle the handle. * @arg buffer the buffer to read from. + * @arg std the standard header. + * @arg pic the standard picture header. * @return the error code (0 if ok). */ int g1m_decode_std_c2p(g1m_t **h, g1m_buffer_t *buffer, - struct standard_header *std) + struct standard_header *std, struct standard_picheader *pic) { - (void)std; - (void)h; - (void)buffer; + (void)h; (void)buffer; + (void)std; (void)pic; /* TODO */ log_info("C2P files are not managed yet."); - log_info("Size is %" PRIuSIZE "B", sizeof(struct c2p_subheader)); /* no error */ return (g1m_error_magic); diff --git a/src/manage/mcs.c b/src/manage/mcs.c index b40d08b..db08a55 100644 --- a/src/manage/mcs.c +++ b/src/manage/mcs.c @@ -17,6 +17,7 @@ * along with libg1m; if not, see . * ************************************************************************** */ #include +#include #define MCS_CHUNK_SIZE 16 /* ************************************************************************** */ @@ -110,3 +111,34 @@ found:; *tofile = *pfile; return (0); } + +/* ************************************************************************** */ +/* Reorganize an MCS handle for encoding */ +/* ************************************************************************** */ +/** + * g1m_mcs_sort: + * Sort an MCS archive. + * + * @arg handle the MCS archive handle. + * @return the error code (0 if ok). + */ + +typedef int (*g1m_compare_mcsfiles_t)(const void*, const void*); +int g1m_mcs_sort(g1m_t *handle) +{ + if (handle->type != g1m_type_mcs) return (g1m_error_op); + if (handle->platform != g1m_platform_fx) return (g1m_error_op); + + /* correct each head */ + for (int i = 0; i < handle->count; i++) { + int err = g1m_correct_mcsfile_head(&handle->files[i]->head); + if (err) return (err); + } + + /* sort */ + qsort(handle->files, handle->count, sizeof(g1m_mcsfile_t*), + (g1m_compare_mcsfiles_t)g1m_compare_mcsfiles); + + /* TODO: check for duplicates */ + return (0); +} diff --git a/src/type/mcs.c b/src/type/mcs.c index 24fec59..7941d12 100644 --- a/src/type/mcs.c +++ b/src/type/mcs.c @@ -27,6 +27,7 @@ #define arg_is_num 0x0002 #define arg_is_let 0x0000 #define weight_by_gid 0x0004 +#define groupable 0x0008 /* Correspondance type */ struct type_corresp { @@ -69,7 +70,9 @@ struct group_corresp { static struct group_corresp mcs_groups[] = { /* Main Memory */ {"SETUP", noarg, (struct type_corresp[]){ - {0x14, NULL /* "SETUP" */, 0, "$GLOBAL", + {0x14, "SETUP", 0, "$GLOBAL", + "setup", g1m_mcstype_setup}, + {0x00, "SETUP", 0, "$GLOBAL", /* setup is also with 0x00...? */ "setup", g1m_mcstype_setup}, TTERM }}, @@ -181,31 +184,39 @@ static struct group_corresp mcs_groups[] = { TTERM }}, {"STAT", noarg, (struct type_corresp[]){ - {0xFE, NULL /* G_CND/C_CND/STATap/G_CNDEX/STATapX */, 0, "@STAT", - "stat data", 0x00}, + {0xFE, "G_CND", 0, "@STAT", + "stat data?", 0x00}, + {0xFE, "G_CNDEX", 0, "@STAT", + "stat data?", 0x00}, + {0xFE, "C_CND", 0, "@STAT", + "stat data?", 0x00}, + {0xFE, "STATap", 0, "@STAT", + "stat data?", 0x00}, + {0xFE, "STATapX", 0, "@STAT", + "stat data?", 0x00}, {0x05, "STATV", arg | arg_is_num, "main", - "stat data 2?", 0x00}, + "stat data?", 0x00}, TTERM }}, {"TABLE", noarg, (struct type_corresp[]){ - {0xFE, NULL /* RANGE */, 0, "@TABLE", + {0xFE, "RANGE", 0, "@TABLE", "range data?", 0x00}, TTERM }}, {"3DGRAPH", noarg, (struct type_corresp[]){ - {0xFE, NULL /* AREACOL */, 0, "@3DGRAPH", + {0xFE, "AREACOL", 0, "@3DGRAPH", "???", 0x00}, - {0xFE, NULL /* LINECOL */, 0, "@3DGRAPH", + {0xFE, "LINECOL", 0, "@3DGRAPH", "???", 0x00}, - {0xFE, NULL /* SELECT */, 0, "@3DGRAPH", + {0xFE, "SELECT", 0, "@3DGRAPH", "???", 0x00}, - {0xFE, NULL /* TEMPLATE */, 0, "@3DGRAPH", + {0xFE, "TEMPLATE", 0, "@3DGRAPH", "???", 0x00}, - {0xFE, NULL /* SETUP */, 0, "@3DGRAPH", + {0xFE, "SETUP", 0, "@3DGRAPH", "???", 0x00}, - {0xFE, NULL /* TYPE */, 0, "@3DGRAPH", + {0xFE, "TYPE", 0, "@3DGRAPH", "???", 0x00}, - {0xFE, NULL /* VWIN */, 0, "@3DGRAPH", + {0xFE, "VWIN", 0, "@3DGRAPH", "???", 0x00}, {0xFE, "Z", arg | arg_is_num /* 1 to 3 */, "@3DGRAPH", "???", 0x00}, @@ -217,30 +228,30 @@ static struct group_corresp mcs_groups[] = { TTERM }}, {"@PROBSIM", noarg, (struct type_corresp[]){ - {0xFE, NULL /* ProbRand */, 0, "@PROBSIM", + {0xFE, "ProbRand", 0, "@PROBSIM", "???", 0x00}, - {0xFE, NULL /* ProbAdv */, 0, "@PROBSIM", + {0xFE, "ProbAdv", 0, "@PROBSIM", "???", 0x00}, - {0xFE, NULL /* ProbSeed */, 0, "@PROBSIM", + {0xFE, "ProbSeed", 0, "@PROBSIM", "???", 0x00}, - {0xFE, NULL /* ProbSet */, 0, "@PROBSIM", + {0xFE, "ProbSet", 0, "@PROBSIM", "???", 0x00}, - {0xFE, NULL /* ProbVer */, 0, "@PROBSIM", + {0xFE, "ProbVer", 0, "@PROBSIM", "???", 0x00}, TTERM }}, {"PICTPLOT", noarg, (struct type_corresp[]){ {0x05, "PGRAPH", arg | arg_is_num /* 0 to 3 */, "main", "???", 0x00}, - {0xFE, NULL /* PATH */, 0, "@PICTPLT", + {0xFE, "PATH", 0, "@PICTPLT", "???", 0x00}, - {0xFE, NULL /* @SC_CNT */, 0, "@PICTPLT", + {0xFE, "@SC_CNT", 0, "@PICTPLT", "???", 0x00}, - {0xFE, NULL /* @SG_CND */, 0, "@PICTPLT", + {0xFE, "@SG_CND", 0, "@PICTPLT", "???", 0x00}, - {0xFE, NULL /* @SG_CDX */, 0, "@PICTPLT", + {0xFE, "@SG_CDX", 0, "@PICTPLT", "???", 0x00}, - {0xFE, NULL /* SETUP */, 0, "@PICTPLT", + {0xFE, "SETUP", 0, "@PICTPLT", "???", 0x00}, TTERM }}, @@ -339,17 +350,18 @@ int g1m_maketype_mcs(g1m_mcshead_t *head, continue; /* check if pattern */ - if (!t->name) - break; - size_t fl = strlen(t->name); - if (strncmp(t->name, fname, fl)) - continue; - fid = 0; - if ((t->flags & arg) - && get_number(&fname[fl], &fid, t->flags & arg_is_num)) - continue; - if (t->flags & weight_by_gid) - fid |= (gid << 5); + if (t->name) { + size_t fl = strlen(t->name); + if (strncmp(t->name, fname, fl)) + continue; + + fid = 0; + if ((t->flags & arg) + && get_number(&fname[fl], &fid, t->flags & arg_is_num)) + continue; + if (t->flags & weight_by_gid) + fid |= (gid << 5); + } break; } if (!t->dirname) @@ -379,8 +391,10 @@ notfound: int g1m_correct_mcsfile_head(g1m_mcshead_t *head) { /* check if there is a type */ - if (!head || !head->type) - return (0); + if (!head) return (0); + if (!head->type + && (!head->_group[0] || !head->name[0] || !head->_dirname[0])) + return (g1m_error_op); /* find the group/type */ struct group_corresp *g; @@ -442,8 +456,73 @@ found:; sprintf(nm, "%s%d", t->name, namid); else sprintf(nm, "%s%c", t->name, namid + 'A' - 1); - } + } else if (t->name) + strcpy(nm, t->name); /* no error */ return (0); } + +/* ************************************************************************** */ +/* Compare function */ +/* ************************************************************************** */ +/** + * find_offset_in_group: + * Find offset in a group. + * + * @arg group the group correspondance. + * @arg file the file. + * @return the offset (-1 if not there). + */ + +static int find_offset_in_group(struct group_corresp *g, + const g1m_mcsfile_t *file) +{ + /* group check */ + if (strcmp((char*)file->head._group, g->name)) + return (-1); + + /* file check */ + struct type_corresp *f; int i; + for (f = g->types, i = 0; f->info; f++, i++) { + if (strcmp((char*)file->head._group, f->name) + || file->head._rawtype != f->rawtype) + continue; + + return (i); + } + + /* not found, but shouldn't look for it in other groups */ + return (-2); +} + +/** + * g1m_compare_mcsfiles: + * Compare MCS files using their heads, for sorting. + * + * @arg first the first file. + * @arg second the second file. + * @return negative value if the 1st is considered less than the 2nd, + * positive value otherwise. + */ + +int g1m_compare_mcsfiles(const g1m_mcsfile_t *first, + const g1m_mcsfile_t *second) +{ + /* find the group correspondance */ + int offset1 = -1, offset2 = -1; + struct group_corresp *g; for (g = mcs_groups; g->types; g++) { + /* get offsets */ + if (offset1 >= -1) offset1 = find_offset_in_group(g, first); + if (offset2 >= -1) offset2 = find_offset_in_group(g, second); + + /* check if the first one corresponds */ + if (offset1 < 0 && offset2 < 0) continue; + if (offset1 == offset2) break; + if (offset1 < offset2) return (-1); + if (offset1 > offset2) return (1); + } + + /* so they're equal, huh... */ + return (0); +} diff --git a/src/type/std.c b/src/type/std.c index 93aeff9..f7dd2d4 100644 --- a/src/type/std.c +++ b/src/type/std.c @@ -21,6 +21,7 @@ #define f_c1 g1m_stdflag_check1 #define f_c2 g1m_stdflag_check2 #define f_sub g1m_stdflag_sub +#define f_pic g1m_stdflag_pic /* ************************************************************************** */ /* Local types */ @@ -86,7 +87,7 @@ static struct main_info types[] = { g1m_platform_fx, g1m_type_eact}, /* Pictures */ - {"\x7d" magic_common, "fx-CG picture", f_c1 | f_c2, + {"\x7d" magic_common, "fx-CG picture", f_c1 | f_c2 | f_pic, g1m_platform_cg, g1m_type_pict}, TTERM @@ -102,7 +103,7 @@ static struct main_info types[] = { /* CASIO (only used for c2p...?) */ {"CASIO\0\0\0", (struct type_info[]){ - {"c2p\0\0\0", "Classpad picture", 0, + {"c2p\0\0\0", "Classpad picture", f_pic, g1m_platform_cp, g1m_type_pict}, TTERM @@ -140,15 +141,15 @@ static struct ext_corresp ext_types[] = { {"g1e", "fx e-activity", g1m_platform_fx, g1m_type_eact, 0}, /* fx-CP types */ - {"c2p", "classpad picture", g1m_platform_cp, g1m_type_pict, 0}, {"c1a", "classpad add-in", g1m_platform_cp, g1m_type_addin, f_sub}, + {"c2p", "classpad picture", g1m_platform_cp, g1m_type_pict, f_pic}, /* fx-CG types */ {"g3l", "fx-CG language file", g1m_platform_cg, g1m_type_lang, f_sub}, {"g3n", "fx-CG fkeys file", g1m_platform_cg, g1m_type_fkey, f_sub}, {"g3a", "fx-CG add-in", g1m_platform_cg, g1m_type_addin, f_sub}, {"g3e", "fx-CG e-activity", g1m_platform_cg, g1m_type_eact, 0}, - {"g3p", "fx-CG picture", g1m_platform_cg, g1m_type_pict, 0}, + {"g3p", "fx-CG picture", g1m_platform_cg, g1m_type_pict, f_pic}, /* sentinel */ {NULL, NULL, 0, 0, 0}