cake
/
libg1m
Archived
1
0
Fork 0

Corrected CasEmul management (endianness)

This commit is contained in:
Thomas Touhey 2017-03-05 13:56:57 +01:00
parent 23f40d1695
commit 88fcbeeb85
5 changed files with 84 additions and 59 deletions

View File

@ -70,7 +70,7 @@
# Compiler
CC := $(TARGET)gcc
# - Check flags (warnings)
CWERROR := all extra no-attributes no-unused-macros no-vla
CWERROR := all extra no-attributes no-unused-macros no-vla no-multichar
ifdef MORE_WARNINGS
CWERROR += shadow write-strings redundant-decls format format-nonliteral \
format-security implicit-function-declaration \

View File

@ -22,13 +22,12 @@
# pragma pack(1)
/* Casemul files are made of an overall header, a source part and an
* optional compiled part. One thing to know is that every header has an
* internal header, which always has this structure: */
* optional compiled part. One thing to know is that every specific header has
* an internal header, which always has this structure: */
struct casemul_internal_header {
/* this type was made using `MAKELONG`: you have to reverse the bytes in
* each word (e.g. AC-FS -> CA-SF). */
char type[4];
/* this signature, a set of 4 characters identifying the header type */
uint32_t signature;
/* version (more or less 0xMMmm, where MM is the major and mm the minor) */
uint32_t version;
@ -37,27 +36,35 @@ struct casemul_internal_header {
uint32_t size;
};
/* The signature is made using `MAKELONG`, a Microsoft Windows specific macro
* which concatenates two words (16-bit integers) into a single long
* (32-bit integer). One usage in CasEmul is the following:
*
* MAKELONG('CA', 'FS') -- for the overall header's internal header.
*
* And here is the macro: */
#ifndef MAKELONG /* XXX: does it work with big endian platforms? */
# define MAKELONG(a, b) \
((uint32_t) (((uint16_t) (((uint32_t) (a)) & 0xffff)) | \
((uint32_t) ((uint16_t) (((uint32_t) (b)) & 0xffff))) << 16))
#endif
/* The multi-byte values do not have a defined endianness! The Casemul files
* are generated from C++ classes, so when one is generated, the host's
* endianness is used. Also, there is no setting anywhere in the file to say
* whether the host was big endian or little endian.
*
* Actually, there is a way to guess using the magic, which is made using
* `MAKELONG`, which concatenates two words ('CA' and 'FS', 'AC' and 'SF' in
* little endian). That means if it is "CASF", then the file was generated on
* a big endian platform, and if it is "ACFS", it was generated on a little
* endian platform.
*
* The libg1m implementation just supposes the file was generated on a
* little-endian platform, as CasEmul was used when Microsoft Windows was
* only implemented on x86-like platforms (little endian). */
* endianness is used. There is no setting anywhere related to endianness,
* but the endianness can be guessed using the magic word: if it is
* "CASF", then the platform was big endian, otherwise ("ACFS"), the platform
* was little endian (very probable, as Microsoft Windows is mostly used on
* the x86 architecture, which is little endian). */
/* ************************************************************************** */
/* Overall, source and compiled headers */
/* ************************************************************************** */
/* The overall header contains information about the other sections, and the
* current state of the file (whether it contains the compiled part or not).
*
* Its internal header ID is "CAFS" (ACFS, used as the magic string).
* Its internal header ID is MAKELONG('CA', 'FS') (abbreviated "CAFS" for
* simplicity, see the 'problem' with endianness above).
* The expected version is 1.00. */
# define casemul_compiled 0x80 /* if the compiled program is there */

View File

@ -27,13 +27,13 @@
/* ************************************************************************** */
/* General type */
typedef unsigned int g1m_type_t;
# define g1m_type_addin 0x01
# define g1m_type_mcs 0x02
# define g1m_type_eact 0x04
# define g1m_type_picture 0x08
# define g1m_type_lang 0x10
# define g1m_type_fkey 0x20
# define g1m_type_storage 0x40
# define g1m_type_addin 0x0001
# define g1m_type_mcs 0x0002
# define g1m_type_eact 0x0004
# define g1m_type_picture 0x0008
# define g1m_type_lang 0x0010
# define g1m_type_fkey 0x0020
# define g1m_type_storage 0x0040
/* General type aliases */
# define g1m_type_pict g1m_type_picture
@ -42,10 +42,18 @@ typedef unsigned int g1m_type_t;
/* Platform */
typedef unsigned int g1m_platform_t;
# define g1m_platform_none 0x00
# define g1m_platform_fx 0x01
# define g1m_platform_cp 0x02
# define g1m_platform_cg 0x04
# define g1m_platform_none 0x0000
# define g1m_platform_fx 0x0001
# define g1m_platform_cp 0x0002
# define g1m_platform_cg 0x0004
# define g1m_platform_cas 0x0008
# define g1m_platform_casemul 0x0010
/* Platform flags */
# define g1m_platflag_be 0x8000
/* Platform macros */
# define g1m_platform(P) ((P) & 0x7FFF)
/* ************************************************************************** */
/* Helpers */
@ -61,10 +69,9 @@ typedef struct g1m_version_s {
/* Handle structure */
/* ************************************************************************** */
typedef struct {
/* g1m type */
/* file type, the source destination platform */
g1m_type_t type;
/* for what platform is this type made for? */
g1m_platform_t platform;
g1m_platform_t platform; /* use the `g1m_platorm` macro! */
/* Add-in related data */
char title[17];

View File

@ -36,7 +36,7 @@ int g1m_decode(g1m_t *handle, const char *path, g1m_buffer_t *buffer,
g1m_type_t expected_types)
{
/* initialize the handle */
bzero(handle, sizeof(g1m_t));
memset(handle, 0, sizeof(g1m_t));
/* identify a CAS file */
unsigned char buf[0x20]; READ(buf, 1)
@ -45,9 +45,9 @@ int g1m_decode(g1m_t *handle, const char *path, g1m_buffer_t *buffer,
/* identify a Casemul file */
READ(&buf[1], 3)
log_info("Buffer content is:");
logm_info(buf, 4);
if (!memcmp(buf, "ACFS", 4))
if (!memcmp(buf, "CAFS", 4)) {
handle->platform |= g1m_platflag_be;
} else if (!memcmp(buf, "ACFS", 4))
return (g1m_decode_casemul(handle, buffer));
/* identify a standard header (send a _copy_) */

View File

@ -24,7 +24,9 @@
* have while in the MCS, but the format CasEmul uses internally.
* ************************************************************************** */
#include <libg1m/internals.h>
#define VER 0x00000100 /* 1.00, the expected version in the internal headers */
#define e32toh(N) ((big_endian) ? be32toh(N) : le32toh(N))
#define htoe32(N) ((big_endian) ? htobe32(N) : htole32(N))
#define VER htoe32(0x00000100) /* 1.00 */
/* ************************************************************************** */
/* Utilities */
@ -39,18 +41,17 @@
* @return the error (if any).
*/
static int read_internal(g1m_buffer_t *buffer, const char *type,
static int read_internal(g1m_buffer_t *buffer, uint32_t signature,
uint_fast32_t version)
{
DREAD(hd, casemul_internal_header)
/* check type */
if (type[0] != hd.type[1] || type[1] != hd.type[0]
|| type[2] != hd.type[3] || type[3] != hd.type[2]) {
log_error("type mismatch!");
if (signature != hd.signature) {
const char *a = (char*)&signature, *b = (char*)&hd.signature;
log_error("signature mismatch!");
log_error("expected '%c%c%c%c', got '%c%c%c%c'",
type[0], type[1], type[2], type[3],
hd.type[1], hd.type[0], hd.type[3], hd.type[2]);
a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
return (g1m_error_magic);
}
@ -59,7 +60,7 @@ static int read_internal(g1m_buffer_t *buffer, const char *type,
log_error("version mismatch!");
log_error("version mismatch!");
log_error("epxected %08" PRIxFAST32 ", got %08" PRIx32,
version, le32toh(hd.version));
version, hd.version);
return (g1m_error_magic);
}
@ -108,10 +109,12 @@ static int read_top(g1m_buffer_t *buffer, char *name, uint_fast32_t *length)
*
* @arg pfile the pointer to the mcsfile to make and fill.
* @arg buffer the buffer to read from.
* @arg big_endian whether the file is big endian or not.
* @return the error (if occured).
*/
static int read_picture(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer)
static int read_picture(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer,
int big_endian)
{
int err; *pfile = NULL;
static const uint32_t colours[256] = {
@ -125,7 +128,7 @@ static int read_picture(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer)
/* general record things */
char name[13]; uint_fast32_t record_length;
if ((err = read_top(buffer, name, &record_length))
|| (err = read_internal(buffer, "PICT", VER)))
|| (err = read_internal(buffer, MAKELONG('PI', 'CT'), VER)))
return (err);
/* specific things */
@ -170,17 +173,19 @@ static int read_picture(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer)
*
* @arg pfile the pointer to the mcsfile to make and fill.
* @arg buffer the buffer to read from.
* @arg big_endian whether the file is big endian encoded or not.
* @return the error that occured.
*/
static int read_matrix(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer)
static int read_matrix(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer,
int big_endian)
{
int err;
/* general record things */
char name[13]; uint_fast32_t record_length;
if ((err = read_top(buffer, name, &record_length))
|| (err = read_internal(buffer, "MTRX", VER)))
|| (err = read_internal(buffer, MAKELONG('MT', 'RX'), VER)))
return (err);
/* read specific things */
@ -235,17 +240,19 @@ static int read_matrix(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer)
*
* @arg pfile the pointer to the mcsfile to make and fill.
* @arg buffer the buffer to read from.
* @arg big_endian whether the file is big endian encoded or not.
* @return the error that occured.
*/
static int read_list(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer)
static int read_list(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer,
int big_endian)
{
int err;
/* general record things */
char name[13]; uint_fast32_t record_length;
if ((err = read_top(buffer, name, &record_length))
|| (err = read_internal(buffer, "LIST", VER)))
|| (err = read_internal(buffer, MAKELONG('LI', 'ST'), VER)))
return (err);
/* read specific things */
@ -303,19 +310,20 @@ static int read_list(g1m_mcsfile_t **pfile, g1m_buffer_t *buffer)
int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer)
{
int err;
int err, big_endian = handle->platform & g1m_platflag_be;
/* read the overall header's internal header end */
struct casemul_internal_header overall_int = {.type = "ACFS"};
struct casemul_internal_header overall_int = {
.signature = MAKELONG('CA', 'FS')};
READ(&overall_int.version, 8);
if (le32toh(overall_int.version) != 0x100)
if (e32toh(overall_int.version) != 0x100)
return (g1m_error_magic);
/* read the overall (global) header */
DREAD(glb, casemul_header)
/* read the source header */
if ((err = read_internal(buffer, "SRCE", VER)))
if ((err = read_internal(buffer, MAKELONG('SR', 'CR'), VER)))
return (err);
DREAD(src, casemul_source_header)
log_info("%d program(s), %d pic(s), %d matrix(es), %d list(s)",
@ -336,7 +344,7 @@ int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer)
/* general record things */
char name[13]; uint_fast32_t record_length;
if ((err = read_top(buffer, name, &record_length))
|| (err = read_internal(buffer, "PROG", VER)))
|| (err = read_internal(buffer, MAKELONG('PR', 'OG'), VER)))
goto fail;
/* specific things */
@ -349,21 +357,24 @@ int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer)
/* read each picture */
for (int i = 0; i < src.pictures; i++) {
if ((err = read_picture(&handle->files[handle->count], buffer)))
if ((err = read_picture(&handle->files[handle->count], buffer,
big_endian)))
goto fail;
handle->count++;
}
/* read each matrix */
for (int i = 0; i < src.matrixes; i++) {
if ((err = read_matrix(&handle->files[handle->count], buffer)))
if ((err = read_matrix(&handle->files[handle->count], buffer,
big_endian)))
goto fail;
handle->count++;
}
/* read each list */
for (int i = 0; i < src.lists; i++) {
if ((err = read_list(&handle->files[handle->count], buffer)))
if ((err = read_list(&handle->files[handle->count], buffer,
big_endian)))
goto fail;
handle->count++;
}