cake
/
libg1m
Archived
1
0
Fork 0
This commit is contained in:
Thomas Touhey 2016-11-19 02:47:36 +01:00
parent 885bcff337
commit d96e450afb
9 changed files with 481 additions and 78 deletions

View File

@ -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);

View File

@ -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];

View File

@ -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);

View File

@ -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"
};

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}