cake
/
libg1m
Archived
1
0
Fork 0

Changed the way type is detected

This commit is contained in:
Thomas Touhey 2016-12-01 13:34:10 +01:00
parent 4474d276f1
commit c728eff645
11 changed files with 236 additions and 198 deletions

View File

@ -1,10 +1,10 @@
/* ************************************************************************** */
/* _____ _ */
/* libg1m/format/main.h |_ _|__ _ _| |__ ___ _ _ */
/* libg1m/format.h |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/02 14:15:46 |___/ */
/* Last updated: 2016/12/01 13:33:58 |___/ */
/* */
/* ************************************************************************** */
#ifndef LIBG1M_FORMAT_H
@ -35,17 +35,11 @@
* it can simply be obtained by bitwise-AND-ing with 0xff. */
struct standard_header {
/* the file identifier - see below */
/* the file identifier */
uint8_t main_id[8];
/* our filetype! */
uint8_t type;
/* magic numbers, not always the same:
* - for fx-CG formats: {0x00, 0x01, 0x00, 0x01, 0x00}
* - for C2P: "2p\0\0\0"
* - otherwise: {0x00, 0x10, 0x00, 0x10, 0x00} */
uint8_t magic[5];
/* our subtype! */
uint8_t subtype[6];
/* first control byte: filesize LSB + 0x41 */
uint8_t control;
@ -70,67 +64,17 @@ struct standard_header {
};
/* At the beginning, we thought "USBPower" was some magic sequence we would
* systematically find in the "main_id" field. But a counter example came:
* the G3L, where the main ID was "Ly755 ".
* systematically find in the "main_id" field. But counter examples came:
* the G3L, whose main ID was "Ly755 ", and the C2P.
*
* So here are the known main IDs: */
enum g1m_main_id {
/* "USBPower": the most common one */
g1m_mid_usbpower,
/* "Ly755 ": fx-CG specific types */
g1m_mid_ly755,
/* "CASIO\0\0\0": some other types */
g1m_mid_casio,
};
/* Each main ID have their own types. Here are the USBPower types: */
enum g1m_usbpower_type {
/* fx language file */
g1m_usbpower_type_lang = 0x12,
/* fx-CG add-in */
g1m_usbpower_type_addin_cg = 0x2c,
/* mcs (main memory) save */
g1m_usbpower_type_mcs = 0x31,
/* e-activity (document) */
g1m_usbpower_type_eact = 0x49,
/* g1r equivalent */
g1m_usbpower_type_g2r = 0x62,
/* g3m (fx-CG program) */
g1m_usbpower_type_g3m = 0x75,
/* g3p (fx-CG picture) */
g1m_usbpower_type_g3p = 0x7d,
/* add-in (compiled program) */
g1m_usbpower_type_addin = 0xf3,
};
/* Here are Ly755 types: */
enum g1m_ly755_type {
/* language file */
g1m_ly755_type_lang = 0x2c
};
/* And here are the CASIO types: */
enum g1m_casio_type {
/* c2p */
g1m_casio_type_c2p = 0x63
};
* 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. */
# pragma pack()
/* After the Standard Header is read and the G1M type is read, we have parts,
/* 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. */

View File

@ -4,7 +4,7 @@
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/10/31 00:14:27 |___/ */
/* Last updated: 2016/12/01 13:33:58 |___/ */
/* */
/* ************************************************************************** */
#ifndef LIBG1M_INTERNALS_H
@ -54,18 +54,27 @@
/* skipping utility */
int g1m_parse_skip(FILE *stream, size_t size, uint_fast32_t *checksum);
/* type getting utility */
int g1m_get_type_info(unsigned char *main_id, unsigned char *subtype,
const char **info, int (**rd)(g1m_t*, FILE*, struct standard_header*));
/* ************************************************************************** */
/* Specific parsing functions */
/* ************************************************************************** */
int g1m_parse_g3p(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_c2p(g1m_t *handle, FILE *stream);
int g1m_parse_mcs(g1m_t *handle, FILE *stream, uint_fast16_t num);
int g1m_parse_eact(g1m_t * handle, FILE *stream);
int g1m_parse_addin(g1m_t *handle, FILE *stream);
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_eact(g1m_t * handle, FILE *stream,
struct standard_header *std);
int g1m_parse_addin(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_addin_cg(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_lang(g1m_t *handle, FILE *stream);
int g1m_parse_lang(g1m_t *handle, FILE *stream,
struct standard_header *std);
int g1m_parse_lang_cg(g1m_t *handle, FILE *stream,
struct standard_header *std);

View File

@ -127,35 +127,6 @@ void g1m_log_mem(const char *prefx, void *m, size_t n)
/* ************************************************************************** */
/* Enumerations strings */
/* ************************************************************************** */
/**
* g1m_get_type_string:
* Get string description of a type of a G1M file.
*
* @arg code the code.
* @return the string.
*/
const char *g1m_get_type_string(int main_id, int type)
{
switch (main_id) {
case g1m_mid_usbpower:
switch (type) {
case g1m_usbpower_type_addin_cg: return ("fx-CG addin");
case g1m_usbpower_type_mcs: return ("mcs");
case g1m_usbpower_type_eact: return ("e-activity");
case g1m_usbpower_type_g2r: return ("mcs (g2r)");
case g1m_usbpower_type_g3p: return ("g3p");
case g1m_usbpower_type_addin: return ("addin");
}
break;
case g1m_mid_ly755:
switch (type) {
case g1m_ly755_type_lang: return ("fx-CG language file");
}
}
return ("unknown");
}
/**
* g1m_get_mcs_ftype_string:
* Get string description of a type of a G1M part directory.

View File

@ -4,7 +4,7 @@
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/02 14:47:49 |___/ */
/* Last updated: 2016/12/01 13:33:45 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
@ -66,8 +66,13 @@ static void set_data(g1m_t *handle,
* @return the error code (0 if ok).
*/
int g1m_parse_addin(g1m_t *handle, FILE *stream)
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)
@ -115,6 +120,10 @@ int g1m_parse_addin(g1m_t *handle, FILE *stream)
int g1m_parse_addin_cg(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
/* set handle vars */
handle->type = g1m_type_addin;
handle->is_cg = 1;
/* get the subheader */
DREAD(hd, g3a_subheader)

View File

@ -4,7 +4,7 @@
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/02 14:47:49 |___/ */
/* Last updated: 2016/12/01 13:33:45 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
@ -137,15 +137,20 @@ static int g1m_parse_eact_cont(g1m_t *handle, uint8_t *buf, size_t bufsize,
* g1m_parse_eact:
* Parse an EACT.
*
* Thanks to Julese50/CoiledSpring for his help on e-acts parsing.
* Thanks to Julese50 for his help on e-acts parsing.
*
* @arg handle the handle.
* @arg stream the stream to parse from.
* @return the error code (0 if ok).
*/
int g1m_parse_eact(g1m_t * handle, FILE *stream)
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)
@ -162,6 +167,10 @@ int g1m_parse_eact(g1m_t * handle, FILE *stream)
log_info("Setup area size is 0x%x bytes long.",
hd.setup_area_size);
/* check if is CG */
if (hd.eact_version == EACT_G3E)
handle->is_cg = 1;
/* skip the setup area */
SKIP(hd.setup_area_size)

View File

@ -4,7 +4,7 @@
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/24 18:00:21 |___/ */
/* Last updated: 2016/12/01 13:33:45 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
@ -18,10 +18,16 @@
* @return the error code (0 if ok).
*/
int g1m_parse_lang(g1m_t *handle, FILE *stream)
int g1m_parse_lang(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
(void)std;
/* set handle type */
//handle->type = g1m_type_lang;
(void)handle;
(void)stream;
/* TODO */
log_info("Language type isn't managed yet.");
return (0);
}
@ -40,6 +46,10 @@ 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;
/* read the subheader */
DREAD(hd, g3l_subheader)

View File

@ -4,30 +4,11 @@
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/02 14:47:49 |___/ */
/* Last updated: 2016/12/01 13:33:45 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
/**
* get_main_id:
* Get numerical main ID based on the main ID string.
*
* @arg s the 8-bytes buffer containing the ID.
* @return the main ID or -1 if the main ID is unknown.
*/
static int get_main_id(unsigned char *s)
{
if (!memcmp(s, "USBPower", 8))
return (g1m_mid_usbpower);
if (!memcmp(s, "Ly755 ", 8))
return (g1m_mid_ly755);
if (!memcmp(s, "CASIO\0\0\0", 8))
return (g1m_mid_casio);
return (-1);
}
/**
* g1m_parse:
* Parse a G1M file.
@ -53,7 +34,7 @@ int g1m_parse(g1m_t *handle, FILE *stream)
for (size_t i = 0; i < sizeof(struct standard_header); i++) u[i] = ~u[i];
/* print header */
log_info("Raw standard header is:");
log_info("Raw inverted standard header is:");
logm_info(&hd, sizeof(struct standard_header));
/* correct standard header endianess */
@ -69,68 +50,19 @@ int g1m_parse(g1m_t *handle, FILE *stream)
return (g1m_error_magic);
}
/* get the main ID */
int main_id = get_main_id(hd.main_id);
if (main_id < 0) {
log_fatal("Main ID is unknown: '%.8s'", hd.main_id);
/* get main ID */
int (*read_func)(g1m_t*, FILE*, struct standard_header*);
const char *type_string;
if (g1m_get_type_info(hd.main_id, hd.subtype, &type_string, &read_func))
return (g1m_error_magic);
}
/* log some data */
log_info("Standard Header Main ID is '%.8s'", hd.main_id);
log_info("Standard Header Type is '%s' (0x%02x)",
g1m_get_type_string(main_id, hd.type), hd.type);
log_info("Standard Header filesize is %uo", hd.filesize);
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);
/* subparse. */
handle->type = 0;
handle->is_cg = 0;
switch (main_id) {
case g1m_mid_usbpower: switch (hd.type) {
case g1m_usbpower_type_lang:
handle->type = g1m_type_lang;
return (g1m_parse_lang(handle, stream));
case g1m_usbpower_type_addin:
handle->type = g1m_type_addin;
return (g1m_parse_addin(handle, stream));
case g1m_usbpower_type_addin_cg:
handle->type = g1m_type_addin;
handle->is_cg = 1;
return (g1m_parse_addin_cg(handle, stream, &hd));
case g1m_usbpower_type_g2r:
case g1m_usbpower_type_mcs:
handle->type = g1m_type_mcs;
return (g1m_parse_mcs(handle, stream, hd.number));
case g1m_usbpower_type_eact:
handle->type = g1m_type_eact;
return (g1m_parse_eact(handle, stream));
case g1m_usbpower_type_g3p:
handle->type = g1m_type_pict;
handle->is_cg = 1;
return (g1m_parse_g3p(handle, stream, &hd));
default:
log_info("Type not managed (yet?): 0x%02x", hd.type);
} break;
case g1m_mid_ly755: switch (hd.type) {
case g1m_ly755_type_lang:
handle->type = g1m_type_lang;
handle->is_cg = 1;
return (g1m_parse_lang_cg(handle, stream, &hd));
break;
default:
log_info("Type not managed (yet?): 0x%02x", hd.type);
} break;
case g1m_mid_casio: switch (hd.type) {
case g1m_casio_type_c2p:
handle->type = g1m_type_pict;
return (g1m_parse_c2p(handle, stream));
break;
default:
log_info("Type not managed (yet?): 0x%02x", hd.type);
} break;
}
/* no error */
return (0);
return ((*read_func)(handle, stream, &hd));
}

