printf for inttypes.h types, blank types, raw mcs management began
This commit is contained in:
parent
3653adecc6
commit
a19e6ae3eb
|
@ -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!
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef LIBG1M_INTERNALS_LOG_H
|
||||
# define LIBG1M_INTERNALS_LOG_H
|
||||
# include <stdint.h>
|
||||
# include <inttypes.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Log utility */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
200
src/parse/lang.c
200
src/parse/lang.c
|
@ -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);
|
||||
}
|
||||
|
|
138
src/parse/main.c
138
src/parse/main.c
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
223
src/utils/type.c
223
src/utils/type.c
|
@ -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);
|
||||
}
|
||||
|
|
Reference in New Issue