Finished rewriting of most things, corrected Prizm/CP headers support, still a weird bug to solve
This commit is contained in:
parent
ad3fb2fe3e
commit
43c58008fa
|
@ -13,9 +13,10 @@ Thanks to:
|
|||
- Teamfx for complementary information;
|
||||
- KermMartian (from Cemetech) for its reverse engineering on Prizm-related
|
||||
formats and test files;
|
||||
- Amazonka (from Cemetech) for its research on G3L/G3N;
|
||||
- Florian Birée for its regrouped documentation (Casetta), like for tokens;
|
||||
- Yves-Marie Morgan for opening Casemul's source code;
|
||||
- Tom Wheeley for making CaS a free software;
|
||||
- Him and Tom Lynn for documenting the legacy protocol (9700);
|
||||
- Zezombye (from Planète Casio) for its research on some MCS formats;
|
||||
- Zezombye (from Planète Casio) for its research on some MCS file formats;
|
||||
- Other people at **Planète Casio** for their support!
|
||||
|
|
|
@ -77,7 +77,7 @@ extern const char *g1m_error_strings[];
|
|||
/* Main functions */
|
||||
/* ************************************************************************** */
|
||||
/* open and free a handle */
|
||||
extern int g1m_decode(g1m_t *handle, const char *path, g1m_buffer_t *buffer,
|
||||
extern int g1m_decode(g1m_t **handle, const char *path, g1m_buffer_t *buffer,
|
||||
g1m_type_t allowed_types);
|
||||
extern void g1m_free(g1m_t *handle);
|
||||
|
||||
|
@ -90,8 +90,13 @@ extern int g1m_fopen(g1m_t **handle, const char *path, FILE *stream,
|
|||
#endif
|
||||
|
||||
/* Make a handle */
|
||||
extern int g1m_make_mcs(g1m_t **h, int count);
|
||||
extern int g1m_make_picture(g1m_t **h, unsigned int width, unsigned int height);
|
||||
extern int g1m_make_mcs(g1m_t **handle, int count);
|
||||
extern int g1m_make_fkey(g1m_t **handle, g1m_platform_t platform, int count);
|
||||
extern int g1m_make_lang(g1m_t **handle, g1m_platform_t platform, int count);
|
||||
extern int g1m_make_picture(g1m_t **handle,
|
||||
unsigned int width, unsigned int height);
|
||||
extern int g1m_make_addin(g1m_t **h, g1m_platform_t platform,
|
||||
const g1m_version_t *version, const time_t *created);
|
||||
/* ************************************************************************** */
|
||||
/* Main MCS functions */
|
||||
/* ************************************************************************** */
|
||||
|
@ -133,6 +138,15 @@ extern int g1m_decode_casfile_part(g1m_mcsfile_t *file, g1m_buffer_t *buffer);
|
|||
extern int g1m_mcs_insert(g1m_t *handle, const g1m_mcshead_t *head,
|
||||
g1m_mcsfile_t **tofile);
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Miscallaneous utilities */
|
||||
/* ************************************************************************** */
|
||||
/* Version decoding/encoding */
|
||||
extern int g1m_decode_version(const char *raw, g1m_version_t *version);
|
||||
|
||||
/* Date decoding/encoding */
|
||||
extern int g1m_decode_date(const char *raw, time_t *date);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
|
|
@ -75,7 +75,6 @@ struct standard_header {
|
|||
*
|
||||
* We also thought the subtype was only one-byte long, but the C2P came along
|
||||
* with its "c2p\0\0\0" subtype.
|
||||
*
|
||||
* All main ID/types correspondances are in the `src/utils/type.c` file.
|
||||
* From a user program, you can use the functions
|
||||
* in `include/libg1m/formatutils.h`.
|
||||
|
@ -83,7 +82,120 @@ struct standard_header {
|
|||
* After the Standard Header is read and the type is read, we have parts,
|
||||
* each with their own subheaders and their own subtilities.
|
||||
*
|
||||
* Where do you want to start? Pick your poison. */
|
||||
* Some Prizm/Classpad-related formats (language, fkeys, add-ins) use a
|
||||
* common subheader followed by a platform-specific subheader (which is the
|
||||
* same size of Prizm and Classpad, but doesn't seem to have the same
|
||||
* field organization). Here is the common subheader structure: */
|
||||
|
||||
struct standard_subheader {
|
||||
/* checksum */
|
||||
uint32_t checksum;
|
||||
|
||||
/* file type:
|
||||
* - 0x01: add-in;
|
||||
* - 0x02: function keys;
|
||||
* - 0x04: language files; */
|
||||
uint8_t filetype;
|
||||
|
||||
/* platform:
|
||||
* - 0x00: fx-CP;
|
||||
* - 0x01: Prizm */
|
||||
uint8_t platform;
|
||||
|
||||
/* unknown */
|
||||
uint8_t _unknown0[8];
|
||||
|
||||
/* control:
|
||||
* - for a G3A: filesize - 0x7000 - 4
|
||||
* - for a C1A: filesize - 0x1000 - 4 */
|
||||
uint32_t control;
|
||||
|
||||
/* unknown */
|
||||
uint8_t _unknown1[4];
|
||||
|
||||
/* message zone size - unreliable (valid could have zero) */
|
||||
uint32_t message_zone_size;
|
||||
|
||||
/* model; for C1A : GY437 */
|
||||
uint8_t models[6];
|
||||
|
||||
/* title/language name */
|
||||
uint8_t title[28];
|
||||
|
||||
/* filesize */
|
||||
uint32_t filesize;
|
||||
|
||||
/* internal name */
|
||||
uint8_t internal_name[11];
|
||||
|
||||
/* language labels */
|
||||
uint8_t labels[8][24];
|
||||
|
||||
/* eAct strip flag (0x00: can't be used, 0x01: can be used) */
|
||||
uint8_t eact_strip_flag;
|
||||
|
||||
/* unknown */
|
||||
uint8_t _unknown2[4];
|
||||
|
||||
/* version: MM.mm.ffff */
|
||||
uint8_t version[10];
|
||||
|
||||
/* unknown */
|
||||
uint8_t _unknown3[2];
|
||||
|
||||
/* timestamp: YYYY.MMDD.HHmm */
|
||||
uint8_t timestamp[14];
|
||||
};
|
||||
|
||||
/* Here is the Prizm-specific subheader: */
|
||||
|
||||
struct _prizm_subheader {
|
||||
/* unknown */
|
||||
uint8_t _unknown4[38];
|
||||
|
||||
/* eAct strip labels */
|
||||
uint8_t eact_strip_labels[8][36];
|
||||
|
||||
/* eAct icon */
|
||||
uint8_t icon[0x300];
|
||||
|
||||
/* unknown stuff */
|
||||
uint8_t _unknown5[0x90C];
|
||||
|
||||
/* language name (null terminated?) */
|
||||
uint8_t language_name[16];
|
||||
|
||||
/* language salutation (null terminated?) */
|
||||
uint8_t language_salutation[16];
|
||||
|
||||
/* filename (extension included) */
|
||||
uint8_t filename[0x144];
|
||||
};
|
||||
|
||||
/* And here is the Classpad-specific subheader: */
|
||||
|
||||
struct _classpad_subheader {
|
||||
/* unknown */
|
||||
uint8_t _unknown4[0x46];
|
||||
|
||||
/* the C1A filename */
|
||||
uint8_t filename[0x144];
|
||||
|
||||
/* unknown */
|
||||
uint8_t _unknown5[0x2C];
|
||||
|
||||
/* icon (maybe 46x30 pixels? packed 1-bit) */
|
||||
uint8_t icon[172];
|
||||
|
||||
/* unknown */
|
||||
uint8_t _unknown3[0xC54];
|
||||
};
|
||||
|
||||
/* Also, if there is a Standard Subheader, there is a footer at the end of the
|
||||
* 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. */
|
||||
|
||||
# pragma pack()
|
||||
# include <libg1m/format/std/addin.h>
|
||||
|
|
|
@ -80,116 +80,26 @@ struct g1a_subheader {
|
|||
/* ************************************************************************** */
|
||||
/* Classpad and Prizm add-ins (C1A, G3A) */
|
||||
/* ************************************************************************** */
|
||||
/* The two formats are identified the same way in the standard header, but
|
||||
* some of the header parts are different, until the header just stops being
|
||||
* the same.
|
||||
/* The two formats both have the Standard Subheader, then, for the C1A,
|
||||
* the Classpad-specific subheader, and for the G3A, the Prizm-specific
|
||||
* subheader.
|
||||
*
|
||||
* Here's the common parts of their headers: */
|
||||
|
||||
struct addin_cp_subheader {
|
||||
/* byte checksum: 0x0000 to 0x001F (standard header)
|
||||
* and 0x0024 to EOF (everything after this checksum), minus 4. */
|
||||
uint32_t checksum;
|
||||
|
||||
/* magic sequence to identify addin type:
|
||||
* - {0x01, 0x01} for the Prizm (G3A);
|
||||
* - {0x01, 0x00} for C1A. */
|
||||
uint8_t magic[2];
|
||||
|
||||
/* undocumented */
|
||||
uint8_t _unknown[8];
|
||||
|
||||
/* control:
|
||||
* - for a G3A: filesize - 0x7000 - 4
|
||||
* - for a C1A: filesize - 0x1000 - 4*/
|
||||
uint32_t control;
|
||||
|
||||
/* undocumented */
|
||||
uint8_t _unknown2[8];
|
||||
|
||||
/* for C1A: "GY437" */
|
||||
uint8_t model[6];
|
||||
|
||||
/* title (zero terminated) */
|
||||
uint8_t title[16];
|
||||
|
||||
/* undocumented */
|
||||
uint8_t undocumented3[12];
|
||||
|
||||
/* filesize */
|
||||
uint32_t filesize;
|
||||
|
||||
/* internal name (preceded by @, filled up with zeros */
|
||||
uint8_t internal_name[11];
|
||||
|
||||
/* language labels */
|
||||
uint8_t language_1_label[24];
|
||||
uint8_t language_2_label[24];
|
||||
uint8_t language_3_label[24];
|
||||
uint8_t language_4_label[24];
|
||||
uint8_t language_5_label[24];
|
||||
uint8_t language_6_label[24];
|
||||
uint8_t language_7_label[24];
|
||||
uint8_t language_8_label[24];
|
||||
|
||||
/* eAct strip flag (0x00: cannot be used, 0x01: can be used) */
|
||||
uint8_t eact_strip_flag;
|
||||
|
||||
/* some null bytes */
|
||||
uint8_t zeroes[4];
|
||||
|
||||
/* version: "01.00.0000" then zeroes */
|
||||
uint8_t version[12];
|
||||
|
||||
/* timestamp: "2012.0903.1652" */
|
||||
uint8_t stamp[14];
|
||||
};
|
||||
|
||||
/* Then from here, the two formats diverge.
|
||||
* G3A subheader goes like this: */
|
||||
* After this, the G3A subheader looks like this: */
|
||||
|
||||
# define G3A_ICON_WIDTH 92
|
||||
# define G3A_ICON_HEIGHT 64
|
||||
struct g3a_subheader {
|
||||
/* null bytes, again */
|
||||
uint8_t zeroes2[38];
|
||||
|
||||
/* eAct strip labels */
|
||||
uint8_t eact_strip_label_1[36];
|
||||
uint8_t eact_strip_label_2[36];
|
||||
uint8_t eact_strip_label_3[36];
|
||||
uint8_t eact_strip_label_4[36];
|
||||
uint8_t eact_strip_label_5[36];
|
||||
uint8_t eact_strip_label_6[36];
|
||||
uint8_t eact_strip_label_7[36];
|
||||
uint8_t eact_strip_label_8[36];
|
||||
|
||||
/* eAct icon */
|
||||
uint8_t icon[0x300];
|
||||
|
||||
/* unused */
|
||||
uint8_t unused[0x92c];
|
||||
|
||||
/* G3A filename (seriously?!) */
|
||||
uint8_t g3a_filename[0x144];
|
||||
|
||||
/* selected and unselected icon image */
|
||||
uint8_t selected_icon_image[0x3000];
|
||||
uint8_t unselected_icon_image[0x3000];
|
||||
};
|
||||
|
||||
/* And the C1A header goes like this: */
|
||||
/* And the C1A subheader goes like this: */
|
||||
|
||||
# define C1A_ICON_WIDTH 46
|
||||
# define C1A_ICON_HEIGHT 30
|
||||
struct c1a_subheader {
|
||||
/* unknown bytes */
|
||||
uint8_t _unknown[0x46];
|
||||
|
||||
/* the C1A filename - the size is guessed with the other formats aside. */
|
||||
uint8_t filename[0x144];
|
||||
|
||||
/* again, unknown bytes */
|
||||
uint8_t _unknown2[0x2C];
|
||||
|
||||
/* this is an approximation (46x30 pixels, packed 1-bit) */
|
||||
|
|
|
@ -52,17 +52,16 @@ struct g1n_subheader {
|
|||
/* ************************************************************************** */
|
||||
/* G3L-N - Function-keys files for CG calculators */
|
||||
/* ************************************************************************** */
|
||||
/* G3L-N have exactly the same header and subheader as G3Ls, except
|
||||
* the magic field is "0201" and not "0401" like for "normal" G3Ls.
|
||||
*
|
||||
* TODO: it is unknown yet how to identify G3N files using the StandardHeader,
|
||||
* as no non-community-made one of them was found and the calculator software
|
||||
* just skips StandardHeader. It has to be found for a correct integration
|
||||
* in libg1m!
|
||||
*
|
||||
* In G3L-Ns, function keys are 64x24 1-bit images. */
|
||||
/* G3N (also named G3L-N) have exactly the same structure than G3Ls (see
|
||||
* `libg1m/format/std/lang.h`), but messages are 64x24 1-bit pictures. */
|
||||
|
||||
# define FKEY3_WIDTH 64
|
||||
# define FKEY3_HEIGHT 24
|
||||
|
||||
/* TODO: it is unknown yet how to identify G3N/G3L files using the
|
||||
* StandardHeader, as no 'official' one of them was found and the calculator
|
||||
* software just skips StandardHeader. It should be found for a better
|
||||
* integration in libg1m! */
|
||||
|
||||
# pragma pack()
|
||||
#endif /* LIBG1M_FORMAT_STD_FKEY_H */
|
||||
|
|
|
@ -52,66 +52,9 @@ struct g1l_subheader {
|
|||
/* ************************************************************************** */
|
||||
/* G3L - Language files for Prizm */
|
||||
/* ************************************************************************** */
|
||||
/* Thanks to amazonka for his (minimalist) description of the G3L format
|
||||
* at Cemetech. So the G3L format starts off with a header: */
|
||||
|
||||
struct g3l_subheader {
|
||||
/* a checksum */
|
||||
uint32_t checksum;
|
||||
|
||||
/* magic:
|
||||
* - 0x04, 0x01, 0x00, 0x00 for language files;
|
||||
* - 0x02, 0x01, 0x00, 0x00 for function key files. */
|
||||
uint8_t magic[4];
|
||||
|
||||
/* lol */
|
||||
uint8_t undocumented[14];
|
||||
|
||||
/* size of the message zone size - unreliable (valid could have zero) */
|
||||
uint32_t message_zone_size;
|
||||
|
||||
/* undocumented, again */
|
||||
uint8_t undocumented5[6];
|
||||
|
||||
/* name of the language */
|
||||
uint8_t language_name2[28];
|
||||
|
||||
/* size of the entire file */
|
||||
uint32_t filesize;
|
||||
|
||||
/* size of the entire file - starts with an '@' */
|
||||
uint8_t internal_name[8];
|
||||
|
||||
/* undocumented */
|
||||
uint8_t undocumented2[200];
|
||||
|
||||
/* version number string: "XX.XX.XXXX" */
|
||||
uint8_t version[10];
|
||||
|
||||
/* unused */
|
||||
uint8_t unused2[2];
|
||||
|
||||
/* creation time: "YYYY.MMDD.HHMM" */
|
||||
uint8_t datetime[14];
|
||||
|
||||
/* big undocumented thing */
|
||||
uint8_t undocumented3[3410];
|
||||
|
||||
/* language name (zero terminated) */
|
||||
uint8_t language_name[16];
|
||||
|
||||
/* language salutation (zero terminated) */
|
||||
uint8_t language_salutation[16];
|
||||
|
||||
/* filename (extension included) */
|
||||
uint8_t g3l_filename[16];
|
||||
|
||||
/* undocumented */
|
||||
uint8_t undocumented4[308];
|
||||
};
|
||||
|
||||
/* Then there is something amazonka names the "executable code section".
|
||||
* This is in fact the message zone. */
|
||||
/* G3L and G3N start with the StandardHeader and the Standard sub-Header,
|
||||
* then the Prizm-specific subheader. After this, both the G3L and G3N
|
||||
* have this language header: */
|
||||
|
||||
struct g3l_lang_header {
|
||||
/* sequence: '4C 59 37 35 35 00 00 00 02' (LY755 ) */
|
||||
|
@ -130,14 +73,7 @@ struct g3l_lang_header {
|
|||
/* Then we have offsets of all messages (4 bytes each),
|
||||
* then messages themselves, zero-terminated.
|
||||
*
|
||||
* The four last bytes of the files are a little footer, which is: */
|
||||
|
||||
struct g3l_footer {
|
||||
/* copy of the first checksum in the subheader */
|
||||
uint32_t checksum;
|
||||
};
|
||||
|
||||
/* This footer is not counted as part of the file. */
|
||||
* And don't forget the footer (see `libg1m/format/std.h`) */
|
||||
|
||||
# pragma pack()
|
||||
#endif /* LIBG1M_FORMAT_STD_LANG_H */
|
||||
|
|
|
@ -35,11 +35,18 @@ extern "C" {
|
|||
/* General types (`g1m_t`) */
|
||||
/* ************************************************************************** */
|
||||
/* 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 */
|
||||
extern int g1m_maketype_std(const char *path,
|
||||
unsigned char *main_id, unsigned char *subtype,
|
||||
const char **info, int *check_one, int *check_two,
|
||||
unsigned int *platform, g1m_type_t *type);
|
||||
const char **info, unsigned int *flags,
|
||||
g1m_platform_t *platform, g1m_type_t *type);
|
||||
|
||||
/* Standard Subheader */
|
||||
//# define g1m_subflag_check 0x0001
|
||||
extern int g1m_maketype_sub(int raw_type, int raw_pf, unsigned int *flags,
|
||||
g1m_type_t *type, g1m_platform_t *platform);
|
||||
/* ************************************************************************** */
|
||||
/* MCS types (`g1m_mcshead_t`/`g1m_mcsfile_t`) */
|
||||
/* ************************************************************************** */
|
||||
|
|
|
@ -71,7 +71,7 @@ typedef struct {
|
|||
|
||||
/* Add-in related data */
|
||||
char title[17];
|
||||
char internal_name[12];
|
||||
char intname[12];
|
||||
g1m_version_t version;
|
||||
time_t creation_date;
|
||||
|
||||
|
@ -93,7 +93,9 @@ typedef struct {
|
|||
|
||||
/* Picture-related data (also used for add-in icons */
|
||||
int width, height;
|
||||
uint32_t **pixels; /* 0x0RGB */
|
||||
uint32_t **pixels; /* 0x0RGB */
|
||||
uint32_t **icon_unsel; /* 0x0RGB */
|
||||
uint32_t **icon_sel; /* 0x0RGB */
|
||||
|
||||
/* E-activities related data */
|
||||
g1m_line_t *line;
|
||||
|
|
|
@ -85,8 +85,10 @@
|
|||
/* skip */
|
||||
# define SKIP(SZ) { \
|
||||
int SKIP_err = g1m_skip(buffer, SZ, NULL); \
|
||||
if (SKIP_err) return (SKIP_err); \
|
||||
}
|
||||
if (SKIP_err) return (SKIP_err); }
|
||||
# define GSKIP(SZ) \
|
||||
err = g1m_skip(buffer, SZ, NULL); \
|
||||
if (err) goto fail;
|
||||
|
||||
/* write */
|
||||
# define WRITE(BUF, SZ) \
|
||||
|
@ -97,42 +99,52 @@
|
|||
/* Decoding functions */
|
||||
/* ************************************************************************** */
|
||||
/* with expected types */
|
||||
int g1m_decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std(g1m_t **handle, const char *path, g1m_buffer_t *buffer,
|
||||
struct standard_header*, g1m_type_t expected_types);
|
||||
|
||||
/* w/o expected types */
|
||||
int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer);
|
||||
int g1m_decode_storage(g1m_t *handle, g1m_buffer_t *buffer);
|
||||
int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer);
|
||||
int g1m_decode_grc(g1m_t *handle, g1m_buffer_t *buffer);
|
||||
int g1m_decode_casemul(g1m_t **handle, g1m_buffer_t *buffer, int big_endian);
|
||||
int g1m_decode_storage(g1m_t **handle, g1m_buffer_t *buffer);
|
||||
int g1m_decode_cas(g1m_t **handle, g1m_buffer_t *buffer);
|
||||
int g1m_decode_grc(g1m_t **handle, g1m_buffer_t *buffer);
|
||||
/* ************************************************************************** */
|
||||
/* "Std"-specific decoding functions */
|
||||
/* ************************************************************************** */
|
||||
# define G1M_STDFUNC(NAME) \
|
||||
int g1m_decode_std_##NAME(g1m_t *handle, g1m_buffer_t *buffer, \
|
||||
extern int g1m_decode_std_##NAME(g1m_t **handle, g1m_buffer_t *buffer, \
|
||||
struct standard_header *std);
|
||||
# define G1M_PRIZMFUNC(NAME) \
|
||||
extern int g1m_decode_std_cg_##NAME(g1m_t **handle, g1m_buffer_t *buffer, \
|
||||
struct standard_header *std, struct standard_subheader *sub, \
|
||||
struct _prizm_subheader *pzm, uint32_t *check);
|
||||
# define G1M_CPFUNC(NAME) \
|
||||
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);
|
||||
|
||||
/* standard funcs */
|
||||
G1M_STDFUNC(g3p)
|
||||
G1M_STDFUNC(c2p)
|
||||
G1M_STDFUNC(mcs)
|
||||
G1M_STDFUNC(eact)
|
||||
G1M_STDFUNC(addin)
|
||||
G1M_STDFUNC(addin_cg)
|
||||
G1M_STDFUNC(lang)
|
||||
G1M_STDFUNC(lang_cg)
|
||||
G1M_STDFUNC(fkey)
|
||||
|
||||
/* others */
|
||||
int g1m_decode_fkey_cg_content(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
uint_fast32_t zonesize, uint32_t *pchecksum);
|
||||
/* specific funcs */
|
||||
G1M_CPFUNC(addin)
|
||||
G1M_PRIZMFUNC(addin)
|
||||
G1M_PRIZMFUNC(lang)
|
||||
G1M_PRIZMFUNC(fkey)
|
||||
/* ************************************************************************** */
|
||||
/* MCS-specific decoding functions */
|
||||
/* ************************************************************************** */
|
||||
# define G1M_MCSFUNC(NAME) \
|
||||
int g1m_decode_mcs_##NAME(g1m_mcsfile_t **handle, g1m_buffer_t *buffer, \
|
||||
extern int g1m_decode_mcs_##NAME(g1m_mcsfile_t **handle, g1m_buffer_t *buffer, \
|
||||
g1m_mcshead_t *head); \
|
||||
int g1m_announce_mcs_##NAME(const g1m_mcsfile_t *handle, size_t *sz); \
|
||||
int g1m_encode_mcs_##NAME(const g1m_mcsfile_t *handle, g1m_buffer_t *buffer);
|
||||
extern int g1m_announce_mcs_##NAME(const g1m_mcsfile_t *handle, size_t *sz); \
|
||||
extern int g1m_encode_mcs_##NAME(const g1m_mcsfile_t *handle, \
|
||||
g1m_buffer_t *buffer);
|
||||
|
||||
G1M_MCSFUNC(var)
|
||||
G1M_MCSFUNC(list)
|
||||
|
@ -172,12 +184,10 @@ G1M_CASFUNC(capture)
|
|||
/* Utilities */
|
||||
/* ************************************************************************** */
|
||||
/* Free-ing */
|
||||
void g1m_free_content(g1m_t *handle);
|
||||
void g1m_free_mcs(g1m_t *handle);
|
||||
void g1m_free_line_content(g1m_line_t *line);
|
||||
|
||||
/* Skipping */
|
||||
int g1m_skip(g1m_buffer_t *buffer, size_t size, uint_fast32_t *checksum);
|
||||
int g1m_skip(g1m_buffer_t *buffer, size_t size, uint32_t *checksum);
|
||||
|
||||
/* Checksum-ing */
|
||||
uint8_t g1m_checksum8(void *mem, size_t size);
|
||||
|
|
|
@ -47,7 +47,7 @@ int g1m_open(g1m_t **handle, const char *path,
|
|||
|
||||
/**
|
||||
* g1m_fopen:
|
||||
* Open handle using FILE* pointer.
|
||||
* Open handle using pointer on FILE.
|
||||
*
|
||||
* Will not seek, and will not keep the stream.
|
||||
* Make sure to fclose the stream after use.
|
||||
|
@ -62,31 +62,18 @@ int g1m_open(g1m_t **handle, const char *path,
|
|||
int g1m_fopen(g1m_t **handle, const char *path, FILE *stream,
|
||||
g1m_type_t expected)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* check stream */
|
||||
if (!stream) return (g1m_error_nostream);
|
||||
if (!__freadable(stream)) return (g1m_error_noread);
|
||||
|
||||
/* create the handle */
|
||||
*handle = malloc(sizeof(g1m_t));
|
||||
if (!*handle) return (g1m_error_alloc);
|
||||
|
||||
/* make the buffer */
|
||||
g1m_buffer_t buffer = {
|
||||
.cookie = stream,
|
||||
.read = g1m_filebuffer_read
|
||||
};
|
||||
|
||||
/* fill it by parsing opened file */
|
||||
if ((err = g1m_decode(*handle, path, &buffer, expected))) {
|
||||
free(*handle);
|
||||
*handle = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
||||
/* everything ok */
|
||||
return (0);
|
||||
/* decode opened file */
|
||||
return (g1m_decode(handle, path, &buffer, expected));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -235,24 +235,22 @@ int g1m_decode_casfile_part(g1m_mcsfile_t *file, g1m_buffer_t *buffer)
|
|||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_decode_cas:
|
||||
* Decode a CAS file. TODO.
|
||||
* Decode a CAS file.
|
||||
*
|
||||
* Is also sort of a guide for using the CAS MCS files.
|
||||
* The colon ':' (0x3A) is already read at this point (CAS file id.).
|
||||
*
|
||||
* @arg handle the handle to create.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @return the libg1m error.
|
||||
* @arg h the handle to create.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @return the libg1m error.
|
||||
*/
|
||||
|
||||
int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer)
|
||||
int g1m_decode_cas(g1m_t **h, g1m_buffer_t *buffer)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* prepare the handle */
|
||||
handle->type = g1m_type_mcs;
|
||||
handle->files = NULL;
|
||||
handle->_size = 0;
|
||||
/* make the handle */
|
||||
int err = g1m_make_mcs(h, 0);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* read each */
|
||||
for (handle->count = 0;;) {
|
||||
|
@ -308,7 +306,7 @@ int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer)
|
|||
|
||||
fail:
|
||||
/* END OF DA WORLD */
|
||||
g1m_free_mcs(handle);
|
||||
g1m_free(handle);
|
||||
return (err);
|
||||
}
|
||||
|
||||
|
@ -316,12 +314,12 @@ fail:
|
|||
* g1m_decode_grc:
|
||||
* Decode Graph Card file.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg handle the handle to make.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_grc(g1m_t *handle, g1m_buffer_t *buffer)
|
||||
int g1m_decode_grc(g1m_t **handle, g1m_buffer_t *buffer)
|
||||
{
|
||||
uint8_t intro[2]; READ(intro, 2) /* probably the file count? */
|
||||
uint8_t colon; READ(&colon, 1) /* read first colon */
|
||||
|
|
|
@ -298,14 +298,15 @@ static int read_list(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer,
|
|||
* g1m_decode_casemul:
|
||||
* Decode a CasEmul file.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg h the handle to make.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg big_endian whether the file is big endian or not.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer)
|
||||
int g1m_decode_casemul(g1m_t **h, g1m_buffer_t *buffer, int big_endian)
|
||||
{
|
||||
int err, big_endian = handle->platform & g1m_platflag_be;
|
||||
int err;
|
||||
|
||||
/* read the overall header's internal header end */
|
||||
struct casemul_internal_header overall_int = {
|
||||
|
@ -331,15 +332,11 @@ int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer)
|
|||
return (err);
|
||||
DREAD(src, casemul_source_header)
|
||||
|
||||
/* prepare the tab */
|
||||
handle->type = g1m_type_mcs;
|
||||
handle->platform = g1m_platform_fx;
|
||||
handle->count = 0;
|
||||
handle->_size = /* src.programs + */ src.pictures + src.matrixes +
|
||||
src.lists;
|
||||
if (!(handle->files = malloc(sizeof(g1m_mcsfile_t*) * handle->_size)))
|
||||
return (g1m_error_alloc);
|
||||
memset(handle->files, 0, sizeof(g1m_mcsfile_t*) * handle->_size);
|
||||
/* make the handle */
|
||||
err = g1m_make_mcs(h, /* src.programs + */ src.pictures + src.matrixes
|
||||
+ src.lists);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* read each program; TODO: put this in a function when token parsing
|
||||
* is managed. */
|
||||
|
@ -394,6 +391,6 @@ int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer)
|
|||
handle->platform &= ~g1m_platflag_be;
|
||||
return (0);
|
||||
fail:
|
||||
g1m_free_mcs(handle);
|
||||
g1m_free(handle);
|
||||
return (err);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
/* Check using extensions */
|
||||
/* ************************************************************************** */
|
||||
/* Decode function */
|
||||
typedef int (*decode_func)(g1m_t*, g1m_buffer_t*);
|
||||
typedef int (*decode_func)(g1m_t**, g1m_buffer_t*);
|
||||
|
||||
/* Correspondance type */
|
||||
struct corresp {
|
||||
|
@ -90,7 +90,7 @@ static int lookup_extension(const char *path, g1m_type_t types,
|
|||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode(g1m_t *handle, const char *path, g1m_buffer_t *buffer,
|
||||
int g1m_decode(g1m_t **handle, const char *path, g1m_buffer_t *buffer,
|
||||
g1m_type_t expected_types)
|
||||
{
|
||||
/* initialize the handle */
|
||||
|
@ -112,15 +112,11 @@ int g1m_decode(g1m_t *handle, const char *path, g1m_buffer_t *buffer,
|
|||
|
||||
/* identify a Casemul file */
|
||||
READ(&buf[1], 3)
|
||||
if (!memcmp(buf, "CAFS", 4)) {
|
||||
handle->platform |= g1m_platflag_be;
|
||||
int casemul_be = !memcmp(buf, "CAFS", 4);
|
||||
if (casemul_be || !memcmp(buf, "ACFS", 4)) {
|
||||
if (expected_types && !(expected_types & g1m_type_mcs))
|
||||
return (g1m_error_wrong_type);
|
||||
return (g1m_decode_casemul(handle, buffer));
|
||||
} else if (!memcmp(buf, "ACFS", 4)) {
|
||||
if (expected_types && !(expected_types & g1m_type_mcs))
|
||||
return (g1m_error_wrong_type);
|
||||
return (g1m_decode_casemul(handle, buffer));
|
||||
return (g1m_decode_casemul(handle, buffer, casemul_be));
|
||||
}
|
||||
|
||||
/* identify a standard header (send a _copy_) */
|
||||
|
|
137
src/decode/std.c
137
src/decode/std.c
|
@ -23,7 +23,7 @@
|
|||
/* Getting the parsing function */
|
||||
/* ************************************************************************** */
|
||||
/* Correspondance type */
|
||||
typedef int (*decode_func)(g1m_t*, g1m_buffer_t*, struct standard_header*);
|
||||
typedef int (*decode_func)();
|
||||
struct corresp {
|
||||
unsigned int platform;
|
||||
unsigned int type;
|
||||
|
@ -36,23 +36,22 @@ struct corresp {
|
|||
static struct corresp parsing_functions[] = {
|
||||
/* add-ins */
|
||||
{g1m_platform_fx, g1m_type_addin, FUNC(addin)},
|
||||
{g1m_platform_cg, g1m_type_addin, FUNC(addin_cg)},
|
||||
{g1m_platform_cp, g1m_type_addin, FUNC(cp_addin)},
|
||||
{g1m_platform_cg, g1m_type_addin, FUNC(cg_addin)},
|
||||
/* mcs */
|
||||
{g1m_platform_fx, g1m_type_mcs, FUNC(mcs)},
|
||||
{g1m_platform_cg, g1m_type_mcs, FUNC(mcs)},
|
||||
/* language files */
|
||||
{g1m_platform_fx, g1m_type_lang, FUNC(lang)},
|
||||
{g1m_platform_cg, g1m_type_lang, FUNC(lang_cg)},
|
||||
{g1m_platform_cg, g1m_type_lang, FUNC(cg_lang)},
|
||||
/* function keys file */
|
||||
{g1m_platform_fx, g1m_type_fkey, FUNC(fkey)},
|
||||
{g1m_platform_cg, g1m_type_fkey, FUNC(lang_cg)},
|
||||
{g1m_platform_cg, g1m_type_fkey, FUNC(cg_fkey)},
|
||||
/* e-activities */
|
||||
{g1m_platform_fx, g1m_type_eact, FUNC(eact)},
|
||||
/* pictures */
|
||||
{g1m_platform_cg, g1m_type_pict, FUNC(g3p)},
|
||||
{g1m_platform_cp, g1m_type_pict, FUNC(c2p)},
|
||||
/* storage */
|
||||
// {g1m_platform_none, g1m_type_storage, FUNC(storage)},
|
||||
|
||||
{0, 0, NULL}
|
||||
};
|
||||
|
@ -61,37 +60,18 @@ static struct corresp parsing_functions[] = {
|
|||
* find_decode_function:
|
||||
* Find the parsing function.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg path the file path.
|
||||
* @arg std pointer to the standard header.
|
||||
* @arg platform the platform.
|
||||
* @arg type the type.
|
||||
* @arg rd pointer to the decode function.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
static int find_decode_function(g1m_t *handle, const char *path,
|
||||
struct standard_header *std, decode_func *rd)
|
||||
static int find_decode_function(g1m_platform_t platform, g1m_type_t type,
|
||||
decode_func *rd)
|
||||
{
|
||||
/* get the type */
|
||||
unsigned int platform;
|
||||
g1m_type_t type;
|
||||
const char *type_string;
|
||||
int check_one, check_two;
|
||||
if (g1m_maketype_std(path, std->main_id, std->subtype, &type_string,
|
||||
&check_one, &check_two, &platform, &type))
|
||||
return (g1m_error_magic);
|
||||
log_info("Standard Header type is '%s'.", type_string);
|
||||
|
||||
/* check control bytes */
|
||||
if (check_one && std->control != ((std->filesize + 0x41) & 0xff)) {
|
||||
log_info("First control byte isn't right.");
|
||||
return (g1m_error_magic);
|
||||
} else if (check_two && std->control2 != ((std->filesize + 0xb8) & 0xff)) {
|
||||
log_info("Second control byte isn't right.");
|
||||
return (g1m_error_magic);
|
||||
}
|
||||
|
||||
/* look for corresponding parsing function */
|
||||
/* get the function */
|
||||
struct corresp *c = parsing_functions - 1;
|
||||
log_info("Type is %04X, platform is %04X", type, platform);
|
||||
while ((++c)->decode) {
|
||||
if (c->type != type)
|
||||
continue;
|
||||
|
@ -106,8 +86,6 @@ static int find_decode_function(g1m_t *handle, const char *path,
|
|||
}
|
||||
|
||||
/* set the vars */
|
||||
handle->type = type;
|
||||
handle->platform = platform;
|
||||
*rd = c->decode;
|
||||
return (0);
|
||||
}
|
||||
|
@ -119,7 +97,7 @@ static int find_decode_function(g1m_t *handle, const char *path,
|
|||
* g1m_decode_std:
|
||||
* Decode a file with standard header.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg handle the handle to create.
|
||||
* @arg path the path.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg std the standard header.
|
||||
|
@ -127,29 +105,97 @@ static int find_decode_function(g1m_t *handle, const char *path,
|
|||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std(g1m_t **handle, const char *path, g1m_buffer_t *buffer,
|
||||
struct standard_header *std, g1m_type_t expected_types)
|
||||
{
|
||||
int err;
|
||||
/* reverse the standard header */
|
||||
uint8_t *u = (uint8_t*)std;
|
||||
uint32_t check = g1m_checksum32(std, sizeof(struct standard_header), 0);
|
||||
for (size_t i = 0; i < sizeof(struct standard_header); i++)
|
||||
u[i] = ~u[i];
|
||||
|
||||
/* print header */
|
||||
log_info("Raw inverted standard header is:");
|
||||
logm_info(std, sizeof(struct standard_header));
|
||||
|
||||
/* correct standard header endianess */
|
||||
std->filesize = be32toh(std->filesize);
|
||||
std->number = be16toh(std->number);
|
||||
|
||||
/* get type */
|
||||
decode_func read_func; int err;
|
||||
if ((err = find_decode_function(handle, path, std, &read_func)))
|
||||
return (err);
|
||||
/* get the type */
|
||||
g1m_platform_t platform; g1m_type_t type;
|
||||
const char *type_string; unsigned int mflags;
|
||||
decode_func rd;
|
||||
if (g1m_maketype_std(path, std->main_id, std->subtype, &type_string,
|
||||
&mflags, &platform, &type))
|
||||
return (g1m_error_magic);
|
||||
log_info("Standard Header type is '%s'.", type_string);
|
||||
|
||||
/* check if the type is alright */
|
||||
if (expected_types && handle->type != expected_types)
|
||||
/* check control bytes */
|
||||
if (mflags & g1m_stdflag_check1
|
||||
&& std->control != ((std->filesize + 0x41) & 0xff)) {
|
||||
log_info("First control byte isn't right.");
|
||||
return (g1m_error_magic);
|
||||
} else if (mflags & g1m_stdflag_check2
|
||||
&& std->control2 != ((std->filesize + 0xb8) & 0xff)) {
|
||||
log_info("Second control byte isn't right.");
|
||||
return (g1m_error_magic);
|
||||
}
|
||||
|
||||
/* check if there is a standard subheader */
|
||||
if (mflags & g1m_stdflag_sub) {
|
||||
log_info("Has a Standard Subheader!");
|
||||
DREAD(hd, standard_subheader)
|
||||
if (g1m_maketype_sub(hd.filetype, hd.platform,
|
||||
&mflags, &type, &platform))
|
||||
return (g1m_error_magic);
|
||||
|
||||
/* TODO: controls */
|
||||
/* find the decode function */
|
||||
if (find_decode_function(platform, type, &rd))
|
||||
return (g1m_error_magic);
|
||||
if (expected_types && !(type & expected_types))
|
||||
return (g1m_error_wrong_type);
|
||||
|
||||
/* read and decode for specific platforms */
|
||||
check = g1m_checksum32(&hd.filetype,
|
||||
sizeof(struct standard_subheader) - 4, check);
|
||||
if (platform == g1m_platform_cp) {
|
||||
DREAD(shd, _classpad_subheader)
|
||||
check = g1m_checksum32(&shd, sizeof(struct _classpad_subheader),
|
||||
check);
|
||||
|
||||
/* decode the file content */
|
||||
err = (*rd)(handle, buffer, std, &hd, &shd, &check);
|
||||
if (err) return (err);
|
||||
} else if (platform == g1m_platform_cg) {
|
||||
DREAD(shd, _prizm_subheader)
|
||||
check = g1m_checksum32(&shd, sizeof(struct _prizm_subheader),
|
||||
check);
|
||||
|
||||
/* decode the file content */
|
||||
err = (*rd)(handle, buffer, std, &hd, &shd, &check);
|
||||
if (err) return (err);
|
||||
|
||||
/* read the footer */
|
||||
uint32_t endcheck; GREAD(&endcheck, sizeof(uint32_t))
|
||||
err = g1m_error_checksum;
|
||||
if (be32toh(endcheck) != be32toh(hd.checksum))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check the sum */
|
||||
err = g1m_error_checksum;
|
||||
if (check != be32toh(hd.checksum))
|
||||
goto fail;
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* find the decode function */
|
||||
if (find_decode_function(platform, type, &rd))
|
||||
return (g1m_error_magic);
|
||||
if (expected_types && !(type & expected_types))
|
||||
return (g1m_error_wrong_type);
|
||||
|
||||
/* log some data */
|
||||
|
@ -157,5 +203,8 @@ int g1m_decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer,
|
|||
log_info("Standard Header num is %" PRIu16 ".", std->number);
|
||||
|
||||
/* subdecode. */
|
||||
return ((*read_func)(handle, buffer, std));
|
||||
return ((*rd)(handle, buffer, std));
|
||||
fail:
|
||||
g1m_free(*handle); *handle = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
|
|
@ -18,71 +18,19 @@
|
|||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/**
|
||||
* addin_set_data:
|
||||
* Set handle data.
|
||||
*
|
||||
* Will take basic add-in data, put it into the right interface format
|
||||
* and store it.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg title the addin title.
|
||||
* @arg title_size the addin title size.
|
||||
* @arg internal_name the addin internal name.
|
||||
* @arg internal_name_size the addin internal name size.
|
||||
* @arg version the version string.
|
||||
* @arg creation_time the creation time.
|
||||
*/
|
||||
|
||||
static void addin_set_data(g1m_t *handle,
|
||||
char *title, size_t title_size,
|
||||
char *internal_name, size_t internal_name_size,
|
||||
char *version, char *creation_time)
|
||||
{
|
||||
/* useful vars */
|
||||
const int two = '0' + '0' * 10;
|
||||
const int four = two + '0' * 100 + '0' * 1000;
|
||||
|
||||
/* put title */
|
||||
bzero(handle->title, 17);
|
||||
strncpy(handle->title, title, title_size);
|
||||
|
||||
/* put internal name */
|
||||
bzero(handle->internal_name, 12);
|
||||
strncpy(handle->internal_name, internal_name, internal_name_size);
|
||||
|
||||
/* put version */
|
||||
#define v version
|
||||
handle->version = (g1m_version_t){
|
||||
.major = v[0] * 10 + v[1] - two,
|
||||
.minor = v[3] * 10 + v[4] - two,
|
||||
.revision = v[6] * 1000 + v[7] * 100 + v[8] * 10 + v[9] - four
|
||||
};
|
||||
#undef v
|
||||
|
||||
/* put time */
|
||||
#define c creation_time
|
||||
struct tm created = {
|
||||
.tm_year = c[0] * 1000 + c[1] * 100 + c[2] * 10 + c[3] - four,
|
||||
.tm_mon = c[5] * 10 + c[6] - two,
|
||||
.tm_mday = c[7] * 10 + c[8] - two,
|
||||
.tm_hour = c[10] * 10 + c[11] - two,
|
||||
.tm_min = c[12] * 10 + c[13] - two
|
||||
};
|
||||
handle->creation_date = mktime(&created);
|
||||
#undef c
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Add-in for the fx-9860G (G1A) */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_decode_std_addin:
|
||||
* Decodes a "normal" add-in (after Standard Header).
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg h the handle to make.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_addin(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std_addin(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -90,33 +38,34 @@ int g1m_decode_std_addin(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
|
||||
/* get the subheader */
|
||||
DREAD(hd, g1a_subheader)
|
||||
|
||||
/* correct subheader endianess */
|
||||
hd.filesize = be32toh(hd.filesize);
|
||||
|
||||
/* make the handle */
|
||||
g1m_version_t version; g1m_decode_version((char*)hd.version, &version);
|
||||
time_t created; g1m_decode_date((char*)hd.creation_date, &created);
|
||||
err = g1m_make_addin(h, g1m_platform_fx, &version, &created);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* set more data */
|
||||
strncpy(handle->title, (char*)hd.title, 8);
|
||||
handle->title[8] = 0;
|
||||
strncpy(handle->intname, (char*)hd.internal_name, 8);
|
||||
handle->intname[8] = 0;
|
||||
|
||||
/* log info about the subheader */
|
||||
log_info("internal name is '%.8s'", hd.internal_name);
|
||||
log_info("title is '%.8s'", hd.title);
|
||||
log_info("title is '%s'", handle->title);
|
||||
log_info("internal name is '%s'", handle->intname);
|
||||
log_info("estrips count is %" PRIu8, hd.estrips_count);
|
||||
log_info("version is %.10s", hd.version);
|
||||
log_info("creation date is %.14s", hd.creation_date);
|
||||
|
||||
/* store data in the handle */
|
||||
addin_set_data(handle,
|
||||
(char*)hd.title, 8,
|
||||
(char*)hd.internal_name, 8,
|
||||
(char*)hd.version, (char*)hd.creation_date);
|
||||
|
||||
/* allocate space for icon */
|
||||
handle->width = G1A_ICON_WIDTH;
|
||||
handle->height = G1A_ICON_HEIGHT;
|
||||
handle->pixels = alloc_pixels(G1A_ICON_WIDTH, G1A_ICON_HEIGHT);
|
||||
if (!handle->pixels) return (g1m_error_alloc);
|
||||
prepare_pixels(handle->pixels, G1A_ICON_WIDTH, G1A_ICON_HEIGHT)
|
||||
log_info("version is %02u.%02u.%04u", handle->version.major,
|
||||
handle->version.minor, handle->version.revision);
|
||||
log_info("creation date is: %.24s", ctime(&handle->creation_date));
|
||||
|
||||
/* fill icon */
|
||||
g1m_decode_picture(handle->pixels, g1m_pictureformat_1bit_packed,
|
||||
hd.icon, G1A_ICON_WIDTH, G1A_ICON_HEIGHT);
|
||||
g1m_decode_picture(handle->icon_unsel, g1m_pictureformat_1bit_packed,
|
||||
hd.icon, handle->width, handle->height);
|
||||
g1m_decode_picture(handle->icon_sel, g1m_pictureformat_1bit_packed,
|
||||
hd.icon, handle->width, handle->height);
|
||||
|
||||
/* skip size */
|
||||
SKIP(hd.filesize - sizeof(struct standard_header)
|
||||
|
@ -126,98 +75,130 @@ int g1m_decode_std_addin(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
return (err);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Add-in for the fx-CP/Classpad (C1A) */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_decode_std_addin_cg:
|
||||
* Decode fx-CG add-in (after Standard Header).
|
||||
* g1m_decode_std_cp_addin:
|
||||
* Decode fx-CP add-in.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg h the handle to make.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg std the standard header.
|
||||
* @arg sub the standard subheader.
|
||||
* @arg cp the classpad-specific subheader.
|
||||
* @arg check the checksum to feed.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_addin_cg(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
int g1m_decode_std_cp_addin(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std, struct standard_subheader *sub,
|
||||
struct _classpad_subheader *cp, uint32_t *check)
|
||||
{
|
||||
int err = 0;
|
||||
/* get the subheader */
|
||||
DREAD(hd, addin_cp_subheader)
|
||||
|
||||
/* correct subheader endianness */
|
||||
hd.checksum = be32toh(hd.checksum);
|
||||
hd.control = be32toh(hd.control);
|
||||
hd.filesize = be32toh(hd.filesize);
|
||||
/* read the add-in subheader */
|
||||
DREAD(cphd, c1a_subheader)
|
||||
*check = g1m_checksum32(&cphd, sizeof(struct c1a_subheader), *check);
|
||||
|
||||
/* control byte */
|
||||
size_t content_size = hd.filesize - 4
|
||||
- hd.magic[1] ? 0x7000 : 0x1000;
|
||||
if (hd.control != content_size) {
|
||||
log_fatal("control value is incorrect!");
|
||||
log_fatal("calculated %" PRIuSIZE ", expected %" PRIu32,
|
||||
content_size, hd.control);
|
||||
return (g1m_error_magic);
|
||||
}
|
||||
/* make the handle */
|
||||
g1m_version_t version; g1m_decode_version((char*)sub->version, &version);
|
||||
time_t created; g1m_decode_date((char*)sub->timestamp, &created);
|
||||
err = g1m_make_addin(h, g1m_platform_cp, &version, &created);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* start making checksum */
|
||||
uint_fast32_t checksum =
|
||||
sizeof(struct standard_header) * 256
|
||||
- g1m_checksum32(std, sizeof(struct standard_header), 0)
|
||||
+ g1m_checksum32(&hd.magic, sizeof(struct addin_cp_subheader), 0);
|
||||
/* copy other basic information */
|
||||
strncpy(handle->intname, (char*)sub->internal_name, 8);
|
||||
handle->intname[9] = 0;
|
||||
strncpy(handle->title, (char*)sub->title, 16);
|
||||
handle->title[16] = 0;
|
||||
|
||||
/* read subheader */
|
||||
if (hd.magic[1]) { /* is Prizm */
|
||||
DREAD(shd, g3a_subheader)
|
||||
|
||||
checksum += g1m_checksum32(&shd, sizeof(struct g3a_subheader), 0);
|
||||
handle->pixels = alloc_pixels(G3A_ICON_WIDTH, G3A_ICON_HEIGHT);
|
||||
handle->width = G3A_ICON_WIDTH; handle->height = G3A_ICON_HEIGHT;
|
||||
if (!handle->pixels) return (g1m_error_alloc);
|
||||
prepare_pixels(handle->pixels, G3A_ICON_WIDTH, G3A_ICON_HEIGHT)
|
||||
|
||||
g1m_decode_picture(handle->pixels, g1m_pictureformat_16bit,
|
||||
shd.unselected_icon_image, G3A_ICON_WIDTH, G3A_ICON_HEIGHT);
|
||||
} else { /* is C1A */
|
||||
DREAD(shd, c1a_subheader)
|
||||
|
||||
checksum += g1m_checksum32(&shd, sizeof(struct c1a_subheader), 0);
|
||||
handle->pixels = alloc_pixels(C1A_ICON_WIDTH, C1A_ICON_HEIGHT);
|
||||
handle->width = C1A_ICON_WIDTH; handle->height = C1A_ICON_HEIGHT;
|
||||
if (!handle->pixels) return (g1m_error_alloc);
|
||||
prepare_pixels(handle->pixels, C1A_ICON_WIDTH, C1A_ICON_HEIGHT);
|
||||
|
||||
g1m_decode_picture(handle->pixels, g1m_pictureformat_1bit_packed,
|
||||
shd.icon, C1A_ICON_WIDTH, C1A_ICON_HEIGHT);
|
||||
}
|
||||
|
||||
/* skip content for now */
|
||||
if ((err = g1m_skip(buffer, content_size, &checksum)))
|
||||
goto fail;
|
||||
|
||||
/* check the sum (yo!) */
|
||||
err = g1m_error_magic;
|
||||
if (checksum != hd.checksum) {
|
||||
log_fatal("Invalid checksum!");
|
||||
log_fatal("Header checksum is %" PRIu32
|
||||
", calculated checksum is %" PRIuFAST32,
|
||||
hd.checksum, checksum);
|
||||
goto fail;
|
||||
}
|
||||
/* decode pictures */
|
||||
g1m_decode_picture(handle->icon_unsel, g1m_pictureformat_1bit_packed,
|
||||
cphd.icon, handle->width, handle->height);
|
||||
g1m_decode_picture(handle->icon_sel, g1m_pictureformat_1bit_packed,
|
||||
cphd.icon, handle->width, handle->height);
|
||||
|
||||
/* log */
|
||||
log_info("title is '%.16s'", hd.title);
|
||||
log_info("internal name is '%.11s'", hd.internal_name);
|
||||
log_info("version is '%.10s'", hd.version);
|
||||
log_info("timestamp is '%.14s'", hd.stamp);
|
||||
log_info("title is '%s'", handle->title);
|
||||
log_info("internal name is '%s'", handle->intname);
|
||||
log_info("version is %02u.%02u.%04u", handle->version.major,
|
||||
handle->version.minor, handle->version.revision);
|
||||
log_info("timestamp is %.24s", ctime(&handle->creation_date));
|
||||
|
||||
/* store basic data in the handle */
|
||||
addin_set_data(handle,
|
||||
(char*)hd.title, 16,
|
||||
(char*)hd.internal_name, 12,
|
||||
(char*)hd.version, (char*)hd.stamp);
|
||||
/* skip content for now */
|
||||
size_t content_size = be32toh(sub->filesize) - 0x1000;
|
||||
if ((err = g1m_skip(buffer, content_size, check)))
|
||||
goto fail;
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
fail:
|
||||
free(handle->pixels);
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Add-in for the fx-CG/Prizm (G3A) */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_decode_std_cg_addin:
|
||||
* Decode fx-CG add-in.
|
||||
*
|
||||
* @arg h the handle to make.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg std the standard header.
|
||||
* @arg sub the standard subheader.
|
||||
* @arg prizm the prizm-specific subheader.
|
||||
* @arg check the checksum to feed.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_cg_addin(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std, struct standard_subheader *sub,
|
||||
struct _prizm_subheader *prizm, uint32_t *check)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/* read the add-in subheader */
|
||||
DREAD(cghd, g3a_subheader)
|
||||
*check = g1m_checksum32(&cghd, sizeof(struct g3a_subheader), *check);
|
||||
|
||||
/* make the handle */
|
||||
g1m_version_t version; g1m_decode_version((char*)sub->version, &version);
|
||||
time_t created; g1m_decode_date((char*)sub->timestamp, &created);
|
||||
err = g1m_make_addin(h, g1m_platform_cg, &version, &created);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* copy other basic information */
|
||||
strncpy(handle->intname, (char*)sub->internal_name, 8);
|
||||
handle->intname[9] = 0;
|
||||
strncpy(handle->title, (char*)sub->title, 16);
|
||||
handle->title[16] = 0;
|
||||
|
||||
/* decode pictures */
|
||||
g1m_decode_picture(handle->icon_unsel, g1m_pictureformat_16bit,
|
||||
cghd.unselected_icon_image, handle->width, handle->height);
|
||||
g1m_decode_picture(handle->icon_sel, g1m_pictureformat_16bit,
|
||||
cghd.selected_icon_image, handle->width, handle->height);
|
||||
|
||||
/* log */
|
||||
log_info("title is '%s'", handle->title);
|
||||
log_info("internal name is '%s'", handle->intname);
|
||||
log_info("version is %02u.%02u.%04u", handle->version.major,
|
||||
handle->version.minor, handle->version.revision);
|
||||
log_info("timestamp is %.24s", ctime(&handle->creation_date));
|
||||
|
||||
/* skip content for now */
|
||||
size_t content_size = be32toh(sub->filesize) - 4 - 0x7000;
|
||||
if ((err = g1m_skip(buffer, content_size, check)))
|
||||
goto fail;
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
fail:
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
|
|
@ -427,19 +427,17 @@ static int eact_decode_line(g1m_line_t *handle, uint8_t *buf, size_t size,
|
|||
*
|
||||
* Thanks to Julese50 for his help on e-acts parsing.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg h the handle to create.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_eact(g1m_t * handle, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std_eact(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
{
|
||||
(void)std;
|
||||
(void)std; int err;
|
||||
/* decode the header */
|
||||
DREAD(hd, eact_header)
|
||||
|
||||
/* correct endianess */
|
||||
hd.filesize = be32toh(hd.filesize);
|
||||
hd.setup_area_size = be32toh(hd.setup_area_size);
|
||||
hd.eact_version = be32toh(hd.eact_version);
|
||||
|
@ -452,22 +450,31 @@ int g1m_decode_std_eact(g1m_t * handle, g1m_buffer_t *buffer,
|
|||
log_info("Setup area size is 0x%" PRIx32 " bytes long.",
|
||||
hd.setup_area_size);
|
||||
|
||||
/* check if is CG */
|
||||
if (hd.eact_version == EACT_G3E)
|
||||
handle->platform = g1m_platform_cg;
|
||||
/* allocate handle */
|
||||
*h = malloc(sizeof(g1m_t));
|
||||
if (!*h) return (g1m_error_alloc);
|
||||
g1m_t *handle = *h;
|
||||
memset(handle, 0, sizeof(g1m_t));
|
||||
|
||||
/* skip the setup area */
|
||||
SKIP(hd.setup_area_size)
|
||||
|
||||
/* prepare the handle */
|
||||
handle->type = g1m_type_eact;
|
||||
handle->platform = g1m_platform_fx;
|
||||
if (hd.eact_version == EACT_G3E) /* check if fx-CG */
|
||||
handle->platform = g1m_platform_cg;
|
||||
|
||||
/* get content buffer */
|
||||
size_t bufsize = hd.filesize - sizeof(struct standard_header)
|
||||
- sizeof(struct eact_header) - hd.setup_area_size;
|
||||
uint8_t buf[bufsize];
|
||||
READ(&buf, bufsize)
|
||||
|
||||
/* prepare handle */
|
||||
handle->line = &handle->_linedata;
|
||||
GREAD(&buf, bufsize)
|
||||
|
||||
/* decode content */
|
||||
handle->line = &handle->_linedata;
|
||||
return (eact_decode_line_content(handle->line, buf, bufsize));
|
||||
fail:
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
|
|
@ -60,25 +60,22 @@ static uint32_t **fkeydup3(uint8_t *fkey)
|
|||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* fx function keys file parsing utilities */
|
||||
/* Decoding fx function keys file (G1N) */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_decode_std_fkey:
|
||||
* Decode fx function keys files.
|
||||
*
|
||||
* @arg handle the libg1m handle.
|
||||
* @arg h the libg1m handle to create.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg std pointer to the standard header.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_fkey(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std_fkey(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
{
|
||||
(void)std;
|
||||
/* set handle type */
|
||||
handle->type = g1m_type_fkey;
|
||||
|
||||
int err; (void)std;
|
||||
/* read the subheader */
|
||||
DREAD(hd, g1n_subheader)
|
||||
uint_fast16_t num = be16toh(hd.fkey_count) + 1;
|
||||
|
@ -89,11 +86,10 @@ int g1m_decode_std_fkey(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
uint8_t data[data_size];
|
||||
READ(data, data_size)
|
||||
|
||||
/* allocate tab */
|
||||
handle->fkeys = malloc(sizeof(uint32_t**) * num);
|
||||
handle->count = 0;
|
||||
handle->_size = num;
|
||||
if (!handle->fkeys) return (g1m_error_alloc);
|
||||
/* prepare the handle */
|
||||
err = g1m_make_fkey(h, g1m_platform_fx, num);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* get the offset table */
|
||||
uint16_t *offsets = (uint16_t*)data;
|
||||
|
@ -104,20 +100,15 @@ int g1m_decode_std_fkey(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
strncpy(handle->title, (char*)fkeys, 16);
|
||||
|
||||
/* read all */
|
||||
for (uint_fast32_t i = 1; i < num; i++) {
|
||||
handle->fkeys[i] = NULL;
|
||||
if (offsets[i] == (uint16_t)-1) {
|
||||
handle->count++;
|
||||
for (handle->count = 0; handle->count < (int)num; handle->count++) {
|
||||
int i = handle->count;
|
||||
if (offsets[i] == (uint16_t)-1)
|
||||
continue ;
|
||||
}
|
||||
|
||||
/* correct offset */
|
||||
offsets[i] = be16toh(offsets[i]);
|
||||
|
||||
/* store */
|
||||
handle->fkeys[i] = fkeydup(&fkeys[i]);
|
||||
if (!handle->fkeys[i]) goto fail;
|
||||
handle->count++;
|
||||
}
|
||||
|
||||
/* no error */
|
||||
|
@ -125,35 +116,76 @@ int g1m_decode_std_fkey(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
|
||||
/* omg fail! */
|
||||
fail:
|
||||
for (int i = 0; i < handle->count; i++)
|
||||
free(handle->fkeys[i]);
|
||||
free(handle->messages);
|
||||
handle->messages = NULL;
|
||||
return (g1m_error_alloc);
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* cg function keys file parsing utilities */
|
||||
/* Decoding fx-CG/Prizm function keys file (G3N) */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_decode_fkey_cg_content:
|
||||
* g1m_decode_std_cg_fkey:
|
||||
* Decode fx-CG key files.
|
||||
*
|
||||
* In fact, the main parsing function is `g1m_decode_lang_cg` (they really
|
||||
* have the same subheader). TODO
|
||||
*
|
||||
* @arg handle the libg1m handle.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg std the standard header.
|
||||
* @arg sub the standard subheader.
|
||||
* @arg prizm the prizm-specific subheader.
|
||||
* @arg check the checksum to feed.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_fkey_cg_content(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
uint_fast32_t zonesize, uint32_t *pchecksum)
|
||||
int g1m_decode_std_cg_fkey(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std, struct standard_subheader *sub,
|
||||
struct _prizm_subheader *prizm, uint32_t *check)
|
||||
{
|
||||
handle->type = 0x00;
|
||||
//handle->type = g1m_type_fkey;
|
||||
(void)buffer;
|
||||
(void)zonesize;
|
||||
(void)pchecksum;
|
||||
return (g1m_error_magic);
|
||||
int err;
|
||||
|
||||
/* read the subheader */
|
||||
DREAD(lhd, g3l_lang_header)
|
||||
*check = g1m_checksum32(&lhd, sizeof(struct g3l_lang_header), *check);
|
||||
|
||||
/* read the data */
|
||||
size_t data_size = sub->filesize - sizeof(struct standard_header)
|
||||
- sizeof(struct standard_subheader) - sizeof(struct _prizm_subheader)
|
||||
- sizeof(struct g3l_lang_header) - 4;
|
||||
uint8_t data[data_size];
|
||||
READ(data, data_size)
|
||||
*check = g1m_checksum32(data, data_size, *check);
|
||||
|
||||
/* make the handle */
|
||||
int num = be32toh(lhd.num);
|
||||
err = g1m_make_fkey(h, g1m_platform_cg, num);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* setup the pointers */
|
||||
uint32_t *offsets = (void*)data;
|
||||
uint8_t *messages = (uint8_t*)&offsets[num + 1];
|
||||
|
||||
/* read messages */
|
||||
for (handle->count = 0; handle->count < (int)num; handle->count++) {
|
||||
int i = handle->count;
|
||||
if (offsets[i] == (uint32_t)-1) {
|
||||
log_info("[#%d] -", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* correct offset and log */
|
||||
offsets[i] = be32toh(offsets[i]);
|
||||
log_info("[#%d] '%s' (0x%" PRIu32 ")", i,
|
||||
&messages[offsets[i]], offsets[i]);
|
||||
|
||||
/* store */
|
||||
handle->fkeys[i] = fkeydup3((void*)&messages[offsets[i]]);
|
||||
if (!handle->fkeys[i]) goto fail;
|
||||
}
|
||||
|
||||
/* done */
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
|
|
@ -25,22 +25,18 @@
|
|||
* g1m_decode_std_lang:
|
||||
* Decode fx language files.
|
||||
*
|
||||
* @arg handle the libg1m handle.
|
||||
* @arg h the libg1m handle to create.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_lang(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std_lang(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
{
|
||||
(void)std;
|
||||
/* set handle type */
|
||||
handle->messages = NULL;
|
||||
(void)std; int err;
|
||||
|
||||
/* read the subheader */
|
||||
DREAD(hd, g1l_subheader)
|
||||
|
||||
/* correct the endianness */
|
||||
uint_fast16_t num = be16toh(hd.message_count) + 1;
|
||||
|
||||
/* log */
|
||||
|
@ -52,31 +48,26 @@ int g1m_decode_std_lang(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
uint8_t data[data_size];
|
||||
READ(data, data_size)
|
||||
|
||||
/* allocate tab */
|
||||
handle->messages = malloc(sizeof(char*) * num);
|
||||
handle->count = 0;
|
||||
handle->_size = num;
|
||||
if (!handle->messages)
|
||||
return (g1m_error_alloc);
|
||||
/* make the handle */
|
||||
err = g1m_make_lang(h, g1m_platform_fx, num);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* get the offset table */
|
||||
uint16_t *offsets = (uint16_t*)data;
|
||||
char *messages = (char*)(offsets + num);
|
||||
|
||||
/* read messages */
|
||||
for (uint_fast16_t i = 0; i < num; i++) {
|
||||
handle->messages[i] = NULL;
|
||||
for (handle->count = 0; handle->count < (int)num; handle->count++) {
|
||||
int i = handle->count;
|
||||
if (offsets[i] == (uint16_t)-1) {
|
||||
log_info("[#%" PRIuFAST16 "] -", i);
|
||||
handle->count++;
|
||||
continue ;
|
||||
log_info("[#%d] -", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* correct offset */
|
||||
/* correct offset and log */
|
||||
offsets[i] = be16toh(offsets[i]);
|
||||
|
||||
/* log */
|
||||
log_info("[#%" PRIuFAST16 "] '%s' (0x%" PRIu16 ")", i,
|
||||
log_info("[#%d] '%s' (0x%" PRIu16 ")", i,
|
||||
&messages[offsets[i]], offsets[i]);
|
||||
|
||||
/* store */
|
||||
|
@ -90,175 +81,76 @@ int g1m_decode_std_lang(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
|
||||
/* omg fail! */
|
||||
fail:
|
||||
for (int i = 0; i < handle->count; i++)
|
||||
free(handle->messages[i]);
|
||||
free(handle->messages);
|
||||
handle->messages = NULL;
|
||||
return (g1m_error_alloc);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* cg language files parsing */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_decode_lang_cg_content:
|
||||
* Decode the content of the message zone size for a G3L language file.
|
||||
*
|
||||
* @arg handle the libg1m handle.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg zonesize the message zone size.
|
||||
* @arg pchecksum pointer to the checksum to contribute to.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
static int g1m_decode_lang_cg_content(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
uint_fast32_t zonesize, uint32_t *pchecksum)
|
||||
{
|
||||
int err; uint32_t checksum = *pchecksum;
|
||||
/* correct the handle type */
|
||||
handle->type = g1m_type_lang;
|
||||
|
||||
/* read the subheader */
|
||||
DREAD(lhd, g3l_lang_header)
|
||||
checksum = g1m_checksum32(&lhd, sizeof(struct g3l_lang_header), checksum);
|
||||
|
||||
/* get the messages table */
|
||||
uint_fast32_t num = be32toh(lhd.num) + 1;
|
||||
uint32_t off[num + 1]; off[num] = zonesize;
|
||||
READ(off, num * sizeof(uint32_t))
|
||||
checksum = g1m_checksum32(off, num * sizeof(uint32_t), checksum);
|
||||
|
||||
/* prepare for next */
|
||||
uint32_t *offsets = &off[1]; num--;
|
||||
log_info("%" PRIuFAST32 " messages to read", num);
|
||||
|
||||
/* get index of first message */
|
||||
uint_fast32_t i;
|
||||
for (i = 0; i < num && offsets[i] == (uint32_t)-1; i++)
|
||||
handle->messages[i] = NULL;
|
||||
offsets[i] = be32toh(offsets[i]);
|
||||
|
||||
/* get and copy the language name */
|
||||
off[0] = be32toh(off[0]);
|
||||
if (off[0] == (uint32_t)-1) {
|
||||
log_fatal("First offset shouldn't be blank!");
|
||||
return (g1m_error_magic);
|
||||
}
|
||||
size_t langname_size = offsets[i] - off[0];
|
||||
uint8_t langname[langname_size];
|
||||
READ(langname, langname_size)
|
||||
handle->title[16] = 0;
|
||||
strncpy(handle->title, (char*)langname, 16);
|
||||
log_info("Language name is '%s'", handle->title);
|
||||
|
||||
/* prepare the handle messages table */
|
||||
handle->messages = malloc(sizeof(char*) * num);
|
||||
if (!handle->messages) return (g1m_error_alloc);
|
||||
handle->count = 0;
|
||||
handle->_size = num;
|
||||
|
||||
/* main loop */
|
||||
uint_fast32_t next;
|
||||
for (; i < num; i = next) {
|
||||
/* find and correct next offset */
|
||||
for (next = i + 1; offsets[next] == (uint32_t)-1; next++)
|
||||
handle->messages[next] = NULL;
|
||||
offsets[next] = be32toh(offsets[next]);
|
||||
|
||||
/* read the message */
|
||||
size_t msg_size = offsets[next] - offsets[i];
|
||||
uint8_t msg[msg_size];
|
||||
GREAD(msg, msg_size)
|
||||
checksum = g1m_checksum32(msg, msg_size, checksum);
|
||||
|
||||
/* copy it */
|
||||
handle->messages[i] = malloc(msg_size + 1);
|
||||
if (!handle->messages[i]) goto fail;
|
||||
handle->messages[i][msg_size] = 0;
|
||||
strncpy(handle->messages[i], (char*)msg, msg_size);
|
||||
handle->count += (next - i);
|
||||
|
||||
/* log it */
|
||||
log_info("[#%04" PRIuFAST32 "] '%s'", i, handle->messages[i]);
|
||||
}
|
||||
|
||||
/* done */
|
||||
*pchecksum = checksum;
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
g1m_free_content(handle);
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Decoding language files for fx-CG/Prizm (G3L) */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_decode_std_lang_cg:
|
||||
* Decode fx-CG language files.
|
||||
* g1m_decode_std_cg_lang:
|
||||
* Decode fx-CG language file.
|
||||
*
|
||||
* @arg handle the libg1m handle.
|
||||
* @arg h the handle to make.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg std the standard header.
|
||||
* @arg sub the standard subheader.
|
||||
* @arg prizm the prizm-specific subheader.
|
||||
* @arg check the checksum to feed.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_lang_cg(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
int g1m_decode_std_cg_lang(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std, struct standard_subheader *sub,
|
||||
struct _prizm_subheader *prizm, uint32_t *check)
|
||||
{
|
||||
/* set handle type */
|
||||
handle->messages = NULL;
|
||||
int err;
|
||||
|
||||
/* read the subheader */
|
||||
DREAD(hd, g3l_subheader)
|
||||
DREAD(lhd, g3l_lang_header)
|
||||
*check = g1m_checksum32(&lhd, sizeof(struct g3l_lang_header), *check);
|
||||
|
||||
/* correct the endianness */
|
||||
hd.checksum = be32toh(hd.checksum);
|
||||
hd.message_zone_size = be32toh(hd.message_zone_size);
|
||||
/* read the data */
|
||||
size_t data_size = sub->filesize - sizeof(struct standard_header)
|
||||
- sizeof(struct standard_subheader) - sizeof(struct _prizm_subheader)
|
||||
- sizeof(struct g3l_lang_header) - 4;
|
||||
uint8_t data[data_size];
|
||||
READ(data, data_size)
|
||||
*check = g1m_checksum32(data, data_size, *check);
|
||||
|
||||
/* log */
|
||||
log_info("internal name is '%.8s'", hd.internal_name);
|
||||
log_info("language name is '%.16s'", hd.language_name);
|
||||
log_info("language salutation is '%.16s'", hd.language_salutation);
|
||||
log_info("version is '%.10s'", hd.version);
|
||||
log_info("datetime is '%.14s'", hd.datetime);
|
||||
log_info("g3l filename is '%.16s'", hd.g3l_filename);
|
||||
/* make the handle */
|
||||
int num = be32toh(lhd.num);
|
||||
err = g1m_make_lang(h, g1m_platform_cg, num);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* precalculate the checksum beginning */
|
||||
uint32_t checksum =
|
||||
sizeof(struct standard_header) * 255
|
||||
- g1m_checksum32(std, sizeof(struct standard_header), 0) +
|
||||
g1m_checksum32(&hd.magic, sizeof(struct g3l_subheader) - 4, 0);
|
||||
/* setup the pointers */
|
||||
uint32_t *offsets = (void*)data;
|
||||
uint8_t *messages = (uint8_t*)&offsets[num + 1];
|
||||
|
||||
/* read and decode the message zone */
|
||||
int err = 0;
|
||||
size_t zonesize = hd.filesize - sizeof(struct standard_header)
|
||||
- sizeof(struct g3l_subheader) - sizeof(struct g3l_footer);
|
||||
if (hd.magic[0] == 0x04)
|
||||
err = g1m_decode_lang_cg_content(handle, buffer, zonesize, &checksum);
|
||||
else return (g1m_error_magic);
|
||||
if (err) return (g1m_error_magic);
|
||||
/* read messages */
|
||||
for (handle->count = 0; handle->count < (int)num; handle->count++) {
|
||||
int i = handle->count;
|
||||
if (offsets[i] == (uint32_t)-1) {
|
||||
log_info("[#%d] -", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check the checksum */
|
||||
if (hd.checksum && hd.checksum != checksum) {
|
||||
log_fatal("header checksum was invalid");
|
||||
goto fail;
|
||||
/* correct offset and log */
|
||||
offsets[i] = be32toh(offsets[i]);
|
||||
log_info("[#%d] '%s' (0x%" PRIu32 ")", i,
|
||||
&messages[offsets[i]], offsets[i]);
|
||||
|
||||
/* store */
|
||||
handle->messages[i] = strdup((char*)&messages[offsets[i]]);
|
||||
if (!handle->messages[i]) goto fail;
|
||||
}
|
||||
|
||||
/* read the footer */
|
||||
GDREAD(footer, g3l_footer)
|
||||
footer.checksum = be32toh(footer.checksum);
|
||||
if (footer.checksum != hd.checksum) {
|
||||
log_fatal("footer checksum was invalid!");
|
||||
log_info("header checksum is %" PRIu32 ","
|
||||
" calculated checksum is %" PRIu32,
|
||||
hd.checksum, checksum);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* no error */
|
||||
/* done */
|
||||
return (0);
|
||||
|
||||
/* omg fail! */
|
||||
fail:
|
||||
g1m_free_content(handle);
|
||||
return (g1m_error_alloc);
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
|
|
@ -201,30 +201,27 @@ int g1m_decode_mcsfile_data(g1m_mcsfile_t **handle,
|
|||
* g1m_decode_std_mcs:
|
||||
* Decode an MCS file, after the Standard Header.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg h the handle to make.
|
||||
* @arg buffer the buffer to read from.
|
||||
* @arg num number of sizes.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_mcs(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std_mcs(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
{
|
||||
int err = g1m_error_alloc;
|
||||
/* get number of subparts from the standard header */
|
||||
uint_fast16_t num = std->number;
|
||||
|
||||
/* allocate memory for the files index */
|
||||
handle->count = 0;
|
||||
handle->_size = num;
|
||||
if (num) {
|
||||
handle->files = malloc(sizeof(g1m_mcsfile_t*) * num);
|
||||
if (!handle->files) return (g1m_error_alloc);
|
||||
}
|
||||
/* make the handle */
|
||||
err = g1m_make_mcs(h, num);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* read all of the parts */
|
||||
log_info("%" PRIuFAST16 " total mcs files to browse", num);
|
||||
while (handle->count < (int)num) {
|
||||
for (handle->count = 0; handle->count < (int)num;) {
|
||||
/* get the subheader */
|
||||
GDREAD(hd, mcs_subheader)
|
||||
|
||||
|
@ -267,6 +264,6 @@ int g1m_decode_std_mcs(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
|
||||
/* was error! */
|
||||
fail:
|
||||
g1m_free_mcs(handle);
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (err);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ static void g3p_deobfuscate(uint8_t *buf, size_t n)
|
|||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_g3p(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std_g3p(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
{
|
||||
/* get the G3P global header */
|
||||
|
@ -60,8 +60,6 @@ int g1m_decode_std_g3p(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
|
||||
/* read the image header */
|
||||
DREAD(ihd, g3p_imageheader)
|
||||
|
||||
/* correct endianness */
|
||||
ihd.df_size = be32toh(ihd.df_size);
|
||||
ihd.width = be16toh(ihd.width);
|
||||
ihd.height = be16toh(ihd.height);
|
||||
|
@ -122,17 +120,14 @@ int g1m_decode_std_g3p(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
}
|
||||
|
||||
/* allocate picture in handle */
|
||||
unsigned int w = ihd.width, h = ihd.height;
|
||||
handle->width = w;
|
||||
handle->height = h;
|
||||
handle->pixels = alloc_pixels(w, h);
|
||||
if (!handle->pixels) return (g1m_error_alloc);
|
||||
prepare_pixels(handle->pixels, w, h)
|
||||
int err = g1m_make_picture(h, ihd.width, ihd.height);
|
||||
if (err) return (err);
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* then store it */
|
||||
g1m_decode_picture(handle->pixels, ihd.color_depth == g3p_color_4bit
|
||||
? g1m_pictureformat_4bit_code : g1m_pictureformat_16bit,
|
||||
inflated_image, w, h);
|
||||
inflated_image, handle->width, handle->height);
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
|
@ -147,16 +142,16 @@ int g1m_decode_std_g3p(g1m_t *handle, g1m_buffer_t *buffer,
|
|||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_std_c2p(g1m_t *handle, g1m_buffer_t *buffer,
|
||||
int g1m_decode_std_c2p(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
{
|
||||
(void)std;
|
||||
(void)handle;
|
||||
(void)h;
|
||||
(void)buffer;
|
||||
/* TODO */
|
||||
log_info("C2P files are not managed yet.");
|
||||
log_info("Size is %" PRIuSIZE "B", sizeof(struct c2p_subheader));
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
return (g1m_error_magic);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ int g1m_make_picture(g1m_t **h, unsigned int width, unsigned int height)
|
|||
*h = malloc(sizeof(g1m_t));
|
||||
if (!*h) return (g1m_error_alloc);
|
||||
g1m_t *handle = *h;
|
||||
memset(handle, 0, sizeof(g1m_t));
|
||||
|
||||
/* allocate the pixels */
|
||||
handle->width = width;
|
||||
|
@ -63,67 +64,209 @@ int g1m_make_mcs(g1m_t **h, int count)
|
|||
/* allocate the handle */
|
||||
*h = malloc(sizeof(g1m_t));
|
||||
if (!*h) return (g1m_error_alloc);
|
||||
g1m_t *handle = *h;
|
||||
memset(handle, 0, sizeof(g1m_t));
|
||||
|
||||
/* initialize it */
|
||||
g1m_t *handle = *h;
|
||||
handle->type = g1m_type_mcs;
|
||||
handle->platform = g1m_platform_fx;
|
||||
handle->count = 0; handle->_size = 0;
|
||||
handle->files = NULL;
|
||||
|
||||
/* allocate space */
|
||||
handle->count = count; handle->_size = count;
|
||||
handle->files = NULL;
|
||||
if (count) {
|
||||
handle->files = malloc(sizeof(g1m_mcsfile_t*) * count);
|
||||
if (!handle->files) { free(*h); *h = NULL; return (g1m_error_alloc); }
|
||||
if (!handle->files) goto fail;
|
||||
memset(handle->files, 0, sizeof(g1m_mcsfile_t*) * count);
|
||||
handle->_size = count;
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
fail:
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (g1m_error_alloc);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_make_fkey:
|
||||
* Make a Function Keys handle.
|
||||
*
|
||||
* @arg h pointer to the handle to create.
|
||||
* @arg pf the platform.
|
||||
* @arg count the number of slots in the index.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_make_fkey(g1m_t **h, g1m_platform_t pf, int count)
|
||||
{
|
||||
/* allocate the handle */
|
||||
*h = malloc(sizeof(g1m_t));
|
||||
if (!*h) return (g1m_error_alloc);
|
||||
g1m_t *handle = *h;
|
||||
memset(handle, 0, sizeof(g1m_t));
|
||||
|
||||
/* initialize it */
|
||||
handle->type = g1m_type_fkey;
|
||||
handle->platform = pf;
|
||||
handle->count = 0; handle->_size = 0;
|
||||
handle->fkeys = NULL;
|
||||
|
||||
/* allocate index */
|
||||
if (count) {
|
||||
handle->fkeys = malloc(sizeof(uint32_t**) * count);
|
||||
if (!handle->fkeys) goto fail;
|
||||
memset(handle->fkeys, 0, sizeof(uint32_t**) * count);
|
||||
handle->_size = count;
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
fail:
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (g1m_error_alloc);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_make_lang:
|
||||
* Make a language handle.
|
||||
*
|
||||
* @arg h pointer to the handle to create.
|
||||
* @arg platform the platform.
|
||||
* @arg count the number of slots in the index.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_make_lang(g1m_t **h, g1m_platform_t platform, int count)
|
||||
{
|
||||
/* allocate the handle */
|
||||
*h = malloc(sizeof(g1m_t));
|
||||
if (!*h) return (g1m_error_alloc);
|
||||
g1m_t *handle = *h;
|
||||
memset(handle, 0, sizeof(g1m_t));
|
||||
|
||||
/* initialize it */
|
||||
handle->type = g1m_type_lang;
|
||||
handle->platform = platform;
|
||||
handle->count = 0; handle->_size = 0;
|
||||
handle->messages = NULL;
|
||||
|
||||
/* allocate index */
|
||||
if (count) {
|
||||
handle->messages = malloc(sizeof(char*) * count);
|
||||
if (!handle->messages) goto fail;
|
||||
memset(handle->messages, 0, sizeof(char*) * count);
|
||||
handle->_size = count;
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
fail:
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (g1m_error_alloc);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_make_addin:
|
||||
* Make an add-in handle.
|
||||
*
|
||||
* @arg h pointer to the handle to create.
|
||||
* @arg platform the platform for which to make the add-in.
|
||||
* @arg version the version of the add-in.
|
||||
* @arg created the creation date of the add-in.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_make_addin(g1m_t **h, g1m_platform_t platform,
|
||||
const g1m_version_t *version, const time_t *created)
|
||||
{
|
||||
*h = NULL;
|
||||
|
||||
/* check the platform */
|
||||
if (platform != g1m_platform_fx && platform != g1m_platform_cg
|
||||
&& platform != g1m_platform_cp)
|
||||
return (g1m_error_op);
|
||||
|
||||
/* allocate the handle */
|
||||
*h = malloc(sizeof(g1m_t));
|
||||
if (!*h) return (g1m_error_alloc);
|
||||
g1m_t *handle = *h;
|
||||
memset(handle, 0, sizeof(g1m_t));
|
||||
|
||||
/* set basic options */
|
||||
handle->platform = platform;
|
||||
handle->version = *version;
|
||||
handle->creation_date = *created;
|
||||
|
||||
/* check the platform */
|
||||
unsigned int width, height;
|
||||
switch (platform) {
|
||||
case g1m_platform_fx:
|
||||
width = G1A_ICON_WIDTH;
|
||||
height = G1A_ICON_HEIGHT;
|
||||
break;
|
||||
case g1m_platform_cp:
|
||||
width = C1A_ICON_WIDTH;
|
||||
height = C1A_ICON_HEIGHT;
|
||||
break;
|
||||
default: /* case g1m_platform_cg: */
|
||||
width = G3A_ICON_WIDTH;
|
||||
height = G3A_ICON_HEIGHT;
|
||||
}
|
||||
|
||||
/* allocate pictures */
|
||||
handle->icon_unsel = alloc_pixels(width, height);
|
||||
if (!handle->icon_unsel) goto fail;
|
||||
handle->icon_sel = alloc_pixels(width, height);
|
||||
if (!handle->icon_sel) goto fail;
|
||||
|
||||
/* prepare pictures */
|
||||
prepare_pixels(handle->icon_unsel, width, height)
|
||||
prepare_pixels(handle->icon_sel, width, height)
|
||||
|
||||
/* end my suffering */
|
||||
return (0);
|
||||
fail:
|
||||
g1m_free(*h); *h = NULL;
|
||||
return (g1m_error_alloc);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Free a handle */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_free_mcs:
|
||||
* Free all of the MCS.
|
||||
* g1m_free:
|
||||
* Free a handle and its data.
|
||||
*
|
||||
* @arg handle the handle to close.
|
||||
* @arg handle the handle.
|
||||
*/
|
||||
|
||||
void g1m_free_mcs(g1m_t *handle)
|
||||
void g1m_free(g1m_t *handle)
|
||||
{
|
||||
/* check if mcs */
|
||||
if (!handle->files)
|
||||
return ;
|
||||
/* check if there is something to free */
|
||||
if (!handle) return ;
|
||||
|
||||
/* foreach file in mcs */
|
||||
g1m_mcsfile_t **files = handle->files;
|
||||
int file_count = handle->count;
|
||||
for (int i = 0; i < file_count; i++) {
|
||||
/* free the file if exists */
|
||||
if (files[i]) g1m_free_mcsfile(files[i]);
|
||||
}
|
||||
free(handle->files); handle->files = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_free_content:
|
||||
* Free handle data.
|
||||
*
|
||||
* @arg handle the handle to close.
|
||||
*/
|
||||
|
||||
void g1m_free_content(g1m_t *handle)
|
||||
{
|
||||
/* addin time! */
|
||||
if (handle->type & g1m_type_addin)
|
||||
free(handle->pixels);
|
||||
if (handle->type & g1m_type_addin) {
|
||||
free(handle->icon_unsel);
|
||||
free(handle->icon_sel);
|
||||
}
|
||||
|
||||
/* mcs time! */
|
||||
if (handle->type & g1m_type_mcs)
|
||||
g1m_free_mcs(handle);
|
||||
if (handle->type & g1m_type_mcs) {
|
||||
/* check if mcs */
|
||||
if (!handle->files)
|
||||
return ;
|
||||
|
||||
/* foreach file in mcs */
|
||||
g1m_mcsfile_t **files = handle->files;
|
||||
int file_count = handle->count;
|
||||
for (int i = 0; i < file_count; i++) {
|
||||
/* free the file if exists */
|
||||
if (files[i]) g1m_free_mcsfile(files[i]);
|
||||
}
|
||||
free(handle->files); handle->files = NULL;
|
||||
}
|
||||
|
||||
/* messages time! */
|
||||
if (handle->type & g1m_type_lang
|
||||
|
@ -148,18 +291,7 @@ void g1m_free_content(g1m_t *handle)
|
|||
/* e-activities time! */
|
||||
if (handle->type & g1m_type_eact)
|
||||
g1m_free_line_content(handle->line);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_free:
|
||||
* Free a handle and its data.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
*/
|
||||
|
||||
void g1m_free(g1m_t *handle)
|
||||
{
|
||||
if (!handle) return ;
|
||||
g1m_free_content(handle);
|
||||
/* free the handle itself! */
|
||||
free(handle);
|
||||
}
|
||||
|
|
|
@ -18,14 +18,13 @@
|
|||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#include <ctype.h>
|
||||
#define f_c1 g1m_stdflag_check1
|
||||
#define f_c2 g1m_stdflag_check2
|
||||
#define f_sub g1m_stdflag_sub
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Local types */
|
||||
/* ************************************************************************** */
|
||||
/* Flags */
|
||||
#define nochk_controlone 0x01
|
||||
#define nochk_controltwo 0x02
|
||||
|
||||
/* Subtype correspondance type */
|
||||
struct type_info {
|
||||
/* identification */
|
||||
|
@ -65,29 +64,29 @@ static struct main_info types[] = {
|
|||
/* USBPower (the most common one) */
|
||||
{"USBPower", (struct type_info[]){
|
||||
/* add-ins */
|
||||
{"\xf3" magic_common, "add-in", 0,
|
||||
{"\xf3" magic_common, "add-in", f_c1 | f_c2,
|
||||
g1m_platform_fx, g1m_type_addin},
|
||||
{"\x2c" cp_magic, "fx-CG add-in", 0,
|
||||
{"\x2c" cp_magic, "fx-CG add-in", f_c1 | f_c2 | f_sub,
|
||||
g1m_platform_cg, g1m_type_addin},
|
||||
|
||||
/* MCS */
|
||||
{"\x62" magic_common, "mcs (g2r)", 0,
|
||||
{"\x62" magic_common, "mcs (g2r)", f_c1 | f_c2,
|
||||
g1m_platform_fx, g1m_type_mcs}, /* TODO: add flag? */
|
||||
{"\x31" magic_common, "mcs", 0,
|
||||
{"\x31" magic_common, "mcs", f_c1 | f_c2,
|
||||
g1m_platform_fx, g1m_type_mcs},
|
||||
{"\x75" magic_common, "mcs (fx-CG)", 0,
|
||||
{"\x75" magic_common, "mcs (fx-CG)", f_c1 | f_c2,
|
||||
g1m_platform_cg, g1m_type_mcs},
|
||||
|
||||
/* Language */
|
||||
{"\x12" magic_common, "fx language file", 0,
|
||||
{"\x12" magic_common, "fx language file", f_c1 | f_c2,
|
||||
g1m_platform_fx, g1m_type_lang},
|
||||
|
||||
/* E-Activities */
|
||||
{"\x49" magic_common, "e-activity (document)", 0,
|
||||
{"\x49" magic_common, "e-activity (document)", f_c1 | f_c2,
|
||||
g1m_platform_fx, g1m_type_eact},
|
||||
|
||||
/* Pictures */
|
||||
{"\x7d" magic_common, "fx-CG picture", 0,
|
||||
{"\x7d" magic_common, "fx-CG picture", f_c1 | f_c2,
|
||||
g1m_platform_cg, g1m_type_pict},
|
||||
|
||||
TTERM
|
||||
|
@ -95,7 +94,7 @@ static struct main_info types[] = {
|
|||
|
||||
/* Ly755 (Classpad-specific) */
|
||||
{"Ly755 ", (struct type_info[]){
|
||||
{"\x2c" cp_magic, "fx-CG language file", 0,
|
||||
{"\x2c" cp_magic, "fx-CG language file", f_c1 | f_c2 | f_sub,
|
||||
g1m_platform_cg, g1m_type_lang},
|
||||
|
||||
TTERM
|
||||
|
@ -103,7 +102,7 @@ static struct main_info types[] = {
|
|||
|
||||
/* CASIO (only used for c2p...?) */
|
||||
{"CASIO\0\0\0", (struct type_info[]){
|
||||
{"c2p\0\0\0", "Classpad picture", nochk_controlone | nochk_controltwo,
|
||||
{"c2p\0\0\0", "Classpad picture", 0,
|
||||
g1m_platform_cp, g1m_type_pict},
|
||||
|
||||
TTERM
|
||||
|
@ -125,20 +124,21 @@ struct ext_corresp {
|
|||
const char *info;
|
||||
unsigned int platform;
|
||||
unsigned int libtype;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* Extension correspondances */
|
||||
static struct ext_corresp ext_types[] = {
|
||||
/* fx types with non-checked header */
|
||||
{"g1l", "fx language file", g1m_platform_fx, g1m_type_lang},
|
||||
{"g1n", "fx fkeys file", g1m_platform_fx, g1m_type_fkey},
|
||||
{"g1l", "fx language file", g1m_platform_fx, g1m_type_lang, 0},
|
||||
{"g1n", "fx fkeys file", g1m_platform_fx, g1m_type_fkey, 0},
|
||||
|
||||
/* cg types with non-checked header */
|
||||
{"g3l", "fx-CG language file", g1m_platform_cg, g1m_type_lang},
|
||||
{"g3n", "fx-CG fkeys file", g1m_platform_cg, g1m_type_fkey},
|
||||
{"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},
|
||||
|
||||
/* sentinel */
|
||||
{NULL, NULL, 0, 0}
|
||||
{NULL, NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
@ -161,7 +161,7 @@ static struct ext_corresp ext_types[] = {
|
|||
|
||||
int g1m_maketype_std(const char *path,
|
||||
unsigned char *main_id, unsigned char *subtype,
|
||||
const char **info, int *check_one, int *check_two,
|
||||
const char **info, unsigned int *flags,
|
||||
unsigned int *platform, g1m_type_t *type)
|
||||
{
|
||||
/* look if blank */
|
||||
|
@ -185,8 +185,7 @@ int g1m_maketype_std(const char *path,
|
|||
if (info) *info = e->info;
|
||||
if (platform) *platform = e->platform;
|
||||
if (type) *type = e->libtype;
|
||||
if (check_one) *check_one = 0;
|
||||
if (check_two) *check_two = 0;
|
||||
if (flags) *flags = e->flags;
|
||||
} else {
|
||||
/* look for main_id */
|
||||
struct main_info *mt = types - 1;
|
||||
|
@ -217,8 +216,7 @@ int g1m_maketype_std(const char *path,
|
|||
if (info) *info = sub->info;
|
||||
if (platform) *platform = sub->platform;
|
||||
if (type) *type = sub->libtype;
|
||||
if (check_one) *check_one = ~sub->flags & nochk_controlone;
|
||||
if (check_two) *check_two = ~sub->flags & nochk_controltwo;
|
||||
if (flags) *flags = sub->flags;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/* *****************************************************************************
|
||||
* type/sub.c -- extract the file type out of raw substd identification data.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* This file is part of libg1m.
|
||||
* libg1m is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3.0 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* libg1m is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Local types */
|
||||
/* ************************************************************************** */
|
||||
/* Type correspondance type */
|
||||
struct type_info {
|
||||
/* identification */
|
||||
int raw_platform;
|
||||
int raw_type;
|
||||
|
||||
/* types */
|
||||
g1m_platform_t platform;
|
||||
g1m_type_t type;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Correspondances */
|
||||
/* ************************************************************************** */
|
||||
/* Terminate type list */
|
||||
#define TTERM {0, 0, 0, 0}
|
||||
|
||||
/* Platforms and types */
|
||||
#define p_cp 0x00
|
||||
#define p_cg 0x01
|
||||
#define t_addin 0x01
|
||||
#define t_fkey 0x02
|
||||
#define t_lang 0x04
|
||||
|
||||
/* Main types */
|
||||
static struct type_info types[] = {
|
||||
/* fx-CP types */
|
||||
{p_cp, t_addin, g1m_platform_cp, g1m_type_addin},
|
||||
|
||||
/* fx-CG types */
|
||||
{p_cg, t_addin, g1m_platform_cg, g1m_type_addin},
|
||||
{p_cg, t_fkey, g1m_platform_cg, g1m_type_fkey},
|
||||
{p_cg, t_lang, g1m_platform_cg, g1m_type_lang},
|
||||
|
||||
/* sentinel */
|
||||
TTERM
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Main functions */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_maketype_sub:
|
||||
* Get type info from Standard Subheader.
|
||||
*
|
||||
* @arg raw_type The raw type.
|
||||
* @arg raw_pf The raw platform.
|
||||
* @arg flags The flags to set.
|
||||
* @arg type The type to get.
|
||||
* @arg platform The platform to get.
|
||||
* @return If there was an error.
|
||||
*/
|
||||
|
||||
int g1m_maketype_sub(int raw_type, int raw_pf, unsigned int *flags,
|
||||
g1m_type_t *type, g1m_platform_t *platform)
|
||||
{
|
||||
/* look for the correspondance */
|
||||
struct type_info *c = types - 1;
|
||||
while ((++c)->platform) {
|
||||
if (c->raw_type == raw_type && c->raw_platform == raw_pf)
|
||||
break;
|
||||
}
|
||||
if (!c->platform) return (g1m_error_unknown);
|
||||
|
||||
/* fill things */
|
||||
if (flags) *flags = 0;
|
||||
if (platform) *platform = c->platform;
|
||||
if (type) *type = c->type;
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/* *****************************************************************************
|
||||
* utils/date.c -- decode and encode a date.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* This file is part of libg1m.
|
||||
* libg1m is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3.0 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* libg1m is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/**
|
||||
* g1m_decode_date:
|
||||
* Decode a date from a string.
|
||||
*
|
||||
* @arg c the raw string.
|
||||
* @arg t the destination timestamp.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_decode_date(const char *c, time_t *t)
|
||||
{
|
||||
/* TODO: make checks on structure */
|
||||
|
||||
/* helper values */
|
||||
const int two = '0' + '0' * 10;
|
||||
const int four = two + '0' * 100 + '0' * 1000;
|
||||
|
||||
/* get the tm structure */
|
||||
struct tm date = {
|
||||
.tm_year = c[0] * 1000 + c[1] * 100 + c[2] * 10 + c[3] - four - 1900,
|
||||
.tm_mon = c[5] * 10 + c[6] - two - 1,
|
||||
.tm_mday = c[7] * 10 + c[8] - two,
|
||||
.tm_hour = c[10] * 10 + c[11] - two,
|
||||
.tm_min = c[12] * 10 + c[13] - two
|
||||
};
|
||||
|
||||
/* set the timestamp, return */
|
||||
*t = mktime(&date);
|
||||
return (0);
|
||||
}
|
|
@ -27,10 +27,10 @@
|
|||
* @arg checksum pointer to the checksum variable if there is one.
|
||||
*/
|
||||
|
||||
int g1m_skip(g1m_buffer_t *buffer, size_t size, uint_fast32_t *checksum)
|
||||
int g1m_skip(g1m_buffer_t *buffer, size_t size, uint32_t *checksum)
|
||||
{
|
||||
uint8_t buf[1024]; int err;
|
||||
uint_fast32_t add = 0;
|
||||
uint32_t add = 0;
|
||||
size_t orig = size;
|
||||
|
||||
while (size) {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* *****************************************************************************
|
||||
* utils/version.c -- decode and encode a version.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* This file is part of libg1m.
|
||||
* libg1m is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3.0 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* libg1m is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/**
|
||||
* g1m_decode_version:
|
||||
* Decode a version from a 'MM.mm.ffff' formatted version string.
|
||||
*
|
||||
* @arg raw the string to decode from.
|
||||
* @arg version the structure where to store the information.
|
||||
* @return the error code (if any).
|
||||
*/
|
||||
|
||||
int g1m_decode_version(const char *raw, g1m_version_t *version)
|
||||
{
|
||||
/* TODO: make checks on format */
|
||||
|
||||
/* helper values */
|
||||
const int two = '0' + '0' * 10;
|
||||
const int four = two + '0' * 100 + '0' * 1000;
|
||||
|
||||
/* get the version data */
|
||||
*version = (g1m_version_t){
|
||||
.major = raw[0] * 10 + raw[1] - two,
|
||||
.minor = raw[3] * 10 + raw[4] - two,
|
||||
.revision = raw[6] * 1000 + raw[7] * 100 + raw[8] * 10 + raw[9] - four
|
||||
};
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
}
|
|
@ -17,15 +17,15 @@ esac; done
|
|||
|
||||
# Make version as numbers
|
||||
vnum=$(echo ${version} | cut -d- -f1)
|
||||
version_major=$(( $(echo ${vnum} | cut -d. -f1) ))
|
||||
version_minor=$(( $(echo ${vnum} | cut -s -d. -f2) ))
|
||||
version_rev=$(( $(echo ${vnum} | cut -s -d. -f3) ))
|
||||
version_indev=$(echo ${version} | cut -s -d- -f2)
|
||||
version_indev=$([ ${version_indev} ] && echo 1 || echo 0)
|
||||
version_major=$(printf "%d" "$(echo ${vnum} | cut -d. -f1)")
|
||||
version_minor=$(printf "%d" "$(echo ${vnum} | cut -s -d. -f2)")
|
||||
version_rev=$(printf "%d" "$(echo ${vnum} | cut -s -d. -f3)")
|
||||
version_indev="$(echo ${version} | cut -s -d- -f2)"
|
||||
version_indev="$([ "${version_indev}" ] && echo 1 || echo 0)"
|
||||
|
||||
# Constitute version thingies
|
||||
version_num=$(printf "0x%02X%02X%04X" \
|
||||
${version_major} ${version_minor} ${version_rev})
|
||||
"${version_major}" "${version_minor}" "${version_rev}")
|
||||
|
||||
#******************************************************************************#
|
||||
# Write the file #
|
||||
|
@ -58,11 +58,11 @@ cat <<_EOF
|
|||
#ifndef LIBG1M_CONFIG_H
|
||||
# define LIBG1M_CONFIG_H
|
||||
# define LIBG1M_VERSION "${version}"
|
||||
# define LIBG1M_VERNUM ${version_num}
|
||||
# define LIBG1M_MAJOR ${version_major}
|
||||
# define LIBG1M_MINOR ${version_minor}
|
||||
# define LIBG1M_REV ${version_rev}
|
||||
# define LIBG1M_INDEV ${version_indev}
|
||||
# define LIBG1M_VERNUM ${version_num}
|
||||
# define LIBG1M_MAJOR ${version_major}
|
||||
# define LIBG1M_MINOR ${version_minor}
|
||||
# define LIBG1M_REV ${version_rev}
|
||||
# define LIBG1M_INDEV ${version_indev}
|
||||
# define LIBG1M_MAINTAINER \\
|
||||
"${maintainer}"
|
||||
|
||||
|
|
Reference in New Issue