Updated
This commit is contained in:
parent
885bcff337
commit
d96e450afb
|
@ -29,12 +29,16 @@ typedef enum {
|
|||
g1m_error_noread,
|
||||
/* could not seek in stream */
|
||||
g1m_error_noseek,
|
||||
|
||||
/* magic or control problem */
|
||||
g1m_error_magic,
|
||||
/* unexpected EOF */
|
||||
g1m_error_eof,
|
||||
/* memory allocation problem */
|
||||
g1m_error_alloc,
|
||||
|
||||
/* operation not supported for this type */
|
||||
g1m_error_op,
|
||||
} g1m_error_t;
|
||||
|
||||
/* Message getting macro */
|
||||
|
@ -62,16 +66,20 @@ typedef uint16_t FONTCHARACTER;
|
|||
/* ************************************************************************** */
|
||||
/* MCS file type */
|
||||
typedef enum {
|
||||
g1m_mftype_program = 0x01,
|
||||
g1m_mftype_list = 0x02,
|
||||
g1m_mftype_mat = 0x04,
|
||||
g1m_mftype_pict = 0x08,
|
||||
g1m_mftype_capt = 0x10,
|
||||
g1m_mftype_ssheet = 0x20
|
||||
g1m_mcstype_program = 0x01,
|
||||
g1m_mcstype_list = 0x02,
|
||||
g1m_mcstype_mat = 0x04,
|
||||
g1m_mcstype_pict = 0x08,
|
||||
g1m_mcstype_capt = 0x10,
|
||||
g1m_mcstype_spreadsheet = 0x20
|
||||
} g1m_mcsfile_type_t;
|
||||
|
||||
/* BCD matrix - real and complex */
|
||||
typedef struct bcd g1m_mcs_cell_t[2];
|
||||
typedef struct {
|
||||
struct bcd real;
|
||||
struct bcd imgn;
|
||||
int used;
|
||||
} g1m_mcs_cell_t;
|
||||
|
||||
/* mcs file */
|
||||
typedef struct {
|
||||
|
@ -79,28 +87,28 @@ typedef struct {
|
|||
char dirname[9];
|
||||
|
||||
/* file name */
|
||||
char filename[9];
|
||||
char name[9];
|
||||
|
||||
/* file type */
|
||||
int filetype;
|
||||
int type;
|
||||
|
||||
/* for programs: the password */
|
||||
char password[9];
|
||||
|
||||
/* for spreadsheets, lists and matrixes */
|
||||
unsigned int columns, rows;
|
||||
g1m_mcs_cell_t **cells;
|
||||
g1m_mcs_cell_t *cells;
|
||||
|
||||
/* for pictures and captures */
|
||||
unsigned int width, height;
|
||||
uint32_t *image; /* 0x0RGB */
|
||||
uint32_t *second_image; /* 0x0RGB */
|
||||
uint32_t **image; /* 0x0RGB */
|
||||
uint32_t **second_image; /* 0x0RGB */
|
||||
} g1m_mcsfile_t;
|
||||
|
||||
/* mcs list */
|
||||
typedef struct {
|
||||
int count;
|
||||
int _mcs_part_size; /* used internally for reallocs */
|
||||
int parts_count;
|
||||
int _parts_size; /* used internally for reallocs */
|
||||
g1m_mcsfile_t **parts;
|
||||
} g1m_mcs_t;
|
||||
|
||||
|
@ -139,8 +147,8 @@ typedef struct {
|
|||
|
||||
/* MCS RELATED DATA */
|
||||
int part_count;
|
||||
int _part_size; /* used internally for reallocs */
|
||||
g1m_mcs_t **subs;
|
||||
int _parts_size; /* used internally for reallocs */
|
||||
g1m_mcs_t **parts;
|
||||
|
||||
/* TODO: pictures, e-activities */
|
||||
} g1m_t;
|
||||
|
@ -152,11 +160,19 @@ typedef struct {
|
|||
int g1m_open(g1m_t **handle, const char *path);
|
||||
int g1m_fopen(g1m_t **handle, FILE *stream);
|
||||
void g1m_free(g1m_t *handle);
|
||||
void g1m_free_mcsfile(g1m_mcsfile_t *handle);
|
||||
int g1m_parse_mcsfile_content(g1m_mcsfile_t **handle, FILE *stream,
|
||||
int raw_type, const char *filename, const char *dirname,
|
||||
uint_fast32_t filesize);
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Utilities */
|
||||
/* ************************************************************************** */
|
||||
/* encoding */
|
||||
/* encoding characters */
|
||||
int g1m_mbtofc(FONTCHARACTER *pfc, const char *s, size_t n);
|
||||
int g1m_fctomb(char *s, FONTCHARACTER fc);
|
||||
|
||||
/* encoding strings */
|
||||
size_t g1m_mbstofcs(FONTCHARACTER *dst, const char *src, size_t n);
|
||||
size_t g1m_fcstombs(char *dst, const FONTCHARACTER *src, size_t n);
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ enum mcs_filetype {
|
|||
|
||||
/* Now all of this is said, each part has this header: */
|
||||
|
||||
struct mcs_partheader {
|
||||
struct mcs_fileheader {
|
||||
/* the directory name (zero-padded).*/
|
||||
uint8_t dirname[8];
|
||||
|
||||
|
|
|
@ -25,14 +25,25 @@
|
|||
#define READ(TO, SZ) { \
|
||||
size_t READ_size = fread(TO, 1, SZ, stream); \
|
||||
if (READ_size < (SZ)) { \
|
||||
log_info("READING failed: read %zu/%zu bytes, %zu missing.", \
|
||||
log_error("READING failed: read %zu/%zu bytes, %zu missing.", \
|
||||
READ_size, SZ, (SZ) - READ_size); \
|
||||
return (g1m_error_eof); \
|
||||
}}
|
||||
#define GREAD(TO, SZ) { \
|
||||
size_t READ_size = fread(TO, 1, SZ, stream); \
|
||||
if (READ_size < (SZ)) { \
|
||||
log_error("READING failed: read %zu/%zu bytes, %zu missing.", \
|
||||
READ_size, SZ, (SZ) - READ_size); \
|
||||
err = g1m_error_eof; \
|
||||
goto fail; \
|
||||
}}
|
||||
/* read with EOF check, declare var before */
|
||||
#define DREAD(NAM, STRUCT) \
|
||||
struct STRUCT NAM; \
|
||||
READ(&NAM, sizeof(struct STRUCT))
|
||||
#define GDREAD(NAM, STRUCT) \
|
||||
struct STRUCT NAM; \
|
||||
GREAD(&NAM, sizeof(struct STRUCT))
|
||||
/* skip */
|
||||
#define SKIP(SZ) \
|
||||
if (g1m_parse_skip(stream, SZ, NULL)) return (g1m_error_eof);
|
||||
|
|
|
@ -28,10 +28,14 @@ const char *g1m_error_strings[] = {
|
|||
"given stream was not readable",
|
||||
[g1m_error_noseek] =
|
||||
"given stream was not seekable",
|
||||
|
||||
[g1m_error_magic] =
|
||||
"magic/control problem",
|
||||
[g1m_error_eof] =
|
||||
"unexpected EOF",
|
||||
[g1m_error_alloc] =
|
||||
"could not allocate memory",
|
||||
|
||||
[g1m_error_op] =
|
||||
"operation is unsupported for this type"
|
||||
};
|
||||
|
|
|
@ -115,7 +115,7 @@ int g1m_parse_addin_cg(g1m_t *handle, FILE *stream,
|
|||
|
||||
/* check the control */
|
||||
if (hd.control != hd.filesize - 0x7000 - 4) {
|
||||
log_info("control value is incorrect");
|
||||
log_fatal("control value is incorrect");
|
||||
return (g1m_error_magic);
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ int g1m_parse_addin_cg(g1m_t *handle, FILE *stream,
|
|||
|
||||
/* check the checksum */
|
||||
if (checksum != hd.checksum) {
|
||||
log_info("Invalid checksum.");
|
||||
log_fatal("Invalid checksum.");
|
||||
return (g1m_error_magic);
|
||||
}
|
||||
|
||||
|
|
328
src/parse/mcs.c
328
src/parse/mcs.c
|
@ -8,7 +8,11 @@
|
|||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* MCS file parsing */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_parse_mcs_program:
|
||||
* Parse a program.
|
||||
|
@ -19,7 +23,7 @@
|
|||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
static int g1m_parse_mcs_program(g1m_t *handle, FILE *stream,
|
||||
static int g1m_parse_mcs_program(g1m_mcsfile_t *handle, FILE *stream,
|
||||
uint_fast32_t length)
|
||||
{
|
||||
/* read header */
|
||||
|
@ -28,6 +32,10 @@ static int g1m_parse_mcs_program(g1m_t *handle, FILE *stream,
|
|||
/* print header data */
|
||||
log_info("Program password is '%.8s'.", hd.password);
|
||||
|
||||
/* store info */
|
||||
strncpy(handle->password, (char*)hd.password, 8);
|
||||
handle->password[8] = 0;
|
||||
|
||||
/* seek for what's left in the file */
|
||||
SKIP(length - sizeof(struct mcs_programheader))
|
||||
|
||||
|
@ -41,10 +49,12 @@ static int g1m_parse_mcs_program(g1m_t *handle, FILE *stream,
|
|||
*
|
||||
* @arg handle the handle.
|
||||
* @arg stream the stream to parse from.
|
||||
* @arg length the data length.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
static int g1m_parse_mcs_spreadsheet(g1m_t *handle, FILE *stream)
|
||||
static int g1m_parse_mcs_spreadsheet(g1m_mcsfile_t *handle, FILE *stream,
|
||||
uint_fast32_t length)
|
||||
{
|
||||
/* read header */
|
||||
DREAD(hd, mcs_spreadsheetheader)
|
||||
|
@ -61,6 +71,16 @@ static int g1m_parse_mcs_spreadsheet(g1m_t *handle, FILE *stream)
|
|||
READ(&column_directory, sizeof(uint32_t) * colcount)
|
||||
/* - we should use `be32toh` here, but it isn't necessary for bool check. */
|
||||
|
||||
/* store info */
|
||||
handle->type = g1m_mcstype_spreadsheet;
|
||||
|
||||
/* prepare */
|
||||
g1m_mcs_cell_t cells[1000 * colcount];
|
||||
bzero(cells, sizeof(g1m_mcs_cell_t) * 1000 * colcount);
|
||||
int cells_count = 0;
|
||||
uint_fast32_t rows = 0;
|
||||
uint_fast32_t cols = 0;
|
||||
|
||||
/* browse columns */
|
||||
for (uint_fast32_t c = 0; c < colcount; c++) {
|
||||
/* check if column is empty */
|
||||
|
@ -82,6 +102,18 @@ static int g1m_parse_mcs_spreadsheet(g1m_t *handle, FILE *stream)
|
|||
/* get cell */
|
||||
DREAD(cell, bcd)
|
||||
|
||||
/* store it */
|
||||
{
|
||||
g1m_mcs_cell_t *c = &cells[colcount * 1000 + i];
|
||||
c->used = 1;
|
||||
c->real = cell;
|
||||
}
|
||||
|
||||
/* check things (max row, max col, cells count) */
|
||||
if (i > rows) rows = i;
|
||||
cols = c;
|
||||
cells_count++;
|
||||
|
||||
/* log it */
|
||||
log_info("[%ld, %ld] not empty.", c, i);
|
||||
}
|
||||
|
@ -92,6 +124,31 @@ static int g1m_parse_mcs_spreadsheet(g1m_t *handle, FILE *stream)
|
|||
}
|
||||
}
|
||||
|
||||
/* we have max rows and columns, increment to have sizes */
|
||||
rows++, cols++;
|
||||
|
||||
/* create final tab */
|
||||
g1m_mcs_cell_t *tab = NULL;
|
||||
handle->columns = cols;
|
||||
handle->rows = rows;
|
||||
if (cells_count) {
|
||||
/* alloc */
|
||||
uint_fast32_t tabsize = rows * cols;
|
||||
tab = malloc(sizeof(g1m_mcs_cell_t) * tabsize);
|
||||
if (!tab) return (g1m_error_alloc);
|
||||
|
||||
/* main copying loop
|
||||
* quite tricky as we're reversing ->x->y to ->y->x. */
|
||||
for (uint_fast32_t x = 0, y = 0; tabsize--;) {
|
||||
/* FIXME: unsure about first formula */
|
||||
tab[y * rows + x] = cells[x * 1000 + y];
|
||||
y++; if (y > rows) y = 0, x++;
|
||||
}
|
||||
|
||||
/* put it into MCS file handle */
|
||||
handle->cells = tab;
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
}
|
||||
|
@ -102,11 +159,12 @@ static int g1m_parse_mcs_spreadsheet(g1m_t *handle, FILE *stream)
|
|||
*
|
||||
* @arg handle the handle.
|
||||
* @arg stream the stream to parse from.
|
||||
* @arg size the
|
||||
* @arg size the length.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
static int g1m_parse_mcs_list(g1m_t *handle, FILE *stream, uint_fast32_t size)
|
||||
static int g1m_parse_mcs_list(g1m_mcsfile_t *handle, FILE *stream,
|
||||
uint_fast32_t size)
|
||||
{
|
||||
/* read header */
|
||||
DREAD(hd, mcs_listheader)
|
||||
|
@ -131,6 +189,23 @@ static int g1m_parse_mcs_list(g1m_t *handle, FILE *stream, uint_fast32_t size)
|
|||
if (size > elsize) /* FIXME: HACK */
|
||||
READ(&imgn, elsize)
|
||||
|
||||
/* create final tab */
|
||||
g1m_mcs_cell_t *tab = NULL;
|
||||
handle->columns = 1;
|
||||
handle->rows = elcount;
|
||||
if (elcount) {
|
||||
/* alloc */
|
||||
tab = malloc(sizeof(g1m_mcs_cell_t) * elcount);
|
||||
if (!tab) return (g1m_error_alloc);
|
||||
|
||||
/* main copying loop */
|
||||
for (uint_fast32_t y = 0; y < elcount; y++) {
|
||||
tab[y].used = 1;
|
||||
tab[y].real = real[y];
|
||||
tab[y].imgn = imgn[y];
|
||||
}
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
}
|
||||
|
@ -141,10 +216,12 @@ static int g1m_parse_mcs_list(g1m_t *handle, FILE *stream, uint_fast32_t size)
|
|||
*
|
||||
* @arg handle the handle.
|
||||
* @arg stream the stream to parse from.
|
||||
* @arg length the data length.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
static int g1m_parse_mcs_mat(g1m_t *handle, FILE *stream)
|
||||
static int g1m_parse_mcs_mat(g1m_mcsfile_t *handle, FILE *stream,
|
||||
uint_fast32_t length)
|
||||
{
|
||||
/* read header */
|
||||
DREAD(hd, mcs_matheader)
|
||||
|
@ -154,17 +231,36 @@ static int g1m_parse_mcs_mat(g1m_t *handle, FILE *stream)
|
|||
hd.height = be16toh(hd.height);
|
||||
|
||||
/* log info */
|
||||
log_info("Matrix is %d/%d", hd.width, hd.height);
|
||||
uint_fast32_t w = hd.width, h = hd.height;
|
||||
log_info("Matrix is %ld/%ld", w, h);
|
||||
|
||||
/* prepare */
|
||||
size_t num = w * h;
|
||||
g1m_mcs_cell_t cells[num];
|
||||
|
||||
/* parse cells */
|
||||
size_t num = hd.width * hd.height;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
/* read the cell */
|
||||
DREAD(cell, bcd)
|
||||
|
||||
/* get x using `i % height` and y using `i / height` */
|
||||
/* store the value */
|
||||
cells[i] = (g1m_mcs_cell_t){
|
||||
.real = cell,
|
||||
.imgn = {},
|
||||
.used = 1
|
||||
};
|
||||
}
|
||||
|
||||
/* alloc real matrix */
|
||||
g1m_mcs_cell_t *tab = malloc(sizeof(g1m_mcs_cell_t) * num);
|
||||
if (!tab) return (g1m_error_alloc);
|
||||
memcpy(tab, cells, num * sizeof(g1m_mcs_cell_t));
|
||||
|
||||
/* put it in handle */
|
||||
handle->width = w;
|
||||
handle->height = h;
|
||||
handle->cells = tab;
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
}
|
||||
|
@ -175,10 +271,12 @@ static int g1m_parse_mcs_mat(g1m_t *handle, FILE *stream)
|
|||
*
|
||||
* @arg handle the handle.
|
||||
* @arg stream the stream to parse from.
|
||||
* @arg length the data length.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
static int g1m_parse_mcs_capture(g1m_t *handle, FILE *stream)
|
||||
static int g1m_parse_mcs_capture(g1m_mcsfile_t *handle, FILE *stream,
|
||||
uint_fast32_t length)
|
||||
{
|
||||
/* read header */
|
||||
DREAD(hd, mcs_captureheader)
|
||||
|
@ -190,16 +288,136 @@ static int g1m_parse_mcs_capture(g1m_t *handle, FILE *stream)
|
|||
/* print info */
|
||||
log_info("capture is %ux%u sized", hd.width, hd.height);
|
||||
|
||||
/* skip */
|
||||
SKIP(hd.height * (hd.width / 8 + !!(hd.width % 8)))
|
||||
/* get raw pixels */
|
||||
size_t linesize = hd.width / 8 + !!(hd.width % 8);
|
||||
size_t bufsize = hd.height * linesize;
|
||||
uint8_t buf[bufsize];
|
||||
READ(buf, bufsize)
|
||||
|
||||
/* alloc */
|
||||
handle->width = hd.width;
|
||||
handle->height = hd.height;
|
||||
handle->image = malloc(hd.height * (sizeof(uint32_t*))
|
||||
+ hd.width * hd.height * sizeof(uint32_t));
|
||||
if (!handle->image)
|
||||
return (g1m_error_alloc);
|
||||
|
||||
/* fill */
|
||||
uint32_t **image = handle->image;
|
||||
for (uint_fast16_t y = 0; y < hd.height; y++) {
|
||||
/* setup index */
|
||||
image[y] = (uint32_t*)&image[hd.height] + y * hd.width;
|
||||
|
||||
/* init vars for monochrome with fill bits image browsing */
|
||||
uint8_t *b = &buf[y * linesize];
|
||||
int bit = 1 << 7;
|
||||
|
||||
/* browse and save pixels! (monochrome to 0x0RGB) */
|
||||
for (uint_fast16_t x = 0; x < hd.width; x++) {
|
||||
image[y][x] = *b & bit ? 0xffffff : 0x000000;
|
||||
b += bit & 1;
|
||||
bit = (bit >> 1) | ((bit & 1) << 7);
|
||||
}
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_parse_mcs_picture:
|
||||
* Parse a picture.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg stream the stream to parse from.
|
||||
* @arg length the data length.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
static int g1m_parse_mcs_picture(g1m_mcsfile_t *handle, FILE *stream,
|
||||
uint_fast32_t length)
|
||||
{
|
||||
/* skip the two captures */
|
||||
SKIP(128 * 8 * 2);
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Public API functions */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_parse_mcsfile:
|
||||
* Parse MCS file content.
|
||||
*
|
||||
* Part of the public API because of the Protocol 7, where file is sent
|
||||
* without its header (only with specific subheaders).
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg stream the stream to parse from.
|
||||
* @arg raw_type the raw file type.
|
||||
* @arg filename the filename (up to 8 bytes are read).
|
||||
* @arg dirname the directory name (up to 8 bytes are read).
|
||||
* @arg filesize the data length.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_parse_mcsfile_content(g1m_mcsfile_t **handle, FILE *stream,
|
||||
int raw_type, const char *filename, const char *dirname,
|
||||
uint_fast32_t filesize)
|
||||
{
|
||||
/* create handle */
|
||||
handle = malloc(sizeof(g1m_mcsfile_t));
|
||||
if (!handle) return (g1m_error_alloc);
|
||||
|
||||
/* save data */
|
||||
g1m_mcsfile_t *h = *handle;
|
||||
strncmp(h->name, filename, 8);
|
||||
strncmp(h->dirname, dirname, 8);
|
||||
|
||||
/* read that much data */
|
||||
int err = 0;
|
||||
switch (raw_type) {
|
||||
case mcs_ftype_program:
|
||||
h->type = g1m_mcstype_program;
|
||||
err = g1m_parse_mcs_program(h, stream, filesize);
|
||||
break;
|
||||
case mcs_ftype_list:
|
||||
h->type = g1m_mcstype_list;
|
||||
err = g1m_parse_mcs_list(h, stream, filesize);
|
||||
break;
|
||||
case mcs_ftype_mat:
|
||||
h->type = g1m_mcstype_mat;
|
||||
err = g1m_parse_mcs_mat(h, stream, filesize);
|
||||
break;
|
||||
case mcs_ftype_spreadsheet:
|
||||
h->type = g1m_mcstype_spreadsheet;
|
||||
err = g1m_parse_mcs_spreadsheet(h, stream, filesize);
|
||||
break;
|
||||
case mcs_ftype_picture:
|
||||
h->type = g1m_mcstype_pict;
|
||||
err = g1m_parse_mcs_picture(h, stream, filesize);
|
||||
break;
|
||||
case mcs_ftype_capture:
|
||||
h->type = g1m_mcstype_capt;
|
||||
err = g1m_parse_mcs_capture(h, stream, filesize);
|
||||
break;
|
||||
default:
|
||||
SKIP(filesize)
|
||||
}
|
||||
|
||||
/* free if error, return */
|
||||
if (err) {
|
||||
free(*handle);
|
||||
*handle = NULL;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_parse_mcs:
|
||||
* We have passed the Standard Header and it's a g... MCS! Let's parse it!
|
||||
* Parse an MCS file, after the Standard Header.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg stream the stream to parse from.
|
||||
|
@ -209,68 +427,78 @@ static int g1m_parse_mcs_capture(g1m_t *handle, FILE *stream)
|
|||
|
||||
int g1m_parse_mcs(g1m_t *handle, FILE *stream, uint_fast16_t num)
|
||||
{
|
||||
log_info("%ld parts to browse", num);
|
||||
int err = g1m_error_alloc;
|
||||
|
||||
/* No "global" header for MCS parts, because this "global header"
|
||||
* was the standard header. */
|
||||
/* allocate memory for the subparts */
|
||||
/*g1m_mcs_t **subs = malloc(sizeof(g1m_mcs_t*) * num);
|
||||
for (int i = 0; i < num; i++)
|
||||
subs[i] = malloc(sizeof(g1m_mcs_t)); -- TODO */
|
||||
handle->part_count = 0;
|
||||
handle->_parts_size = num;
|
||||
handle->parts = malloc(sizeof(g1m_mcs_t*) * num);
|
||||
if (!handle->parts) return (g1m_error_alloc);
|
||||
bzero(handle->parts, sizeof(g1m_mcs_t*) * num);
|
||||
|
||||
/* read all of the parts */
|
||||
log_info("%ld parts to browse", num);
|
||||
for (uint_fast16_t i = 0; i < num; i++) {
|
||||
/* get the subheader */
|
||||
DREAD(hd, mcs_subheader)
|
||||
GDREAD(hd, mcs_subheader)
|
||||
|
||||
/* correct endianess */
|
||||
hd.subcount = be32toh(hd.subcount);
|
||||
|
||||
/* log info about part */
|
||||
log_info("[%ld] Internal name is '%.16s'", i, hd.intname);
|
||||
log_info("[%ld] %d subparts to browse", i, hd.subcount);
|
||||
|
||||
/* prepare tab */
|
||||
err = g1m_error_alloc;
|
||||
g1m_mcs_t *mcs = malloc(sizeof(g1m_mcs_t));
|
||||
if (!mcs) goto fail;
|
||||
handle->parts[i] = mcs;
|
||||
mcs->_parts_size = hd.subcount;
|
||||
mcs->parts = malloc(sizeof(g1m_mcsfile_t*) * hd.subcount);
|
||||
if (!mcs->parts) goto fail;
|
||||
bzero(mcs, sizeof(g1m_mcsfile_t*) * hd.subcount);
|
||||
|
||||
/* foreach subpart */
|
||||
uint_fast32_t subcount = hd.subcount;
|
||||
for (uint_fast32_t j = 0; j < subcount; j++) {
|
||||
log_info("[%ld] %d subparts to browse", i, hd.subcount);
|
||||
for (uint_fast32_t j = 0; j < hd.subcount; j++) {
|
||||
/* get the part header */
|
||||
DREAD(phd, mcs_partheader)
|
||||
GDREAD(fhd, mcs_fileheader)
|
||||
|
||||
/* correct endianess */
|
||||
phd.datalength = be32toh(phd.datalength);
|
||||
fhd.datalength = be32toh(fhd.datalength);
|
||||
|
||||
/* log info about the subpart */
|
||||
log_info("[%ld,%ld] directory name is '%.8s'", i, j, phd.dirname);
|
||||
log_info("[%ld,%ld] filename is '%.8s'", i, j, phd.filename);
|
||||
log_info("[%ld,%ld] directory type is '%s' (0x%02d)",
|
||||
i, j, g1m_get_mcs_ftype_string(phd.filetype), phd.filetype);
|
||||
log_info("[%ld,%ld] data length is %u", i, j, phd.datalength);
|
||||
log_info("[%ld,%ld] directory name is '%.8s'", i, j, fhd.dirname);
|
||||
log_info("[%ld,%ld] filename is '%.8s'", i, j, fhd.filename);
|
||||
log_info("[%ld,%ld] file type is '%s' (0x%02d)",
|
||||
i, j, g1m_get_mcs_ftype_string(fhd.filetype), fhd.filetype);
|
||||
log_info("[%ld,%ld] data length is %u", i, j, fhd.datalength);
|
||||
|
||||
/* and read that much data */
|
||||
int err = 0;
|
||||
switch (phd.filetype) {
|
||||
case mcs_ftype_program:
|
||||
err = g1m_parse_mcs_program(handle, stream, phd.datalength);
|
||||
break;
|
||||
case mcs_ftype_spreadsheet:
|
||||
err = g1m_parse_mcs_spreadsheet(handle, stream);
|
||||
break;
|
||||
case mcs_ftype_capture:
|
||||
err = g1m_parse_mcs_capture(handle, stream);
|
||||
break;
|
||||
case mcs_ftype_list:
|
||||
err = g1m_parse_mcs_list(handle, stream, phd.datalength);
|
||||
break;
|
||||
case mcs_ftype_mat:
|
||||
err = g1m_parse_mcs_mat(handle, stream);
|
||||
break;
|
||||
default:
|
||||
SKIP(phd.datalength)
|
||||
}
|
||||
|
||||
/* if there is an error, return it */
|
||||
/* decode */
|
||||
int err = g1m_parse_mcsfile_content(&mcs->parts[j], stream,
|
||||
fhd.filetype, (char*)fhd.filename, (char*)fhd.dirname,
|
||||
fhd.datalength);
|
||||
if (err) return (err);
|
||||
}
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
|
||||
/* was error! */
|
||||
fail:;
|
||||
g1m_mcs_t **parts = handle->parts;
|
||||
int part_count = handle->part_count;
|
||||
for (int i = 0; parts[i] && i < part_count; i++) {
|
||||
g1m_mcsfile_t **mcs = parts[i]->parts;
|
||||
int mcs_parts = parts[i]->parts_count;
|
||||
for (int j = 0; mcs[j] && j < mcs_parts; j++)
|
||||
g1m_free_mcsfile(mcs[j]);
|
||||
free(mcs);
|
||||
free(parts[i]);
|
||||
}
|
||||
free(parts);
|
||||
return (err);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include <stdio_ext.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Open operations (parsing has its own module) */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_open:
|
||||
* Open handle using path.
|
||||
|
@ -68,18 +71,60 @@ int g1m_fopen(g1m_t **handle, FILE *stream)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Free the data */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_free_mcsfile:
|
||||
* Free an MCS file handle.
|
||||
*
|
||||
* @arg handle the handle to free.
|
||||
*/
|
||||
|
||||
void g1m_free_mcsfile(g1m_mcsfile_t *handle)
|
||||
{
|
||||
/* free cells */
|
||||
if (handle->type & (g1m_mcstype_mat | g1m_mcstype_list
|
||||
| g1m_mcstype_spreadsheet))
|
||||
free(handle->cells);
|
||||
/* free the first image */
|
||||
if (handle->type & (g1m_mcstype_pict | g1m_mcstype_capt))
|
||||
free(handle->image);
|
||||
/* free the second image */
|
||||
if (handle->type & g1m_mcstype_pict)
|
||||
free(handle->second_image);
|
||||
/* free the handle */
|
||||
free(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_free:
|
||||
* Free handle data.
|
||||
*
|
||||
* @arg handle the handle to close.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
void g1m_free(g1m_t *handle)
|
||||
{
|
||||
if (!handle) return ;
|
||||
|
||||
/* mcs time! */
|
||||
if (handle->type & g1m_type_mcs) {
|
||||
g1m_mcs_t **mcs = handle->parts;
|
||||
int mcs_count = handle->part_count;
|
||||
for (int i = 0; i < mcs_count; i++) {
|
||||
if (!mcs[i])
|
||||
continue ;
|
||||
g1m_mcsfile_t **files = mcs[i]->parts;
|
||||
int file_count = mcs[i]->parts_count;
|
||||
for (int j = 0; j < file_count; j++) {
|
||||
if (!files[j])
|
||||
continue ;
|
||||
g1m_free_mcsfile(files[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free the handle */
|
||||
free(handle);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,81 @@
|
|||
/* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Single character conversion */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_mbtofc:
|
||||
* Multi-byte to FONTCHARACTER.
|
||||
*
|
||||
* Based on what is said in the fx-9860G SDK.
|
||||
* Let's hope it stays true.
|
||||
*
|
||||
* Based on how `mbtowc` works.
|
||||
*
|
||||
* @arg pfc pointer to the FONTCHARACTER character.
|
||||
* @arg s the multi-byte source string.
|
||||
* @arg n the size of the source buffer.
|
||||
* @return the number of bytes used (-1 if error).
|
||||
*/
|
||||
|
||||
int g1m_mbtofc(FONTCHARACTER *pfc, const char *s, size_t n)
|
||||
{
|
||||
/* null string? */
|
||||
if (!s)
|
||||
return (2);
|
||||
|
||||
/* no space? */
|
||||
if (!n)
|
||||
return (-1);
|
||||
|
||||
/* extended char? */
|
||||
if (strchr("\x7F\xF7\xF9\xE5\x56\x57", *s))
|
||||
{
|
||||
if (n < 2) return (-1);
|
||||
*pfc = (*s << 8) + *(s + 1);
|
||||
return (2);
|
||||
}
|
||||
|
||||
/* single-byte character */
|
||||
*pfc = *s;
|
||||
return (*s != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_fctomb:
|
||||
* FONTCHARACTER to multi-byte.
|
||||
*
|
||||
* Based on the same document, and on how `wctomb` works.
|
||||
*
|
||||
* Do you think a battery has self-consciousness?
|
||||
*
|
||||
* @arg s pointer to the multi-byte string.
|
||||
* @arg fc the FONTCHARACTER character.
|
||||
* @return the
|
||||
*/
|
||||
|
||||
int g1m_fctomb(char *s, FONTCHARACTER fc)
|
||||
{
|
||||
/* no string? */
|
||||
if (!s)
|
||||
return (2);
|
||||
|
||||
/* extended? */
|
||||
if (fc > 0xff) {
|
||||
*s++ = fc >> 8;
|
||||
*s = fc & 0xff;
|
||||
return (2);
|
||||
}
|
||||
|
||||
/* normal char. */
|
||||
*s = fc;
|
||||
return (fc != 0);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* String conversion */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_mbstofcs:
|
||||
* Multi-byte string to FONTCHARACTER string.
|
||||
|
@ -24,8 +99,20 @@
|
|||
|
||||
size_t g1m_mbstofcs(FONTCHARACTER *dest, const char *src, size_t n)
|
||||
{
|
||||
/* TODO */
|
||||
return (0);
|
||||
size_t len = 0;
|
||||
while (n) {
|
||||
FONTCHARACTER fc;
|
||||
int count = g1m_mbtofc(&fc, src, n);
|
||||
if (count < 0)
|
||||
return (-1);
|
||||
if (dest)
|
||||
*dest++ = fc;
|
||||
if (!count)
|
||||
break;
|
||||
len++;
|
||||
n -= count;
|
||||
}
|
||||
return (len);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,14 +122,26 @@ size_t g1m_mbstofcs(FONTCHARACTER *dest, const char *src, size_t n)
|
|||
* This function imitates `wcstombs` (unicode), but for CASIO's encoding.
|
||||
* You should be able to use it the same way.
|
||||
*
|
||||
* @arg dest the destination.
|
||||
* @arg dst the destination.
|
||||
* @arg src the source.
|
||||
* @arg n number of FONTCHARACTER elements in the source.
|
||||
* @return the size of the destination.
|
||||
*/
|
||||
|
||||
size_t g1m_fcstombs(char *src, const FONTCHARACTER *dest, size_t n)
|
||||
size_t g1m_fcstombs(char *dst, const FONTCHARACTER *src, size_t n)
|
||||
{
|
||||
/* TODO */
|
||||
return (0);
|
||||
size_t len = 0;
|
||||
while (n) {
|
||||
char buf[2];
|
||||
int count = g1m_fctomb(buf, *src);
|
||||
if ((size_t)count > n)
|
||||
break;
|
||||
memcpy(dst, buf, count);
|
||||
dst += count;
|
||||
n -= count;
|
||||
if (!*src++)
|
||||
break;
|
||||
len += count;
|
||||
}
|
||||
return (len);
|
||||
}
|
||||
|
|
Reference in New Issue