197 lines
5.9 KiB
C
197 lines
5.9 KiB
C
/* *****************************************************************************
|
|
* decode/mcs.c -- decode an MCS file.
|
|
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
|
*
|
|
* This file is part of libg1m.
|
|
* libg1m is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 3.0 of the License,
|
|
* or (at your option) any later version.
|
|
*
|
|
* libg1m is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
|
|
* ************************************************************************** */
|
|
#include <libg1m/internals.h>
|
|
#include <stdlib.h>
|
|
#define FUNC(NAME) g1m_decode_mcs_##NAME
|
|
|
|
/* ************************************************************************** */
|
|
/* Type correspondance list */
|
|
/* ************************************************************************** */
|
|
/* MCS file parsing function type */
|
|
typedef int (*mcs_decode_func_t)(g1m_mcsfile_t**, g1m_buffer_t*,
|
|
g1m_mcshead_t*);
|
|
|
|
/* Correspondance type */
|
|
struct mcs_corresp {
|
|
unsigned int type;
|
|
mcs_decode_func_t decode;
|
|
};
|
|
|
|
/* All correspondances */
|
|
#define TTERM {0, NULL}
|
|
static struct mcs_corresp mcs_types[] = {
|
|
{g1m_mcstype_program, FUNC(program)},
|
|
{g1m_mcstype_list, FUNC(cells)},
|
|
{g1m_mcstype_mat, FUNC(cells)},
|
|
{g1m_mcstype_vct, FUNC(cells)},
|
|
{g1m_mcstype_spreadsheet, FUNC(spreadsheet)},
|
|
{g1m_mcstype_pict, FUNC(picture)},
|
|
{g1m_mcstype_capt, FUNC(capture)},
|
|
{g1m_mcstype_string, FUNC(string)},
|
|
{g1m_mcstype_setup, FUNC(setup)},
|
|
{g1m_mcstype_alphamem, FUNC(var)},
|
|
{g1m_mcstype_variable, FUNC(var)},
|
|
TTERM
|
|
};
|
|
|
|
/**
|
|
* lookup_mcsfile_decode:
|
|
* Lookup for a parsing function for an MCS file type.
|
|
*
|
|
* @arg type the libg1m MCS file type.
|
|
* @return the function (NULL if not found).
|
|
*/
|
|
|
|
static mcs_decode_func_t lookup_mcsfile_decode(g1m_mcstype_t type)
|
|
{
|
|
/* lookup for the type */
|
|
struct mcs_corresp *c = mcs_types;
|
|
while (c->decode) {
|
|
if (type == c->type)
|
|
break;
|
|
c++;
|
|
}
|
|
|
|
/* return the function */
|
|
return (c->decode);
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* Head decoding function */
|
|
/* ************************************************************************** */
|
|
/**
|
|
* g1m_decode_mcsfile_head:
|
|
* Decode MCS file head.
|
|
*
|
|
* @arg head the head to fill.
|
|
* @arg raw_type the raw file type.
|
|
* @arg groupname the groupname (up to 16 bytes).
|
|
* @arg dirname the directory name (up to 8 bytes).
|
|
* @arg filename the filename (up to 8 bytes).
|
|
* @arg filesize the data length.
|
|
* @return 0 if the head was filled with success, -1 otherwise.
|
|
*/
|
|
|
|
int g1m_decode_mcsfile_head(g1m_mcshead_t *head,
|
|
int raw_type, const unsigned char *groupname,
|
|
const unsigned char *dirname, const unsigned char *filename,
|
|
uint_fast32_t filesize)
|
|
{
|
|
/* check that we have a head, lol */
|
|
if (!head) return (-1);
|
|
|
|
/* look for the raw type */
|
|
g1m_maketype_mcs(head, (char*)groupname, (char*)dirname,
|
|
(char*)filename, raw_type);
|
|
head->g1m_mcshead_size = filesize;
|
|
log_info("libg1m file type is 0x%08" PRIXMCSTYPE, head->g1m_mcshead_type);
|
|
#if LOGLEVEL <= ll_info
|
|
if (g1m_mcshead_uses_id(head)) {
|
|
log_info("libg1m file id is (%d, %d)",
|
|
g1m_get_id_major(head->g1m_mcshead_id),
|
|
g1m_get_id_minor(head->g1m_mcshead_id));
|
|
}
|
|
#endif
|
|
|
|
/* everything went well! */
|
|
return (0);
|
|
}
|
|
/* ************************************************************************** */
|
|
/* File decoding functions */
|
|
/* ************************************************************************** */
|
|
/**
|
|
* g1m_decode_mcsfile:
|
|
* Decode 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 to make.
|
|
* @arg head the head to use.
|
|
* @arg buffer the buffer to read from.
|
|
* @return the error code (0 if ok).
|
|
*/
|
|
|
|
int g1m_decode_mcsfile(g1m_mcsfile_t **handle, const g1m_mcshead_t *head,
|
|
g1m_buffer_t *buffer)
|
|
{
|
|
int err = 0;
|
|
|
|
/* check that the head is there */
|
|
if (!head) return (g1m_error_op);
|
|
g1m_mcshead_t h = *head;
|
|
|
|
/* look for the decoding function */
|
|
mcs_decode_func_t decode = lookup_mcsfile_decode(head->g1m_mcshead_type);
|
|
if (!decode) {
|
|
log_error("No dedicated decoding function for this type was found!");
|
|
goto notparsing;
|
|
}
|
|
|
|
/* decode */
|
|
if (!head->g1m_mcshead_size) err = (*decode)(handle, buffer, &h);
|
|
else {
|
|
g1m_buffer_t lbuf = LIMBUFFER(buffer, head->g1m_mcshead_size);
|
|
err = (*decode)(handle, &lbuf, &h);
|
|
if (lbuf.g1m_buffer_offset < head->g1m_mcshead_size)
|
|
SKIP(head->g1m_mcshead_size - lbuf.g1m_buffer_offset)
|
|
}
|
|
|
|
/* oh yeah, and go away. */
|
|
if (err) goto fail;
|
|
return (0);
|
|
|
|
notparsing:
|
|
/* allocate enough space */
|
|
if ((err = g1m_make_mcsfile(handle, &h)))
|
|
return (err);
|
|
|
|
/* read the content */
|
|
GREAD((*handle)->g1m_mcsfile_content, h.g1m_mcshead_size)
|
|
|
|
/* log */
|
|
log_info("File content:");
|
|
logm_info((*handle)->g1m_mcsfile_content, h.g1m_mcshead_size);
|
|
|
|
/* saved normally */
|
|
return (0);
|
|
|
|
fail:
|
|
g1m_free_mcsfile(*handle);
|
|
return (err);
|
|
}
|
|
|
|
/**
|
|
* g1m_decode_mcsfile_data:
|
|
* Decode a MCS file content from raw memory.
|
|
*
|
|
* @arg handle the file handle.
|
|
* @arg head the file head.
|
|
* @arg data the buffer data.
|
|
* @arg size the buffer size.
|
|
* @return the libg1m error.
|
|
*/
|
|
|
|
int g1m_decode_mcsfile_data(g1m_mcsfile_t **handle,
|
|
const g1m_mcshead_t *head, const unsigned char *data, size_t size)
|
|
{
|
|
g1m_buffer_t membuf = MEMBUFFER(data, size);
|
|
return (g1m_decode_mcsfile(handle, head, &membuf));
|
|
}
|