Added MCS thingies, started correcting picture decoding
This commit is contained in:
parent
598a065a65
commit
cba16a37a3
|
@ -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 ;;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
/* ************************************************************************** */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
151
src/type/mcs.c
151
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);
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
|
|
Reference in New Issue