cake
/
libg1m
Archived
1
0
Fork 0

Finished rewriting of most things, corrected Prizm/CP headers support, still a weird bug to solve

This commit is contained in:
Thomas Touhey 2017-03-17 22:23:55 +01:00
parent ad3fb2fe3e
commit 43c58008fa
27 changed files with 1018 additions and 775 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

94
src/type/sub.c Normal file
View File

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

50
src/utils/date.c Normal file
View File

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

View File

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

47
src/utils/version.c Normal file
View File

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

View File

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