View File

@ -4,7 +4,7 @@
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/02 14:47:49 |___/ */
/* Last updated: 2016/12/01 13:33:45 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
@ -529,12 +529,16 @@ int g1m_parse_mcsfile_content(g1m_mcsfile_t **handle, FILE *stream,
* @return the error code (0 if ok).
*/
int g1m_parse_mcs(g1m_t *handle, FILE *stream, uint_fast16_t num)
int g1m_parse_mcs(g1m_t *handle, FILE *stream,
struct standard_header *std)
{
int err = g1m_error_alloc;
/* No "global" header for MCS parts, because this "global header"
* was the standard header. */
/* set handle vars */
handle->type = g1m_type_mcs;
/* get number of subparts from the standard header */
uint_fast16_t num = std->number;
/* allocate memory for the subparts */
handle->mcs_count = 0;

View File

@ -1,10 +1,10 @@
/* ************************************************************************** */
/* _____ _ */
/* parse/picture_cg.c |_ _|__ _ _| |__ ___ _ _ */
/* parse/picture.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/02 14:47:49 |___/ */
/* Last updated: 2016/12/01 13:33:45 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
@ -39,6 +39,9 @@ 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);
@ -138,13 +141,17 @@ int g1m_parse_g3p(g1m_t *handle, FILE *stream,
* @return the error code (0 if ok).
*/
int g1m_parse_c2p(g1m_t *handle, FILE *stream)
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;
handle->type = 0;
log_info("C2P files are not managed yet.");
/* TODO */
log_info("C2P files are not managed yet.");
/* no error */
return (0);

View File

@ -1,10 +1,10 @@
/* ************************************************************************** */
/* _____ _ */
/* parse/skip.c |_ _|__ _ _| |__ ___ _ _ */
/* utils/skip.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/02 14:48:51 |___/ */
/* Last updated: 2016/12/01 13:33:41 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>

143
src/utils/type.c Normal file
View File

@ -0,0 +1,143 @@
/* ************************************************************************** */
/* _____ _ */
/* utils/type.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/12/01 13:33:41 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* Local types */
/* ************************************************************************** */
/* Subtype correspondance type */
struct type_info {
/* identification */
const char *type;
/* info */
const char *info;
/* actions */
int (*read)(g1m_t*, FILE*, struct standard_header*);
};
/* Main type correspondance type */
struct main_info {
/* identification */
const char *type;
/* subtypes */
struct type_info *subtypes;
};
/* ************************************************************************** */
/* Correspondances */
/* ************************************************************************** */
/* Common magic types */
#define magic_common "\x00\x10\x00\x10\x00"
#define cp_magic "\x00\x01\x00\x01\x00"
/* USBPower subtypes */
static struct type_info usbpower_types[] = {
/* add-ins */
{"\xf3" magic_common,
"add-in", g1m_parse_addin},
{"\x2c" cp_magic,
"fx-CG add-in", g1m_parse_addin_cg},
/* MCS */
{"\x31" magic_common,
"mcs", g1m_parse_mcs},
{"\x62" magic_common,
"mcs (g2r)", g1m_parse_mcs},
{"\x75" magic_common,
"mcs (fx-CG)", g1m_parse_mcs},
/* Language */
{"\x12" magic_common,
"fx language file", g1m_parse_lang},
/* E-Activities */
{"\x49" magic_common,
"e-activity (document)", g1m_parse_eact},
/* Pictures */
{"\x7d" magic_common,
"fx-CG picture", g1m_parse_g3p},
{}
};
/* Ly755 subtypes */
static struct type_info ly755_types[] = {
{"\x2c" cp_magic,
"fx-CG language file", g1m_parse_lang_cg},
{}
};
/* CASIO subtypes */
static struct type_info casio_types[] = {
{"c2p\0\0\0",
"Classpad picture", g1m_parse_c2p},
{}
};
/* Main types */
static struct main_info types[] = {
{"USBPower", usbpower_types},
{"Ly755 ", ly755_types},
{"CASIO\0\0\0", casio_types},
{}
};
/* ************************************************************************** */
/* Main functions */
/* ************************************************************************** */
/**
* g1m_get_type_info:
* Get type info.
*
* @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 read Pointer to the read callback to set.
* @return If there was an error.
*/
int g1m_get_type_info(unsigned char *main_id, unsigned char *subtype,
const char **info, int (**rd)(g1m_t*, FILE*, struct standard_header*))
{
/* 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 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 and return */
if (info) *info = sub->info;
if (rd) *rd = sub->read;
return (0);
}