cake
/
libg1m
Archived
1
0
Fork 0

Added MCS thingies, started correcting picture decoding

This commit is contained in:
Thomas Touhey 2017-03-21 02:10:01 +01:00
parent 598a065a65
commit cba16a37a3
13 changed files with 352 additions and 213 deletions

2
configure vendored
View File

@ -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 ;;

View File

@ -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);

View File

@ -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 <libg1m/format/std/addin.h>

View File

@ -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

View File

@ -19,55 +19,25 @@
#ifndef LIBG1M_FORMAT_STD_PICTURE_H
# define LIBG1M_FORMAT_STD_PICTURE_H
# include <stdint.h>
# 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()

View File

@ -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,

View File

@ -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 */
/* ************************************************************************** */

View File

@ -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 */

View File

@ -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);

View File

@ -19,6 +19,9 @@
#include <libg1m/internals.h>
#include <zlib.h>
/* ************************************************************************** */
/* 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);

View File

@ -17,6 +17,7 @@
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libg1m/internals.h>
#include <stdlib.h>
#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);
}

View File

@ -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);
}

View File

@ -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}