/* ***************************************************************************** * decode/mcs.c -- decode an MCS file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * 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 . * ************************************************************************** */ #include #include #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)); }