cake
/
libg1m
Archived
1
0
Fork 0

printf for inttypes.h types, blank types, raw mcs management began

This commit is contained in:
Thomas Touhey 2016-12-25 14:14:21 +01:00
parent 3653adecc6
commit a19e6ae3eb
21 changed files with 560 additions and 257 deletions

View File

@ -5,4 +5,5 @@ The documentation comes from a lot of places in the CASIO community, but mainly
from **Casiopeia** (mainly with Simon Lothar's documentation) and **Cemetech**
(Prizm-related formats).
Thanks to the people on **Planète Casio** for their support.
Thanks to Simon Lothar, Teamfx and KermMartian for their help!
Thanks to the people on **Planète Casio** for their support!

View File

@ -169,12 +169,22 @@ typedef enum {
g1m_type_fkey = 0x20
} g1m_type_t;
/* platform */
typedef enum {
g1m_platform_none = 0x00,
g1m_platform_fx = 0x01,
g1m_platform_cp = 0x02,
g1m_platform_cg = 0x04,
g1m_platform_fx_raw = 0x08
} g1m_platform_t;
/* handle */
typedef struct {
/* g1m type */
g1m_type_t type;
/* is it a format adapted for fx-CG? */
int is_cg;
/* for what platform is this type made for? */
g1m_platform_t platform;
/* Add-in related data */
char title[17];
@ -209,7 +219,7 @@ typedef struct {
/* ************************************************************************** */
/* open handles */
int g1m_open(g1m_t **handle, const char *path);
int g1m_fopen(g1m_t **handle, FILE *stream);
int g1m_fopen(g1m_t **handle, const char *path, FILE *stream);
/* open MCS handle (this one is mainly for `libp7`) */
int g1m_parse_mcsfile_content(g1m_mcsfile_t **handle, FILE *stream,

View File

@ -82,6 +82,7 @@ struct standard_header {
# include <libg1m/format/addin.h>
# include <libg1m/format/eact.h>
# include <libg1m/format/mcs.h>
# include <libg1m/format/mcsraw.h>
# include <libg1m/format/picture.h>
# include <libg1m/format/lang.h>
# include <libg1m/format/fkey.h>

View File

@ -12,15 +12,16 @@
# include <libg1m.h>
# pragma pack(1)
/* TODO: it is unknown yet how to identify G1N files, as no non-community-made
* was found and the calculator software just skips the StandardHeader.
* It has to be found for a correct integration in libg1m! */
/* Function keys are the little boxes at the bottom with text in it, to tell
* you what you're going to access if you press F1-F6. */
/* ************************************************************************** */
/* G1N - Function-keys files for fx calculators */
/* ************************************************************************** */
/* Function-keys are the little black boxes with text in it, to tell you what
* you're going to access if you press F1-F6. It's in fact encoded as
* 24x8 packed 1-bit images.
/* In G1Ns, function keys are 19x8 1-bit with fill bits images.
*
* TODO: it is unknown yet how to identify G1N files, 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!
*
* The format looks a lot like G1L files. The header is the following: */
@ -38,9 +39,21 @@ struct g1n_subheader {
};
/* Then there is a table of 16-bits offsets (iconXXX - icon0), then the icons.
* The first "icon" is in fact the name of the language.
* The first "icon" is in fact the name of the language. */
/* ************************************************************************** */
/* 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.
*
* There is no equivalent of this for the Prizm. */
* 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. */
# define FKEY3_WIDTH 64
# define FKEY3_HEIGHT 24
# pragma pack()
#endif /* LIBG1M_FORMAT_FKEY_H */

View File

@ -50,13 +50,15 @@ struct g3l_subheader {
/* a checksum */
uint32_t checksum;
/* magic: always "0401" */
/* 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 */
/* size of the message zone size - unreliable (valid could have zero) */
uint32_t message_zone_size;
/* undocumented, again */

View File

@ -0,0 +1,23 @@
/* ************************************************************************** */
/* _____ _ */
/* libg1m/format/mcsraw.h |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/12/25 13:39:13 |___/ */
/* */
/* ************************************************************************** */
#ifndef LIBG1M_FORMAT_MCSRAW_H
# define LIBG1M_FORMAT_MCSRAW_H
/* Raw MCS files (G1S) contain backups of the raw MCS.
*
* According to Simon Lothar, the files contain zeroes up to 0x00270000
* (the location of the MCS in real fx-9860 calculators), then it has the
* same structure than on the calculator. These files exist because FA-124
* implements Bfile as well as the calculator (brilliant, huh?).
*
* The structure has been documented by Simon Lothar, but I haven't
* worked on it yet: TODO. */
#endif /* LIBG1M_FORMAT_MCSRAW_H */

View File

@ -12,9 +12,10 @@
# include <libg1m/format.h>
/* get type */
int g1m_get_type_info(unsigned char *main_id, unsigned char *subtype,
int g1m_get_type_info(const char *path,
unsigned char *main_id, unsigned char *subtype,
const char **info, int *check_one, int *check_two,
int (**rd)(g1m_t*, FILE*, struct standard_header*));
unsigned int *platform, unsigned int *type);
/* get mcs type data */
int g1m_mcstype_getlib(const unsigned char *groupname,

View File

@ -70,12 +70,15 @@
/* ************************************************************************** */
/* Specific parsing functions */
/* ************************************************************************** */
/* types */
int g1m_parse_g3p(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_c2p(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_mcs(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_mcsraw(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_eact(g1m_t * handle, FILE *stream,
struct standard_header *std);
int g1m_parse_addin(g1m_t *handle, FILE *stream,
@ -88,8 +91,10 @@ int g1m_parse_lang_cg(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_fkey(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_g1s(g1m_t *handle, FILE *stream,
struct standard_header *std);
/* others */
int g1m_parse_fkey_cg_content(g1m_t *handle, FILE *stream,
uint_fast32_t zonesize, uint32_t *pchecksum);
/* ************************************************************************** */
/* Picture utilities */
@ -118,7 +123,10 @@ G1M_PROTOTYPE_PIX(16bits)
/* Utilities */
/* ************************************************************************** */
/* Parsing */
int g1m_parse(g1m_t *handle, FILE *stream);
int g1m_parse(g1m_t *handle, const char *path, FILE *stream);
/* Free-ing */
void g1m_free_content(g1m_t *handle);
void g1m_free_mcsfile_content(g1m_mcsfile_t *handle);
void g1m_free_mcs(g1m_t *handle);
void g1m_free_line_content(g1m_line_t *line);

View File

@ -10,6 +10,7 @@
#ifndef LIBG1M_INTERNALS_LOG_H
# define LIBG1M_INTERNALS_LOG_H
# include <stdint.h>
# include <inttypes.h>
/* ************************************************************************** */
/* Log utility */

View File

@ -77,9 +77,6 @@ int g1m_parse_addin(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
(void)std;
/* set handle vars */
handle->type = g1m_type_addin;
/* get the subheader */
DREAD(hd, g1a_subheader)
@ -89,7 +86,7 @@ int g1m_parse_addin(g1m_t *handle, FILE *stream,
/* log info about the subheader */
log_info("internal name is '%.8s'", hd.internal_name);
log_info("title is '%.8s'", hd.title);
log_info("estrips count is %hhu", hd.estrips_count);
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);
@ -132,11 +129,6 @@ int g1m_parse_addin_cg(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
int err = 0;
/* set handle vars */
handle->type = g1m_type_addin;
handle->is_cg = 1;
/* get the subheader */
DREAD(hd, addin_cp_subheader)
@ -150,7 +142,8 @@ int g1m_parse_addin_cg(g1m_t *handle, FILE *stream,
- hd.magic[1] ? 0x7000 : 0x1000;
if (hd.control != content_size) {
log_fatal("control value is incorrect!");
log_fatal("calculated %lu, expected %u", content_size, hd.control);
log_fatal("calculated %zu, expected %" PRIu32,
content_size, hd.control);
return (g1m_error_magic);
}
@ -193,7 +186,8 @@ int g1m_parse_addin_cg(g1m_t *handle, FILE *stream,
err = g1m_error_magic;
if (checksum != hd.checksum) {
log_fatal("Invalid checksum!");
log_fatal("Header checksum is %u, calculated checksum is %lu",
log_fatal("Header checksum is %" PRIu32
", calculated checksum is %" PRIuFAST32,
hd.checksum, checksum);
goto fail;
}

View File

@ -67,7 +67,7 @@ static int eact_parse_content_eact(g1m_line_t *handle, uint8_t *buf,
bzero(handle->lines, sizeof(g1m_line_t*) * handle->_size);
/* browse the lines */
log_info("%d lines to browse", ehd.line_count);
log_info("%" PRIu32 " lines to browse", ehd.line_count);
if (ehd.line_count)
lds[0].entry_offset = be32toh(lds[0].entry_offset << 8);
for (uint_fast32_t i = 0; i < ehd.line_count; i++) {
@ -428,9 +428,6 @@ int g1m_parse_eact(g1m_t * handle, FILE *stream,
struct standard_header *std)
{
(void)std;
/* set handle type */
handle->type = g1m_type_eact;
/* parse the header */
DREAD(hd, eact_header)
@ -444,12 +441,12 @@ int g1m_parse_eact(g1m_t * handle, FILE *stream,
log_info("E-Activity version is '%s'.",
hd.eact_version == EACT_G1E ? "g1e" :
hd.eact_version == EACT_G2E ? "g2e" : "g3e");
log_info("Setup area size is 0x%x bytes long.",
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->is_cg = 1;
handle->platform = g1m_platform_cg;
/* skip the setup area */
SKIP(hd.setup_area_size)

View File

@ -9,6 +9,9 @@
/* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* Utilities */
/* ************************************************************************** */
/**
* fkeydup:
* "Duplicate" function key.
@ -27,12 +30,16 @@ static uint32_t **fkeydup(uint8_t *fkey)
return (pixels);
}
/* ************************************************************************** */
/* fx function keys file parsing utilities */
/* ************************************************************************** */
/**
* g1m_parse_fkey:
* Parse fx function keys files.
*
* @arg handle the libg1m handle.
* @arg stream the stream to parse from.
* @arg std pointer to the standard header.
* @return the error code (0 if ok).
*/
@ -95,3 +102,29 @@ fail:
handle->messages = NULL;
return (g1m_error_alloc);
}
/* ************************************************************************** */
/* cg function keys file parsing utilities */
/* ************************************************************************** */
/**
* g1m_parse_fkey_cg_content:
* Parse fx-CG key files.
*
* In fact, the main parsing function is `g1m_parse_lang_cg` (they really
* have the same subheader). TODO
*
* @arg handle the libg1m handle.
* @arg stream the stream to parse from.
* @return the error code (0 if ok).
*/
int g1m_parse_fkey_cg_content(g1m_t *handle, FILE *stream,
uint_fast32_t zonesize, uint32_t *pchecksum)
{
//handle->type = g1m_type_fkey;
(void)handle;
(void)stream;
(void)zonesize;
(void)pchecksum;
return (g1m_error_magic);
}

View File

@ -9,6 +9,9 @@
/* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* fx language files parsing */
/* ************************************************************************** */
/**
* g1m_parse_lang:
* Parse fx language files.
@ -23,17 +26,16 @@ int g1m_parse_lang(g1m_t *handle, FILE *stream,
{
(void)std;
/* set handle type */
handle->type = g1m_type_lang;
handle->messages = NULL;
/* read the subheader */
DREAD(hd, g1l_subheader)
/* correct the endianness */
uint_fast32_t num = be16toh(hd.message_count) + 1;
uint_fast16_t num = be16toh(hd.message_count) + 1;
/* log */
log_info("%lu messages to read", num);
log_info("%" PRIuFAST16 " messages to read", num);
/* beat the best, read the rest! */
size_t data_size = std->filesize - sizeof(struct standard_header)
@ -53,10 +55,10 @@ int g1m_parse_lang(g1m_t *handle, FILE *stream,
char *messages = (char*)(offsets + num);
/* read messages */
for (uint_fast32_t i = 0; i < num; i++) {
for (uint_fast16_t i = 0; i < num; i++) {
handle->messages[i] = NULL;
if (offsets[i] == (uint16_t)-1) {
log_info("[#%lu] -", i);
log_info("[#%" PRIuFAST16 "] -", i);
handle->count++;
continue ;
}
@ -65,7 +67,8 @@ int g1m_parse_lang(g1m_t *handle, FILE *stream,
offsets[i] = be16toh(offsets[i]);
/* log */
log_info("[#%lu] '%s' (0x%hu)", i, &messages[offsets[i]], offsets[i]);
log_info("[#%" PRIuFAST16 "] '%s' (0x%" PRIu16 ")", i,
&messages[offsets[i]], offsets[i]);
/* store */
handle->messages[i] = strdup(&messages[offsets[i]]);
@ -85,6 +88,98 @@ fail:
return (g1m_error_alloc);
}
/* ************************************************************************** */
/* cg language files parsing */
/* ************************************************************************** */
/**
* g1m_parse_lang_cg_content:
* Parse the content of the message zone size for a G3L language file.
*
* @arg handle the libg1m handle.
* @arg stream the stream 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_parse_lang_cg_content(g1m_t *handle, FILE *stream,
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] = strndup((char*)msg, msg_size);
if (!handle->messages[i]) goto fail;
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);
return (err);
}
/**
* g1m_parse_lang_cg:
* Parse fx-CG language files.
@ -98,10 +193,7 @@ fail:
int g1m_parse_lang_cg(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
(void)handle;
/* set handle type */
handle->type = g1m_type_lang;
handle->is_cg = 1;
handle->messages = NULL;
/* read the subheader */
@ -119,75 +211,36 @@ int g1m_parse_lang_cg(g1m_t *handle, FILE *stream,
log_info("datetime is '%.14s'", hd.datetime);
log_info("g3l filename is '%.16s'", hd.g3l_filename);
/* read the languages header */
DREAD(lhd, g3l_lang_header)
logm_info(&lhd, sizeof(struct g3l_lang_header));
/* correct endianness */
lhd.num = be32toh(lhd.num);
/* log */
log_info("there are %d messages", lhd.num);
/* read the entire message zone */
size_t message_zone_size = hd.message_zone_size
- sizeof(struct g3l_lang_header);
uint8_t message_zone[message_zone_size];
READ(message_zone, message_zone_size)
/* calculate checksum and check */
/* 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) +
g1m_checksum32(&lhd, sizeof(struct g3l_lang_header), 0) +
g1m_checksum32(message_zone, message_zone_size, 0);
log_info("header checksum is %u, calc checksum is %u",
hd.checksum, checksum);
sizeof(struct standard_header) * 255
- g1m_checksum32(std, sizeof(struct standard_header), 0) +
g1m_checksum32(&hd.magic, sizeof(struct g3l_subheader) - 4, 0);
/* 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_parse_lang_cg_content(handle, stream, zonesize, &checksum);
else return (g1m_error_magic);
if (err) return (g1m_error_magic);
/* check the checksum */
if (hd.checksum && hd.checksum != checksum) {
log_fatal("header checksum was invalid");
return (g1m_error_magic);
goto fail;
}
/* parse footer */
DREAD(footer, g3l_footer)
/* read the footer */
GDREAD(footer, g3l_footer)
footer.checksum = be32toh(footer.checksum);
if (footer.checksum != hd.checksum) {
log_fatal("footer checksum was invalid");
return (g1m_error_magic);
}
/* get parts */
const uint_fast32_t num = lhd.num + 1;
uint32_t *offsets = (uint32_t*)message_zone;
char *messages = (char*)message_zone + num * sizeof(uint32_t);
/* prepare tab */
handle->messages = malloc(sizeof(char*) * num);
handle->count = 0;
handle->_size = num;
if (!handle->messages)
return (g1m_error_alloc);
/* read messages */
for (uint_fast32_t i = 0; i < num; i++) {
/* check if offset is valid */
handle->messages[i] = NULL;
if (offsets[i] == (uint32_t)-1) {
log_info("[#%ld] -", i);
handle->count++;
continue ;
}
/* correct offset */
offsets[i] = be32toh(offsets[i]);
/* log */
log_info("[#%ld] '%s'", i, &messages[offsets[i]]);
/* store message */
handle->messages[i] = strdup(&messages[offsets[i]]);
if (!handle->messages[i]) goto fail;
handle->count++;
log_fatal("footer checksum was invalid!");
log_info("header checksum is %" PRIu32 ","
" calculated checksum is %" PRIu32,
hd.checksum, checksum);
goto fail;
}
/* no error */
@ -195,9 +248,6 @@ int g1m_parse_lang_cg(g1m_t *handle, FILE *stream,
/* omg fail! */
fail:
for (int i = 0; i < handle->count; i++)
free(handle->messages[i]);
free(handle->messages);
handle->messages = NULL;
g1m_free_content(handle);
return (g1m_error_alloc);
}

View File

@ -9,6 +9,117 @@
/* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* Getting the parsing function */
/* ************************************************************************** */
/* Correspondance type */
struct corresp {
unsigned int platform;
unsigned int type;
/* result */
int (*read)(g1m_t*, FILE*, struct standard_header*);
};
/* The correspondances */
static struct corresp parsing_functions[] = {
/* add-ins */
{g1m_platform_fx, g1m_type_addin,
g1m_parse_addin},
{g1m_platform_cg, g1m_type_addin,
g1m_parse_addin_cg},
/* mcs */
{g1m_platform_fx, g1m_type_mcs,
g1m_parse_mcs},
{g1m_platform_cg, g1m_type_mcs,
g1m_parse_mcs},
{g1m_platform_fx_raw, g1m_type_mcs,
g1m_parse_mcsraw},
/* language files */
{g1m_platform_fx, g1m_type_lang,
g1m_parse_lang},
{g1m_platform_cg, g1m_type_lang,
g1m_parse_lang_cg},
/* function keys file */
{g1m_platform_fx, g1m_type_fkey,
g1m_parse_fkey},
{g1m_platform_cg, g1m_type_fkey,
g1m_parse_lang_cg},
/* e-activities */
{g1m_platform_fx, g1m_type_eact,
g1m_parse_eact},
/* pictures */
{g1m_platform_cg, g1m_type_pict,
g1m_parse_g3p},
{g1m_platform_cp, g1m_type_pict,
g1m_parse_c2p},
{0, 0, NULL}
};
/**
* find_parse_function:
* Find the parsing function.
*
* @arg handle the handle.
* @arg path the file path.
* @arg std pointer to the standard header.
* @arg rd pointer to the read function.
* @return the error code (0 if ok).
*/
static int find_parse_function(g1m_t *handle, const char *path,
struct standard_header *std,
int (**rd)(g1m_t*, FILE*, struct standard_header*))
{
/* get the type */
unsigned int platform, type;
const char *type_string;
int check_one, check_two;
if (g1m_get_type_info(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 */
struct corresp *c = parsing_functions - 1;
while ((++c)->read) {
if (c->type != type)
continue;
if (c->platform != platform)
continue;
break;
}
if (!c->read) {
log_fatal("No parsing function was found for this type.");
return (g1m_error_magic);
}
/* set the vars */
handle->type = type;
handle->platform = platform;
*rd = c->read;
return (0);
}
/* ************************************************************************** */
/* Main parsing function */
/* ************************************************************************** */
/**
* g1m_parse:
* Parse a G1M file.
@ -17,11 +128,12 @@
* then read subparts according to the G1M type.
*
* @arg handle the handle.
* @arg path the file path.
* @arg stream the stream to parse from.
* @return the error code (0 if ok).
*/
int g1m_parse(g1m_t *handle, FILE *stream)
int g1m_parse(g1m_t *handle, const char *path, FILE *stream)
{
/* initialize the handle */
bzero(handle, sizeof(g1m_t));
@ -42,28 +154,14 @@ int g1m_parse(g1m_t *handle, FILE *stream)
hd.number = be16toh(hd.number);
/* get type */
int (*read_func)(g1m_t*, FILE*, struct standard_header*);
const char *type_string; int check_one, check_two;
if (g1m_get_type_info(hd.main_id, hd.subtype, &type_string,
&check_one, &check_two, &read_func))
return (g1m_error_magic);
/* check standard header magics */
if (check_one && hd.control != ((hd.filesize + 0x41) & 0xff)) {
log_info("First control byte isn't right.");
return (g1m_error_magic);
} else if (check_two && hd.control2 != ((hd.filesize + 0xb8) & 0xff)) {
log_info("Second control byte isn't right.");
return (g1m_error_magic);
}
int (*read_func)(g1m_t*, FILE*, struct standard_header*); int err;
if ((err = find_parse_function(handle, path, &hd, &read_func)))
return (err);
/* log some data */
log_info("Standard Header type is '%s'.", type_string);
log_info("Standard Header filesize is %uo.", hd.filesize);
log_info("Standard Header num is %d.", hd.number);
log_info("Standard Header filesize is %" PRIu32 "o.", hd.filesize);
log_info("Standard Header num is %" PRIu16 ".", hd.number);
/* subparse. */
handle->type = 0;
handle->is_cg = 0;
return ((*read_func)(handle, stream, &hd));
}

View File

@ -138,7 +138,7 @@ static int mcs_parse_spreadsheet(g1m_mcsfile_t *handle, FILE *stream,
uint_fast32_t cols = 0;
/* log some info */
log_info("%ld columns to parse!", colcount);
log_info("%" PRIuFAST32 " columns to parse!", colcount);
if (colcount) {
/* get the column directory */
@ -180,7 +180,8 @@ static int mcs_parse_spreadsheet(g1m_mcsfile_t *handle, FILE *stream,
/* log it */
char *bcd_string = g1m_bcdtoa(&cell);
log_info("[%ld, %ld] contains '%s'.", c, i, bcd_string);
log_info("[%" PRIuFAST32 ", %" PRIuFAST32 "] contains '%s'.",
c, i, bcd_string);
free(bcd_string);
}
@ -243,8 +244,7 @@ static int mcs_parse_list(g1m_mcsfile_t *handle, FILE *stream,
DREAD(hd, mcs_listheader)
/* correct endianess */
uint16_t elcount = hd.element_count;
elcount = be16toh(elcount);
uint_fast16_t elcount = be16toh(hd.element_count);
/* log */
log_info("Title is '%.8s'", hd.title);
@ -259,7 +259,7 @@ static int mcs_parse_list(g1m_mcsfile_t *handle, FILE *stream,
if (elcount) {
/* browse real elements */
log_info("Browsing %d list elements", elcount);
log_info("Browsing %" PRIuFAST16 " list elements", elcount);
READ(&real, elsize)
size -= elsize;
@ -295,10 +295,11 @@ static int mcs_parse_list(g1m_mcsfile_t *handle, FILE *stream,
#if LOGLEVEL <= ll_info
char *real_string = g1m_bcdtoa(&real[y]);
if (!has_complex)
log_info("Cell #%ld is (%s).", y, real_string);
log_info("Cell #%" PRIuFAST32 " is (%s).", y, real_string);
else {
char *imgn_string = g1m_bcdtoa(&imgn[y]);
log_info("Cell #%ld is (%s)+(%s)i.", y, real_string, imgn_string);
log_info("Cell #%" PRIuFAST32 " is (%s)+(%s)i.",
y, real_string, imgn_string);
free(imgn_string);
}
free(real_string);
@ -346,7 +347,7 @@ static int mcs_parse_matrix(g1m_mcsfile_t *handle, FILE *stream,
/* log info */
uint_fast32_t w = hd.width, h = hd.height;
log_info("Matrix size is %ld*%ld", w, h);
log_info("Matrix size is %" PRIuFAST32 "*%" PRIuFAST32, w, h);
/* store dimensions */
handle->rows = w;
@ -403,10 +404,12 @@ static int mcs_parse_matrix(g1m_mcsfile_t *handle, FILE *stream,
char *real_string = g1m_bcdtoa(&cell->real);
if (!g1m_bcd_has_complex(&cell->real))
log_info("[%lu][%lu] (%s).", x, y, real_string);
log_info("[%" PRIuFAST32 "][%" PRIuFAST32 "] (%s).",
x, y, real_string);
else {
char *imgn_string = g1m_bcdtoa(&cell->imgn);
log_info("[%lu][%lu] (%s)+(%s)i.", x, y, real_string, imgn_string);
log_info("[%" PRIuFAST32 "][%" PRIuFAST32 "] (%s)+(%s)i.",
x, y, real_string, imgn_string);
free(imgn_string);
}
free(real_string);
@ -448,7 +451,7 @@ static int mcs_parse_capture(g1m_mcsfile_t *handle, FILE *stream,
handle->height = hd.height;
/* print info */
log_info("capture is %ux%u sized", hd.width, hd.height);
log_info("capture is %dx%d sized", handle->width, handle->height);
/* get the image and return */
return (get_image(stream, &handle->image, handle->width, handle->height));
@ -701,10 +704,6 @@ int g1m_parse_mcs(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
int err = g1m_error_alloc;
/* set handle vars */
handle->type = g1m_type_mcs;
/* get number of subparts from the standard header */
uint_fast16_t num = std->number;
@ -717,7 +716,7 @@ int g1m_parse_mcs(g1m_t *handle, FILE *stream,
}
/* read all of the parts */
log_info("%ld total mcs files to browse", num);
log_info("%" PRIuFAST16 " total mcs files to browse", num);
while (handle->count < (int)num) {
/* get the subheader */
GDREAD(hd, mcs_subheader)
@ -740,7 +739,7 @@ int g1m_parse_mcs(g1m_t *handle, FILE *stream,
/* log info about the subpart */
log_info("[%lu] directory name is '%.8s'", i, fhd.dirname);
log_info("[%lu] filename is '%.8s'", i, fhd.filename);
log_info("[%lu] data length is %u", i, fhd.datalength);
log_info("[%lu] data length is %" PRIu32, i, fhd.datalength);
/* decode */
handle->files[handle->count] = NULL;

View File

@ -1,16 +1,16 @@
/* ************************************************************************** */
/* _____ _ */
/* parse/archive.c |_ _|__ _ _| |__ ___ _ _ */
/* parse/mcsraw.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/12/01 15:56:56 |___/ */
/* Last updated: 2016/12/25 13:38:52 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
/**
* g1m_parse_g1s:
* g1m_parse_mcsraw:
* Parse archives.
*
* @arg handle the libg1m handle.
@ -19,17 +19,16 @@
* @return the error code (0 if ok).
*/
int g1m_parse_g1s(g1m_t *handle, FILE *stream,
int g1m_parse_mcsraw(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
(void)handle;
/* set handle info */
//handle->type =
(void)stream;
(void)std;
/* TODO */
log_error("G1S archives are not managed yet.");
/* skip the first 0x270000 - 0x20 bytes */
SKIP(0x270000 - sizeof(struct standard_header))
/* then read and stuff... not yet. */
log_error("Raw MCS archives are not managed yet.");
(void)handle;
/* no error */
return (0);

View File

@ -39,9 +39,6 @@ static void g3p_deobfuscate(uint8_t *buf, size_t n)
int g1m_parse_g3p(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
/* set handle vars */
handle->type = g1m_type_pict;
/* get the G3P global header */
DREAD(hd, g3p_subheader)
hd.g3p_size = be32toh(hd.g3p_size);
@ -69,10 +66,11 @@ int g1m_parse_g3p(g1m_t *handle, FILE *stream,
size_t deflated_image_size = ihd.data_size - has_footer * 0x4;
/* log info */
log_info("Width: %dpx, height: %dpx", ihd.width, ihd.height);
log_info("Width: %" PRIu16 "px, height: %" PRIu16 "px",
ihd.width, ihd.height);
log_info("Pixel depth: %s",
(ihd.color_depth == g3p_color_4bit) ? "4-bit" : "16-bit");
log_info("Deflated image length: %uo", ihd.data_size - 0x04);
log_info("Deflated image length: %zuo", deflated_image_size);
log_info("Is obfuscated: %s", is_obfuscated ? "yes" : "no");
/* read image */
@ -87,7 +85,8 @@ int g1m_parse_g3p(g1m_t *handle, FILE *stream,
uLong adl = adler32(0, deflated_image, deflated_image_size);
if (adl != ft.checksum) {
log_fatal("Incorrect Adler32 checksum!");
log_fatal("Expected %u, got %lu", ft.checksum, adl);
log_fatal("Expected %" PRIu32 ", got %lu",
ft.checksum, adl);
return (g1m_error_magic);
}
}
@ -146,9 +145,6 @@ int g1m_parse_c2p(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
(void)std;
/* set handle vars */
//handle->type = g1m_type_pict;
(void)handle;
(void)stream;
/* TODO */

View File

@ -103,16 +103,14 @@ void g1m_free_mcs(g1m_t *handle)
}
/**
* g1m_free:
* g1m_free_content:
* Free handle data.
*
* @arg handle the handle to close.
*/
void g1m_free(g1m_t *handle)
void g1m_free_content(g1m_t *handle)
{
if (!handle) return ;
/* addin time! */
if (handle->type & g1m_type_addin)
free(handle->pixels);
@ -144,7 +142,18 @@ void g1m_free(g1m_t *handle)
/* e-activities time! */
if (handle->type & g1m_type_eact)
g1m_free_line_content(handle->line);
}
/* free the handle */
/**
* 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(handle);
}

View File

@ -26,7 +26,7 @@ int g1m_make_mcs(g1m_t **h)
/* initialize it */
g1m_t *handle = *h;
handle->type = g1m_type_mcs;
handle->is_cg = 0;
handle->platform = g1m_platform_fx;
handle->count = 0;
handle->_size = 0;
handle->files = NULL;

View File

@ -26,7 +26,7 @@ int g1m_open(g1m_t **handle, const char *path)
FILE *f = fopen(path, "r");
/* open using `g1m_fopen` */
int err = g1m_fopen(handle, f);
int err = g1m_fopen(handle, path, f);
/* close opened stream and return error code (or 0 if ok) */
if (f) fclose(f);
@ -40,12 +40,13 @@ int g1m_open(g1m_t **handle, const char *path)
* Will not seek, and will not keep the stream.
* Make sure to fclose the stream after use.
*
* @arg handle the handle to create
* @arg stream the stream
* @arg handle the handle to create.
* @arg path the file path.
* @arg stream the stream.
* @return the error code (0 if ok)
*/
int g1m_fopen(g1m_t **handle, FILE *stream)
int g1m_fopen(g1m_t **handle, const char *path, FILE *stream)
{
int err;
@ -58,7 +59,7 @@ int g1m_fopen(g1m_t **handle, FILE *stream)
if (!*handle) return (g1m_error_alloc);
/* fill it by parsing opened file */
if ((err = g1m_parse(*handle, stream))) {
if ((err = g1m_parse(*handle, path, stream))) {
free(*handle);
*handle = NULL;
return (err);

View File

@ -25,8 +25,9 @@ struct type_info {
const char *info;
unsigned int flags;
/* actions */
int (*read)(g1m_t*, FILE*, struct standard_header*);
/* types */
unsigned int platform;
unsigned int libtype;
};
/* Main type correspondance type */
@ -41,82 +42,120 @@ struct main_info {
/* ************************************************************************** */
/* Correspondances */
/* ************************************************************************** */
/* Terminate type list */
#define TTERM {NULL, NULL, 0, 0, 0}
/* Common magic types */
#define magic_common "\x00\x10\x00\x10\x00"
#define cp_magic "\x00\x01\x00\x01\x00"
#define blank "\xFF\xFF\xFF\xFF\xFF\xFF"
/* Main types */
static struct main_info types[] = {
/* USBPower (the most common one) */
{"USBPower", (struct type_info[]){
/* add-ins */
{"\xf3" magic_common,
"add-in", 0,
g1m_parse_addin},
{"\x2c" cp_magic,
"fx-CG add-in", 0,
g1m_parse_addin_cg},
{"\xf3" magic_common, "add-in", 0,
g1m_platform_fx, g1m_type_addin},
{"\x2c" cp_magic, "fx-CG add-in", 0,
g1m_platform_cg, g1m_type_addin},
/* MCS */
{"\x31" magic_common,
"mcs", 0,
g1m_parse_mcs},
{"\x62" magic_common,
"mcs (g2r)", 0,
g1m_parse_mcs},
{"\x75" magic_common,
"mcs (fx-CG)", 0,
g1m_parse_mcs},
{"\x62" magic_common, "mcs (g2r)", 0,
g1m_platform_fx, g1m_type_mcs}, /* TODO: add flag? */
{"\x31" magic_common, "mcs", 0,
g1m_platform_fx, g1m_type_mcs},
{"\x75" magic_common, "mcs (fx-CG)", 0,
g1m_platform_cg, g1m_type_mcs},
/* Language */
{"\x12" magic_common,
"fx language file", 0,
g1m_parse_lang},
{"\x12" magic_common, "fx language file", 0,
g1m_platform_fx, g1m_type_lang},
/* E-Activities */
{"\x49" magic_common,
"e-activity (document)", 0,
g1m_parse_eact},
{"\x49" magic_common, "e-activity (document)", 0,
g1m_platform_fx, g1m_type_eact},
/* Pictures */
{"\x7d" magic_common,
"fx-CG picture", 0,
g1m_parse_g3p},
{"\x7d" magic_common, "fx-CG picture", 0,
g1m_platform_cg, g1m_type_pict},
{}
TTERM
}},
/* Ly755 (Classpad-specific) */
{"Ly755 ", (struct type_info[]){
{"\x2c" cp_magic,
"fx-CG language file", 0,
g1m_parse_lang_cg},
{}
{"\x2c" cp_magic, "fx-CG language file", 0,
g1m_platform_cg, g1m_type_lang},
TTERM
}},
/* CASIO (only used for c2p...?) */
{"CASIO\0\0\0", (struct type_info[]){
{"c2p\0\0\0",
"Classpad picture", nochk_controlone | nochk_controltwo,
g1m_parse_c2p},
{}
}},
{"c2p\0\0\0", "Classpad picture", nochk_controlone | nochk_controltwo,
g1m_platform_cp, g1m_type_pict},
/* Blank (hack) */
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", (struct type_info[]){
{"\xFF\xFF\xFF\xFF\xFF\xFF",
"CASIO archive", nochk_controlone | nochk_controltwo,
g1m_parse_g1s},
{"\xFF\xFF\xFF\xFF\xFF\xFF",
"Function keys file", 0,
g1m_parse_fkey},
{}
TTERM
}},
/* terminating */
{}
{NULL, NULL}
};
/* ************************************************************************** */
/* Extensions comparison */
/* ************************************************************************** */
/* Extension correspondance type */
struct ext_corresp {
/* identification */
const char *ext;
/* data */
const char *info;
unsigned int platform;
unsigned int libtype;
};
/* Extension correspondances */
static struct ext_corresp ext_types[] = {
/* raw MCS */
{"g1s", "Raw Bfile backup", g1m_platform_fx_raw, g1m_type_mcs},
/* 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},
/* 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},
/* sentinel */
{NULL, NULL, 0, 0}
};
/**
* get_extension:
* Get extension from a path.
*
* @arg path the path.
* @return extension.
*/
static const char *get_extension(const char *path)
{
/* get filename */
const char *filename = strrchr(path, '/');
filename = filename ? filename + 1 : path;
/* get extension */
const char *ext = strrchr(filename, '.');
ext = ext ? ext + 1 : filename;
/* return it */
return (ext);
}
/* ************************************************************************** */
/* Main functions */
/* ************************************************************************** */
@ -124,49 +163,77 @@ static struct main_info types[] = {
* g1m_get_type_info:
* Get type info.
*
* @arg path Path of the file.
* @arg main_id The main ID (at least 8 bytes).
* @arg subtype The subtype (at least 6 bytes).
* @arg info Pointer to the info string to set.
* @arg check_one Check first control byte.
* @arg check_two Check second control byte.
* @arg read Pointer to the read callback to set.
* @arg platform Pointer to the platform to set.
* @arg type Pointer to the type to set.
* @return If there was an error.
*/
int g1m_get_type_info(unsigned char *main_id, unsigned char *subtype,
int g1m_get_type_info(const char *path,
unsigned char *main_id, unsigned char *subtype,
const char **info, int *check_one, int *check_two,
int (**rd)(g1m_t*, FILE*, struct standard_header*))
unsigned int *platform, unsigned int *type)
{
/* look for main_id */
struct main_info *mt = types;
while (mt->type) {
if (!memcmp(mt->type, main_id, 8))
break ;
mt++;
}
if (!mt->type) {
log_fatal("Main ID not recognized:");
logm_info(main_id, 8);
return (1);
}
/* look if blank */
if (!memcmp(main_id, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8)
&& !memcmp(subtype, "\xFF\xFF\xFF\xFF\xFF\xFF", 6)) {
log_info("Blank type! Let's use the extension to try and identify it.");
if (!path) return (1);
const char *ext = get_extension(path);
/* look for subtype */
struct type_info *sub = mt->subtypes;
while (sub->type) {
if (!memcmp(sub->type, subtype, 6))
break ;
sub++;
}
if (!sub->type) {
log_fatal("Type not managed (yet?):");
logm_info(subtype, 6);
return (1);
}
struct ext_corresp *e = ext_types - 1;
while ((++e)->ext) {
if (!strcmp(e->ext, ext))
break ;
}
if (!e->ext) {
log_fatal("No matching extension with '%s'!", ext);
return (1);
}
/* fill in info and return */
if (info) *info = sub->info;
if (rd) *rd = sub->read;
if (check_one) *check_one = ~sub->flags & nochk_controlone;
if (check_two) *check_two = ~sub->flags & nochk_controltwo;
/* fill in info */
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;
} else {
/* look for main_id */
struct main_info *mt = types - 1;
while ((++mt)->type) {
if (!memcmp(mt->type, main_id, 8))
break ;
}
if (!mt->type) {
log_fatal("Main ID not recognized:");
logm_info(main_id, 8);
return (1);
}
/* look for subtype */
struct type_info *sub = mt->subtypes;
while (sub->type) {
if (!memcmp(sub->type, subtype, 6))
break ;
sub++;
}
if (!sub->type) {
log_fatal("Type not managed (yet?):");
logm_info(subtype, 6);
return (1);
}
/* fill in info */
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;
}
return (0);
}