diff --git a/Makefile b/Makefile index ada33e0..956609a 100755 --- a/Makefile +++ b/Makefile @@ -94,23 +94,23 @@ dist: mrproper all-lib: $(CHECKCFG) $(if $(STATIC),$(ANAME),$(SONAME)) # Make a module object directory. - $(MODULES:%=$(OBJDIR)/%): + $(OBJDIR)/ $(DIRS:%=$(OBJDIR)/%): $(call bcmd,mkdir,$@,$(MD) $@) -# Make a module object out of a module source file. -define make-moduleobj-rule - $(OBJDIR)/$1/%.o: $(SRCDIR)/$1/%.c $(INC) | $(OBJDIR)/$1 +# Make an object out of a source file. +define make-obj-rule + $(OBJDIR)/$1.o: $(SRCDIR)/$1.c $(INC) | $(dir $(OBJDIR)/$1) $(call bcmd,cc,$$@,$(CC) -c -o $$@ $$< $(CFLAGS)) endef -$(foreach mod,$(MODULES), \ -$(eval $(call make-moduleobj-rule,$(mod)))) +$(foreach src,$(SRC),\ +$(eval $(call make-obj-rule,$(src)))) # Make the shared library. - $(SONAME): $(foreach m,$(MODULES),$(SRC_$(m):%=$(OBJDIR)/$(m)/%.o)) + $(SONAME): $(SRC:%=$(OBJDIR)/%.o) $(call bcmd,ld,$@,$(LD) -o $@ $^ $(LDFLAGS)) # Make the static library. - lib$(NAME).a: $(foreach m,$(MODULES),$(SRC_$(m):%=$(OBJDIR)/$(m)/%.o)) + lib$(NAME).a: $(SRC:%=$(OBJDIR)/%.o) $(call bcmd,ar rc,$@,$(AR) rcs $@ $^) # Remove the objects directory. @@ -138,7 +138,7 @@ $(eval $(call make-moduleobj-rule,$(mod)))) $(if $(FOR_WINDOWS),lib$(NAME).dll.a,$(SONAME)))) $(if $(IWINDLL),$(call qcmd,$(INST) -m 755 -d "$(IBINDIR)")) - $(if $(IWINDLL),$(call qcmd,$(INST) -m 644 -t "$(IBINDIR)" \ + $(if $(IWINDLL),$(call qcmd,$(INST) -m 755 -t "$(IBINDIR)" \ lib$(NAME).dll)) $(if $(LINK_TO_MAJOR),\ @@ -166,8 +166,11 @@ $(eval $(call make-moduleobj-rule,$(mod)))) $(call qcmd,$(RM) "$(IINCDIR)/lib$(NAME).h") $(call qcmd,$(RM) -r "$(IINCDIR)/lib$(NAME)") +# Reinstall the library and development files. + reinstall-lib: uninstall-lib install-lib + .PHONY: all-lib mostlyclean-lib mclean-lib clean-lib re-lib -.PHONY: install-lib uninstall-lib +.PHONY: install-lib uninstall-lib reinstall-lib #******************************************************************************# # Configuration tools-related # #******************************************************************************# diff --git a/Makefile.vars b/Makefile.vars index 2b0afca..a36a55e 100755 --- a/Makefile.vars +++ b/Makefile.vars @@ -122,28 +122,18 @@ endif GZIP := gzip -f #******************************************************************************# -# Look for modules and modules sources # +# Look up the sources and includes # #******************************************************************************# -# Look for modules first - MODULES := $(notdir $(shell find $(SRCDIR) -mindepth 1 -maxdepth 1 \ - -type d | sort)) +# Look up the sources + SRC := $(basename $(shell find $(SRCDIR) -mindepth 1 -type f \ + -name "*.c" -printf "%P\n")) + DIRS := $(sort $(dir $(SRC))) -# Then look for their content -define get-module-source -SRC_$1 := $(basename $(shell find $(SRCDIR)/$1 \ - -maxdepth 1 -mindepth 1 -type f -name "*.[cs]" -printf "%P\n" | sort)) -endef -$(foreach mod,$(MODULES), \ -$(eval $(call get-module-source,$(mod)))) +# Look up the includes + INCPUB := $(shell find $(INCDIR) -name "*.h" -and \ + -not -path "*internals*" -printf "%P\n") -#******************************************************************************# -# Look for headers # -#******************************************************************************# -# Public headers only (not internals.h or internals/**/*.h) - INCPUB := $(shell find $(INCDIR) \ - -name "*.h" -and -not -path "*internals*" -printf "%P\n" | sort) - -# ... and for headers (dependencies) +# Look up the includes INC := $(shell find $(INCDIR) -name "*.h") #******************************************************************************# diff --git a/include/libg1m/bcd.h b/include/libg1m/bcd.h index 17f8f0a..c555442 100644 --- a/include/libg1m/bcd.h +++ b/include/libg1m/bcd.h @@ -17,20 +17,10 @@ * along with libg1m; if not, see . * * BCD are the main number format CASIO uses in its calculators. - * Each semi-byte is a digit going from 0 to 9 (0xA to 0xF aren't used). * This format has the huge advantage to make 0.1 + 0.2 and 0.3 equal. * - * The first three digits are the exponent. - * If the exponent is more than 500, then remove 500, and that means the - * number is negative. - * Then you have to remove 100 to have the real exponent. - * - * Before applying these operations, you should check the most significant bit - * of the upper nibble of the first binary-coded digit of the exponent. - * If it is 1, then the number has a complex part. Anyway, always set this - * bit to zero before interpreting the exponent. - * - * The other 15 digits are the mantissa. So the number is: (M ** (E + 1)) + * There are several raw BCD formats, libg1m offers conversion to its own + * format, easier to read and write (but not optimized for storing). * ************************************************************************** */ #ifndef LIBG1M_BCD_H # define LIBG1M_BCD_H diff --git a/include/libg1m/buffer.h b/include/libg1m/buffer.h index b296a01..c6c5e91 100644 --- a/include/libg1m/buffer.h +++ b/include/libg1m/buffer.h @@ -41,6 +41,7 @@ typedef int (*g1m_buffer_announce_t)(void*, uint_fast32_t size); /* ... and the structure of a buffer. */ typedef struct { void *cookie; + size_t _offset; g1m_buffer_read_t read; g1m_buffer_write_t write; diff --git a/include/libg1m/format.h b/include/libg1m/format.h index a22a1e9..52b247c 100644 --- a/include/libg1m/format.h +++ b/include/libg1m/format.h @@ -19,7 +19,6 @@ #ifndef LIBG1M_FORMAT_H # define LIBG1M_FORMAT_H # include -# pragma pack(1) /* Welcome on this new episode of the Monster Circus show! Today we'll present * to you the different formats surrounding CASIO calculators: open or closed, @@ -52,7 +51,7 @@ /* Followed by loads of zero, then, the content. The description of the rest * of the format is described in this header: */ -# include +//# include /* ************************************************************************** */ /* The G1M format */ /* ************************************************************************** */ @@ -77,6 +76,8 @@ * The LSB is the Least Significant Byte: once adapted to the host endianness, * it can simply be obtained by bitwise-AND-ing with 0xff. */ +# pragma pack(1) + struct standard_header { /* the file identifier */ uint8_t main_id[8]; diff --git a/include/libg1m/format/fxi.h.draft b/include/libg1m/format/fxi.h.draft new file mode 100644 index 0000000..330c901 --- /dev/null +++ b/include/libg1m/format/fxi.h.draft @@ -0,0 +1,92 @@ +/* ***************************************************************************** + * libg1m/format/fxi.h -- the FXI file format description. + * 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 . + * ************************************************************************** */ +#ifndef LIBG1M_FORMAT_FXI_H +# define LIBG1M_FORMAT_FXI_H +# include +# include +# pragma pack(1) + +/* FXI is obfuscated with a symetrical obfuscation algorithm: + * byte = byte ^ ~24; + * + * Once the format is deobfuscated, this is the header structure: */ + +struct fxi_header { + /* unknown - probably part of the magic? "\xD5\xD7\x1F" "f" */ + uint8_t _unknown[4]; + + /* description: the description of the format (probably part of the + * magic too): "FX-INTERFACE - YELLOW COMPUTING" */ + char description[31]; + uint8_t _unused[40]; + + /* the number of meta entries */ + uint8_t num; + uint8_t _unused2[80]; + + /* sum of the number of meta entries and records */ + uint16_t sum; + uint8_t _unused3; + + /* 0xFF, 0xFF, 0, 0, 0x0F, 0 */ + uint8_t _blackmagic[6]; + + /* board type? CY */ + uint8_t board[2]; + + /* introduction? */ + uint8_t type[11]; +}; + +/* Then come the meta-entries, which have this structure: */ + +struct fxi_entry { + /* entry type: first type is 'NP', then {0x01, 0x80}. */ + uint8_t type[2]; + uint8_t _unused[2]; + + /* entry number */ + uint8_t number; + uint8_t _unused2[3]; + + /* unknown: either 0x00, 0x01, 0x02 */ + uint8_t _unknown; + uint8_t _unused3; + + /* unknown: either 0x00, 0x02, 0x03 */ + uint8_t _unknown2; + uint8_t _unused4; + + /* unknown: checksum? */ + uint16_t checksum; + uint8_t _unused5[2]; + + /* unknown: some sort of type? */ + uint8_t typeid; + uint8_t _unused6; + + /* size of the file name */ + uint8_t filename_size; + + + /* TODO: finish me */ +}; + +# pragma pack() +#endif diff --git a/include/libg1m/internals.h b/include/libg1m/internals.h index 8cb6ed7..5aa610c 100644 --- a/include/libg1m/internals.h +++ b/include/libg1m/internals.h @@ -25,6 +25,7 @@ # include # include # include +# include # include # include @@ -53,52 +54,122 @@ /* ************************************************************************** */ /* Macros and functions for parsing */ /* ************************************************************************** */ -/* read with EOF check */ -#define READ(TO, SZ) { \ +/* read from buffer */ +# define READ(TO, SZ) /* normal read */ { \ int READ_err = (*buffer->read)(buffer->cookie, (void*)(TO), (SZ)); \ + buffer->_offset += SZ; \ if (READ_err) return (READ_err); } -#define GREAD(TO, SZ) { \ +# define FREAD(TO, SZ) /* fail-less read */ \ + err = (*buffer->read)(buffer->cookie, (void*)(TO), (SZ)); \ + buffer->_offset += SZ; +# define GREAD(TO, SZ) /* read with goto fail */ { \ if ((err = (*buffer->read)(buffer->cookie, (void*)(TO), (SZ)))) \ - goto fail; } -/* read with EOF check, declare var before */ -#define DREAD(NAM, STRUCT) \ + goto fail; \ + buffer->_offset += SZ; } + +/* read from buffer, declare var before */ +# define DREAD(NAM, STRUCT) /* D read (I don't remember where D comes from) */ \ struct STRUCT NAM; \ READ(&NAM, sizeof(struct STRUCT)) -#define GDREAD(NAM, STRUCT) \ +# define GDREAD(NAM, STRUCT) /* D read with goto fail */ \ struct STRUCT NAM; \ GREAD(&NAM, sizeof(struct STRUCT)) + +/* read from buffer, declare tab before */ +# define TREAD(NAM, TYPE, NUM) /* Tableau (list) read */ \ + TYPE NAM[NUM]; \ + READ(NAM, sizeof(TYPE)) + /* skip */ -#define SKIP(SZ) { \ +# define SKIP(SZ) { \ int SKIP_err = g1m_skip(buffer, SZ, NULL); \ if (SKIP_err) return (SKIP_err); \ } /* ************************************************************************** */ -/* Specific decoding functions */ +/* Memory buffer-related */ /* ************************************************************************** */ -typedef int (g1m_decode_function)(g1m_t*, g1m_buffer_t*, - struct standard_header*); +/* Structure */ +typedef struct { + const unsigned char *p; + size_t left; +} g1m_cursor_t; -/* types */ -g1m_decode_function g1m_decode_g3p; -g1m_decode_function g1m_decode_c2p; -g1m_decode_function g1m_decode_mcs; -g1m_decode_function g1m_decode_eact; -g1m_decode_function g1m_decode_addin; -g1m_decode_function g1m_decode_addin_cg; -g1m_decode_function g1m_decode_lang; -g1m_decode_function g1m_decode_lang_cg; -g1m_decode_function g1m_decode_fkey; -g1m_decode_function g1m_decode_storage; +/* Callbacks */ +int g1m_membuffer_read(void *cookie, unsigned char *dest, size_t size); -/* independant functions */ +/* Management functions */ +int g1m_empty_limbuffer(g1m_buffer_t *limbuffer); + +/* Initialize a memory buffer */ +# define MEMBUFFER(P, SZ) (g1m_buffer_t){ \ + .cookie = (g1m_cursor_t[]){{.p = (P), .left = (SZ)}}, \ + .read = g1m_membuffer_read} + +/* ************************************************************************** */ +/* Limited buffer */ +/* ************************************************************************** */ +/* Structure */ +typedef struct { + g1m_buffer_t *buffer; + size_t left; +} g1m_limited_t; + +/* Callbacks */ +int g1m_limbuffer_read(void *cookie, unsigned char *dest, size_t size); + +/* Initialize a limited buffer */ +# define LIMBUFFER(BUFFER, SZ) (g1m_buffer_t){ \ + .cookie = (g1m_limited_t[]){{.buffer = (BUFFER), .left = (SZ)}}, \ + .read = g1m_limbuffer_read} + +/* ************************************************************************** */ +/* Decoding functions */ +/* ************************************************************************** */ +int g1m_decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer, + struct standard_header*, g1m_type_t expected_types); int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer, g1m_type_t expected_types); +/* ************************************************************************** */ +/* "Std"-specific decoding functions */ +/* ************************************************************************** */ +# define G1M_STDFUNC(NAME) \ +int g1m_decode_std_##NAME(g1m_t *handle, g1m_buffer_t *buffer, \ + struct standard_header *std); + +G1M_STDFUNC(g3p) +G1M_STDFUNC(c2p) +G1M_STDFUNC(mcs) +G1M_STDFUNC(eact) +G1M_STDFUNC(addin) +G1M_STDFUNC(addin_cg) +G1M_STDFUNC(lang) +G1M_STDFUNC(lang_cg) +G1M_STDFUNC(fkey) +G1M_STDFUNC(storage) + /* others */ int g1m_decode_fkey_cg_content(g1m_t *handle, g1m_buffer_t *buffer, uint_fast32_t zonesize, uint32_t *pchecksum); +/* ************************************************************************** */ +/* MCS-specific decoding functions */ +/* ************************************************************************** */ +# define G1M_MCSFUNC(NAME) \ +int g1m_decode_mcs_##NAME(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, \ + uint_fast32_t length); + +G1M_MCSFUNC(alphamem) +G1M_MCSFUNC(list) +G1M_MCSFUNC(matrix) +G1M_MCSFUNC(picture) +G1M_MCSFUNC(capture) +G1M_MCSFUNC(program) +G1M_MCSFUNC(setup) +G1M_MCSFUNC(spreadsheet) +G1M_MCSFUNC(string) + /* ************************************************************************** */ /* Picture utilities */ /* ************************************************************************** */ @@ -144,7 +215,4 @@ uint32_t g1m_checksum32(void *mem, size_t size, uint32_t checksum); /* File buffer */ int g1m_filebuffer_read(void *vcookie, unsigned char *buf, size_t size); -/* Callbacks */ -int g1m_membuffer_read(void *cookie, unsigned char *dest, size_t size); - #endif /* LIBG1M_INTERNALS_H */ diff --git a/include/libg1m/mcs.h b/include/libg1m/mcs.h index 9ffbd0e..23436cc 100644 --- a/include/libg1m/mcs.h +++ b/include/libg1m/mcs.h @@ -50,7 +50,8 @@ typedef unsigned int g1m_mcstype_t; /* Macros to check if the type uses the ID, and to interact with it */ # define g1m_mcstype_uses_id(T) ((T) & (\ g1m_mcstype_list | g1m_mcstype_mat | g1m_mcstype_vct | \ - g1m_mcstype_pict | g1m_mcstype_capt | g1m_mcstype_string)) + g1m_mcstype_pict | g1m_mcstype_capt | g1m_mcstype_string | \ + g1m_mcstype_variable)) # define g1m_get_id_major(I) ((I) >> 5) # define g1m_get_id_minor(I) ((I) & 31) @@ -103,6 +104,7 @@ typedef struct g1m_mcsfile_s { g1m_mcs_cell_t **cells; /* variables */ + int count; g1m_mcs_cell_t *vars; /* for pictures and captures */ diff --git a/src/core/decode.c b/src/core/decode.c new file mode 100644 index 0000000..b9d5346 --- /dev/null +++ b/src/core/decode.c @@ -0,0 +1,51 @@ +/* ***************************************************************************** + * core/decode.c -- decode a 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 + +/** + * g1m_decode: + * Decode a file. + * + * Read the standard header, correct endianness, check magic numbers, + * then read subparts according to the G1M type. + * + * @arg handle the handle. + * @arg path the file path. + * @arg buffer the buffer to read from. + * @arg expected_types the expected types. + * @return the error code (0 if ok). + */ + +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)); + + /* identify a CAS file */ + unsigned char buf[0x20]; READ(buf, 1) + if (buf[0] == ':') + return (g1m_decode_cas(handle, buffer, expected_types)); + + /* identify a standard header (send a _copy_) */ + READ(&buf[1], 0x1F) + uint8_t altbuf[0x20]; memcpy(altbuf, buf, 0x20); + return (g1m_decode_std(handle, path, buffer, + (struct standard_header*)altbuf, expected_types)); +} diff --git a/src/decode/cafix.c b/src/decode/cafix.c.draft similarity index 100% rename from src/decode/cafix.c rename to src/decode/cafix.c.draft diff --git a/src/decode/cas.c b/src/decode/cas.c index e345bf0..f58ec45 100644 --- a/src/decode/cas.c +++ b/src/decode/cas.c @@ -61,6 +61,8 @@ int g1m_decode_casfile_head(g1m_mcshead_t *head, const char *datatype, return (0); } +/* TODO: g1m_decode_casfile */ + /* ************************************************************************** */ /* File decoding function */ /* ************************************************************************** */ diff --git a/src/decode/casemul.c b/src/decode/casemul.c.draft similarity index 100% rename from src/decode/casemul.c rename to src/decode/casemul.c.draft diff --git a/src/decode/cat.c b/src/decode/cat.c.draft similarity index 100% rename from src/decode/cat.c rename to src/decode/cat.c.draft diff --git a/src/decode/fxi.c.draft b/src/decode/fxi.c.draft index f8cc592..f748718 100644 --- a/src/decode/fxi.c.draft +++ b/src/decode/fxi.c.draft @@ -56,9 +56,9 @@ static void obf(unsigned char *s, size_t n) /* File header */ /* ************************************************************************** */ static unsigned char header = - "\xD5\xD7\x1F" "f" "FX-INTERFACE - YELLOW COMPUTING" + "\xD5\xD7\x1F" "f" "FX-INTERFACE - YELLOW COMPUTING" /* 35 */ - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" /* 20 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\x06" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" @@ -121,7 +121,7 @@ static unsigned char header = "\x01" /* number of records? */ "\x00" "\x01\x80\0\0" "\x00" "\0\0\0" "\x02\0" "\x01\0" - "\xBA\x1E" "\0\0\x22" "\0" "\x08" /* >program name size */ + "\xBA\x1E" "\0\0\x22" "\0\x08" /* >program name size */ "SpeedSnk" "\x83\x80" "\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0" "SpeedSnk" diff --git a/src/decode/mcs.c b/src/decode/mcs.c deleted file mode 100644 index 46154a9..0000000 --- a/src/decode/mcs.c +++ /dev/null @@ -1,812 +0,0 @@ -/* ***************************************************************************** - * decode/mcs.c -- decode an MCS archive 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 - -/* ************************************************************************** */ -/* Internal functions */ -/* ************************************************************************** */ -/** - * get_image: - * Allocate space, and convert monochromic image to 0x0RGB. - * - * @arg buffer the buffer to read from. - * @arg img the image to make. - * @arg width the image width. - * @arg height the image height. - */ - -static int get_image(g1m_buffer_t *buffer, uint32_t ***img, - unsigned int width, unsigned int height) -{ - /* get raw pixels */ - size_t linesize = width / 8 + !!(width % 8); - size_t bufsize = height * linesize; - uint8_t buf[bufsize]; - READ(buf, bufsize) - - /* alloc */ - *img = malloc(height * (sizeof(uint32_t*)) - + width * height * sizeof(uint32_t)); - if (!*img) - return (g1m_error_alloc); - - /* fill */ - uint32_t **image = *img; - for (uint_fast16_t y = 0; y < height; y++) { - /* setup index */ - image[y] = (uint32_t*)&image[height] + y * 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 < width; x++) { - /* set pixel */ - image[y][x] = *b & bit ? 0xffffff : 0x000000; - - /* go further */ - b += bit & 1; - bit = (bit >> 1) | ((bit & 1) << 7); - } - } - - /* no error */ - return (0); -} - -/* ************************************************************************** */ -/* MCS file parsing */ -/* ************************************************************************** */ -/** - * mcs_decode_program: - * Decode a program. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg length the data length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_program(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t length) -{ - /* read header */ - DREAD(hd, mcs_programheader) - - /* print header data */ - log_info("Program password is '%.8s'.", hd.password); - - /* store info */ - strncpy(handle->password, (char*)hd.password, 8); - handle->password[8] = 0; - - /* get content */ - size_t content_size = length - sizeof(struct mcs_programheader); - log_info("Getting program content (%" PRIuSIZE "o)", content_size); - handle->content = malloc(content_size + 1); - handle->head.size = content_size + 1; - if (!handle->content) return (g1m_error_alloc); - READ(handle->content, content_size); - handle->content[content_size] = 0; - - /* no error */ - return (0); -} - -/** - * mcs_decode_spreadsheet: - * Decode a spreadsheet. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg length the data length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_spreadsheet(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t length) -{ - /* read header */ - DREAD(hd, mcs_spreadsheetheader) - - /* check if the spreadsheet type is known */ - if (hd.has_subheader != 0x01) - return (0); - - /* read subheader */ - DREAD(shd, mcs_spreadsheet_subheader) - - /* correct endianness */ - uint_fast32_t colcount = hd.column_count; - colcount = be32toh(colcount << 8); - shd.defs_size = be32toh(shd.defs_size); - - /* 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; - - /* log some info */ - log_info("%" PRIuFAST32 " columns to read!", colcount); - - if (colcount) { - /* get the column directory */ - uint32_t column_directory[colcount]; - READ(&column_directory, sizeof(uint32_t) * colcount) - - /* browse columns */ - for (uint_fast32_t c = 0; c < colcount; c++) { - /* check if column is empty */ - if (!column_directory[c]) - continue; - - /* get the row directory */ - uint8_t row_directory[0x80]; - READ(&row_directory, (size_t)0x80) - - /* initialize loop values */ - uint8_t *rd = row_directory; - int bit = 1 << 7; - - /* explore each cell */ - for (uint_fast32_t i = 0; i < 1000; i++) { - /* check if used */ - if (*rd & bit) { - /* get cell */ - g1m_bcd_t cell; - DREAD(rawcell, bcd) - g1m_bcd_frommcs(&rawcell, &cell); - - /* store it */ - cells[c * 1000 + i] = (g1m_mcs_cell_t){ - .used = 1, - .real = cell, - .imgn = (g1m_bcd_t){} - }; - - /* check things (max row, max col, cells count) */ - rows = max(rows, i); - cols = c; - cells_count++; - } - - /* iterate bit and rd */ - rd += (bit & 1); - bit = (bit >> 1) | ((bit & 1) << 7); - } - } - } - - /* we have max rows and columns, increment to have sizes */ - rows++, cols++; - - /* create final tab */ - handle->cells = NULL; - handle->columns = 0; - handle->rows = 0; - if (cells_count) { - handle->columns = cols; - handle->rows = rows; - - /* alloc */ - g1m_mcs_cell_t **tab = malloc(sizeof(g1m_mcs_cell_t*) * cols); - if (!tab) return (g1m_error_alloc); - g1m_mcs_cell_t *rws = malloc(sizeof(g1m_mcs_cell_t) * cols * rows); - if (!rws) { free(tab); return (g1m_error_alloc); } - - /* main copying loop */ - for (uint_fast32_t y = 0; y < cols; y++) { - /* prepare index */ - tab[y] = &rws[y * rows]; - - /* copy each cell */ - for (uint_fast32_t x = 0; x < rows; x++) - tab[y][x] = cells[x * 1000 + y]; - } - - /* i used to be a cow. */ - handle->cells = tab; - } - - /* no error */ - return (0); -} - -/** - * mcs_decode_list: - * Decode an List. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg size the length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_list(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t size) -{ - /* read header */ - DREAD(hd, mcs_listheader) - - /* correct endianess */ - uint_fast16_t elcount = be16toh(hd.element_count); - - /* log */ - log_info("Title is '%.8s'", hd.title); - - /* prepare browsing */ - size -= sizeof(struct mcs_listheader); - - /* make tabs */ - g1m_bcd_t real[elcount], imgn[elcount]; - if (elcount) { - int one_imgn = 0; - mcs_bcd_t tab[elcount]; - /* read the real parts */ - size_t elsize = sizeof(mcs_bcd_t) * elcount; - size -= elsize; { - /* read reals */ - READ(tab, elsize) - - /* convert them */ - for (uint_fast16_t i = 0; i < elsize; i++) - one_imgn |= g1m_bcd_frommcs(&tab[elcount], &real[elcount]); - } - - /* read the imaginary parts */ - if (one_imgn) { - READ(tab, elsize) - - /* convert */ - for (uint_fast16_t i = 0; i < elsize; i++) - g1m_bcd_frommcs(&tab[elcount], &imgn[elcount]); - } - } - - /* fill final tab */ - handle->rows = elcount; - handle->columns = 1; - handle->cells = NULL; - if (elcount) { - /* allocate final tab */ - g1m_mcs_cell_t **tab = malloc(sizeof(g1m_mcs_cell_t*) * elcount); - if (!tab) return (g1m_error_alloc); - g1m_mcs_cell_t *rws = malloc(sizeof(g1m_mcs_cell_t) * elcount); - if (!tab) { free(tab); return (g1m_error_alloc); } - - /* main copying loop */ - for (uint_fast32_t y = 0; y < elcount; y++) { - int has_complex = g1m_bcd_has_special(&real[y]); - - /* prepare index and store */ - tab[y] = &rws[y]; - tab[y][0] = (g1m_mcs_cell_t){ - .used = 1, - .real = real[y], - .imgn = has_complex ? imgn[y] : (g1m_bcd_t){} - }; - } - - /* don't forget your baguette! */ - handle->cells = tab; - } - - /* no error */ - return (0); -} - -/** - * mcs_decode_matrix: - * Decode a matrix. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg length the data length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_matrix(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t length) -{ - g1m_mcs_cell_t **tab, *rws; - int err = g1m_error_alloc; - - /* read header */ - DREAD(hd, mcs_matheader) - - /* correct endianess */ - hd.width = be16toh(hd.width); - hd.height = be16toh(hd.height); - - /* log info */ - uint_fast32_t w = hd.width, h = hd.height; - log_info("Matrix size is %" PRIuFAST32 "*%" PRIuFAST32, w, h); - - /* store dimensions */ - handle->rows = w; - handle->columns = h; - handle->cells = NULL; - - if (w && h) { - /* alloc real matrix */ - tab = malloc(sizeof(g1m_mcs_cell_t*) * h); - if (!tab) return (g1m_error_alloc); - rws = malloc(sizeof(g1m_mcs_cell_t) * h * w); - if (!rws) { free(tab); return (g1m_error_alloc); } - - /* copy */ - int one_imgn = 0; - for (uint_fast32_t y = 0; y < h; y++) { - /* prepare index */ - tab[y] = &rws[y * w]; - - /* read squares */ - for (uint_fast32_t x = 0; x < w; x++) { - /* read the cell */ - g1m_bcd_t cell; - GDREAD(rawcell, bcd) - one_imgn |= g1m_bcd_frommcs(&rawcell, &cell); - - /* store it */ - tab[y][x] = (g1m_mcs_cell_t){ - .real = cell, - .imgn = {}, - .used = 1 - }; - } - } - - /* check imaginary parts */ - if (one_imgn) { - for (uint_fast32_t y = 0; y < h; y++) - for (uint_fast32_t x = 0; x < w; x++) { - GDREAD(rawcell, bcd) - if (tab[y][x].real.spe) { - g1m_bcd_t cell; - g1m_bcd_frommcs(&rawcell, &cell); - tab[y][x].imgn = cell; - } - } - } - - /* your sandwich, monsieur. */ - handle->cells = tab; - } - - /* no error */ - return (0); - - /* in case of unexpected EOF */ -fail: - free(tab); - free(rws); - return (err); -} - -/** - * mcs_decode_capture: - * Decode a capture. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg length the data length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_capture(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t length) -{ - /* read header */ - DREAD(hd, mcs_captureheader) - - /* correct endianess */ - hd.width = be16toh(hd.width); - hd.height = be16toh(hd.height); - - /* store */ - handle->width = hd.width; - handle->height = hd.height; - - /* print info */ - log_info("capture is %dx%d sized", handle->width, handle->height); - - /* get the image and return */ - return (get_image(buffer, &handle->image, handle->width, handle->height)); -} - -/** - * mcs_decode_picture: - * Decode a picture. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg length the data length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_picture(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t length) -{ - int err; - - /* store some dimensions, in case. */ - handle->width = 128; - handle->height = 64; - - /* get the first image */ - if ((err = get_image(buffer, &handle->image, 128, 64))) { - log_fatal("Failed to get the first image."); - return (err); - } - - /* and the second */ - if ((err = get_image(buffer, &handle->second_image, 128, 64))) { - log_fatal("Failed to get the second image."); - return (err); - } - - /* no error */ - return (0); -} - -/** - * mcs_decode_string: - * Decode an MCS string. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg length the data length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_string(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t length) -{ - (void)handle; - log_info("String MCS file is not managed yet. Content:"); - uint8_t str[length]; - READ(str, length); - logm_info(str, length); - /* TODO */ - return (0); -} - -/** - * mcs_decode_setup: - * Decode settings. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg length the data length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_setup(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t length) -{ - (void)handle; - log_info("Settings MCS file is not managed yet."); - /* TODO */ - SKIP(length) - return (0); -} - -/** - * mcs_decode_alphamem: - * Decode alpha memory (variables). - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg length the data length. - * @return the error code (0 if ok). - */ - -static int mcs_decode_alphamem(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, - uint_fast32_t length) -{ - /* read the data */ - uint8_t buf[length]; - READ(buf, length) - - /* allocate the vars table */ - handle->vars = malloc(29 * sizeof(g1m_mcs_cell_t)); - if (!handle->vars) return (g1m_error_alloc); - bzero(handle->vars, 29 * sizeof(g1m_mcs_cell_t)); - - /* copy */ - size_t tocopy = length - length % sizeof(g1m_mcs_cell_t); - memcpy(handle->vars, buf, tocopy); - - /* no problem, woop woop */ - return (0); -} - -/* ************************************************************************** */ -/* Type correspondance list */ -/* ************************************************************************** */ -/* MCS file parsing function type */ -typedef int (*mcs_decode_func_t)(g1m_mcsfile_t*, g1m_buffer_t*, uint_fast32_t); - -/* Correspondance type */ -struct mcs_corresp { - unsigned int type; - mcs_decode_func_t decode; -}; - -/* All correspondances */ -static struct mcs_corresp mcs_types[] = { - {g1m_mcstype_program, mcs_decode_program}, - {g1m_mcstype_list, mcs_decode_list}, - {g1m_mcstype_mat, mcs_decode_matrix}, - {g1m_mcstype_vct, mcs_decode_matrix}, - {g1m_mcstype_spreadsheet, mcs_decode_spreadsheet}, - {g1m_mcstype_pict, mcs_decode_picture}, - {g1m_mcstype_capt, mcs_decode_capture}, - {g1m_mcstype_string, mcs_decode_string}, - {g1m_mcstype_setup, mcs_decode_setup}, - {g1m_mcstype_alphamem, mcs_decode_alphamem}, - {} -}; - -/** - * 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(unsigned int 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); -} - -/* ************************************************************************** */ -/* Public file functions */ -/* ************************************************************************** */ -/** - * 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 */ - if (g1m_mcstype_get((char*)groupname, (char*)filename, raw_type, - &head->type, &head->id)) - head->type = g1m_mcstype_unknown; - log_info("libg1m file type is 0x%04X", head->type); -#if LOGLEVEL <= ll_info - if (g1m_mcstype_uses_id(head->type)) { - log_info("libg1m file id is (%d, %d)", g1m_get_id_major(head->id), - g1m_get_id_minor(head->id)); - } -#endif - - /* copy the name and size */ - memcpy(head->name, filename, 8); head->name[8] = 0; - head->size = filesize; - - /* save raw data */ - head->_rawtype = raw_type; - memcpy(head->_group, groupname, 16); head->_group[16] = 0; - if (dirname) { - memcpy(head->_dirname, dirname, 8); head->_dirname[8] = 0; - } else memset(head->_dirname, 0, 9); - - /* everything went well! */ - return (0); -} - -/** - * 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); - - /* create handle */ - *handle = malloc(sizeof(g1m_mcsfile_t)); - if (!handle) return (g1m_error_alloc); - g1m_mcsfile_t *h = *handle; - memset(h, 0, sizeof(g1m_mcsfile_t)); - - /* copy the head */ - memcpy(&h->head, head, sizeof(g1m_mcshead_t)); - - /* look for the parsing function */ - mcs_decode_func_t decode = lookup_mcsfile_decode(head->type); - if (!decode) { - log_error("No dedicated parsing function for this type was found!"); - goto notparsing; - } - - /* decode */ - err = (*decode)(h, buffer, head->size); - if (err) goto fail; - - /* no error :D */ - return (0); - -notparsing: - /* allocate enough space */ - h->content = malloc(head->size); - err = g1m_error_alloc; - if (!h->content) goto fail; - - /* read the content */ - GREAD(h->content, head->size) - - /* log */ - log_info("File content:"); - logm_info(h->content, head->size); - - /* saved normally */ - return (0); - -fail: - if (h) { - if (h->content) free(h->content); - free(h); - } - *handle = NULL; - 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) -{ - const unsigned char *p = data; - g1m_buffer_t buffer = { - .cookie = p, - .read = g1m_membuffer_read - }; - - return (g1m_decode_mcsfile(handle, head, &buffer)); -} - -/* ************************************************************************** */ -/* Main file function */ -/* ************************************************************************** */ -/** - * g1m_decode_mcs: - * Decode an MCS file, after the Standard Header. - * - * @arg handle the handle. - * @arg buffer the buffer to read from. - * @arg num number of sizes. - * @return the error code (0 if ok). - */ - -int g1m_decode_mcs(g1m_t *handle, g1m_buffer_t *buffer, - struct standard_header *std) -{ - int err = g1m_error_alloc; - /* get number of subparts from the standard header */ - uint_fast16_t num = std->number; - - /* allocate memory for the files index */ - handle->count = 0; - handle->_size = num; - if (num) { - handle->files = malloc(sizeof(g1m_mcsfile_t*) * num); - if (!handle->files) return (g1m_error_alloc); - } - - /* read all of the parts */ - log_info("%" PRIuFAST16 " total mcs files to browse", num); - while (handle->count < (int)num) { - /* get the subheader */ - GDREAD(hd, mcs_subheader) - - /* correct endianess */ - hd.subcount = be32toh(hd.subcount); - - /* log info about part */ - log_info("New group! Group name is '%.16s'.", hd.intname); - log_info("%d mcs files to browse in that group", hd.subcount); - - /* foreach subpart */ - for (uint_fast32_t i = 0; i < hd.subcount; i++) { - /* get the part header */ - GDREAD(fhd, mcs_fileheader) - - /* correct endianess */ - fhd.datalength = be32toh(fhd.datalength); - - /* log info about the subpart */ - log_info("[%" PRIuFAST32 "] directory name is '%.8s'", - i, fhd.dirname); - log_info("[%" PRIuFAST32 "] filename is '%.8s'", i, fhd.filename); - log_info("[%" PRIuFAST32 "] data length is %" PRIu32, - i, fhd.datalength); - - /* decode the head */ - g1m_mcshead_t head; - g1m_decode_mcsfile_head(&head, fhd.filetype, hd.intname, - fhd.dirname, fhd.filename, fhd.datalength); - - /* decode */ - handle->files[handle->count] = NULL; - err = g1m_decode_mcsfile(&handle->files[handle->count], - &head, buffer); - if (err) goto fail; - handle->count++; - } - } - - /* no error */ - return (0); - - /* was error! */ -fail: - g1m_free_mcs(handle); - return (err); -} diff --git a/src/decode/mcs/alphamem.c b/src/decode/mcs/alphamem.c new file mode 100644 index 0000000..8dd303b --- /dev/null +++ b/src/decode/mcs/alphamem.c @@ -0,0 +1,59 @@ +/* ***************************************************************************** + * decode/mcs/alphamem.c -- decode an MCS alpha memory 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 + +/** + * g1m_decode_mcs_alphamem: + * Decode alpha memory (variables). + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg length the data length. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcs_alphamem(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t length) +{ + /* read the data */ + uint8_t buf[length]; + READ(buf, length) + + /* count number of vars */ + handle->count = length / (2 * sizeof(mcs_bcd_t)); + + /* allocate the vars table */ + handle->vars = malloc(handle->count * sizeof(g1m_mcs_cell_t)); + if (!handle->vars) return (g1m_error_alloc); + + /* copy */ + const mcs_bcd_t *b = (void*)buf; + for (int i = 0; i < handle->count; i++) { + g1m_bcd_frommcs(b++, &handle->vars[i].real); + g1m_bcd_frommcs(b++, &handle->vars[i].imgn); + handle->vars[i].used = 1; + } + + /* copy */ + size_t tocopy = length - length % sizeof(g1m_mcs_cell_t); + memcpy(handle->vars, buf, tocopy); + + /* no problem, woop woop */ + return (0); +} diff --git a/src/decode/mcs/list.c b/src/decode/mcs/list.c new file mode 100644 index 0000000..2ebc49d --- /dev/null +++ b/src/decode/mcs/list.c @@ -0,0 +1,102 @@ +/* ***************************************************************************** + * decode/mcs/list.c -- decode an MCS list. + * 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 + +/** + * g1m_decode_mcs_list: + * Decode an List. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg size the length. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcs_list(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t size) +{ + /* read header */ + DREAD(hd, mcs_listheader) + + /* correct endianess */ + uint_fast16_t elcount = be16toh(hd.element_count); + + /* log */ + log_info("Title is '%.8s'", hd.title); + + /* prepare browsing */ + size -= sizeof(struct mcs_listheader); + + /* make tabs */ + g1m_bcd_t real[elcount], imgn[elcount]; + if (elcount) { + int one_imgn = 0; + mcs_bcd_t tab[elcount]; + /* read the real parts */ + size_t elsize = sizeof(mcs_bcd_t) * elcount; + size -= elsize; { + /* read reals */ + READ(tab, elsize) + + /* convert them */ + for (uint_fast16_t i = 0; i < elsize; i++) + one_imgn |= g1m_bcd_frommcs(&tab[elcount], &real[elcount]); + } + + /* read the imaginary parts */ + if (one_imgn) { + READ(tab, elsize) + + /* convert */ + for (uint_fast16_t i = 0; i < elsize; i++) + g1m_bcd_frommcs(&tab[elcount], &imgn[elcount]); + } + } + + /* fill final tab */ + handle->rows = elcount; + handle->columns = 1; + handle->cells = NULL; + if (elcount) { + /* allocate final tab */ + g1m_mcs_cell_t **tab = malloc(sizeof(g1m_mcs_cell_t*) * elcount); + if (!tab) return (g1m_error_alloc); + g1m_mcs_cell_t *rws = malloc(sizeof(g1m_mcs_cell_t) * elcount); + if (!tab) { free(tab); return (g1m_error_alloc); } + + /* main copying loop */ + for (uint_fast32_t y = 0; y < elcount; y++) { + int has_complex = g1m_bcd_has_special(&real[y]); + + /* prepare index and store */ + tab[y] = &rws[y]; + tab[y][0] = (g1m_mcs_cell_t){ + .used = 1, + .real = real[y], + .imgn = has_complex ? imgn[y] : (g1m_bcd_t){} + }; + } + + /* don't forget your baguette! */ + handle->cells = tab; + } + + /* no error */ + return (0); +} diff --git a/src/decode/mcs/matrix.c b/src/decode/mcs/matrix.c new file mode 100644 index 0000000..0d7fac8 --- /dev/null +++ b/src/decode/mcs/matrix.c @@ -0,0 +1,106 @@ +/* ***************************************************************************** + * decode/mcs/matrix.c -- decode an MCS matrix. + * 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 + +/** + * g1m_decode_mcs_matrix: + * Decode a matrix. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg length the data length. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcs_matrix(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t length) +{ + g1m_mcs_cell_t **tab, *rws; + int err = g1m_error_alloc; + + /* read header */ + DREAD(hd, mcs_matheader) + + /* correct endianess */ + hd.width = be16toh(hd.width); + hd.height = be16toh(hd.height); + + /* log info */ + uint_fast32_t w = hd.width, h = hd.height; + log_info("Matrix size is %" PRIuFAST32 "*%" PRIuFAST32, w, h); + + /* store dimensions */ + handle->rows = w; + handle->columns = h; + handle->cells = NULL; + + if (w && h) { + /* alloc real matrix */ + tab = malloc(sizeof(g1m_mcs_cell_t*) * h); + if (!tab) return (g1m_error_alloc); + rws = malloc(sizeof(g1m_mcs_cell_t) * h * w); + if (!rws) { free(tab); return (g1m_error_alloc); } + + /* copy */ + int one_imgn = 0; + g1m_bcd_t bcd; + for (uint_fast32_t y = 0; y < h; y++) { + /* prepare index */ + tab[y] = &rws[y * w]; + + /* read squares */ + for (uint_fast32_t x = 0; x < w; x++) { + /* read the cell */ + GDREAD(rawbcd, bcd) + one_imgn |= g1m_bcd_frommcs(&rawbcd, &bcd); + + /* store it */ + tab[y][x] = (g1m_mcs_cell_t){ + .real = bcd, + .imgn = {}, + .used = 1 + }; + } + } + + /* check imaginary parts */ + if (one_imgn) { + for (uint_fast32_t y = 0; y < h; y++) + for (uint_fast32_t x = 0; x < w; x++) { + GDREAD(rawbcd, bcd) + if (tab[y][x].real.spe) { + g1m_bcd_frommcs(&rawbcd, &bcd); + tab[y][x].imgn = bcd; + } + } + } + + /* your sandwich, monsieur. */ + handle->cells = tab; + } + + /* no error */ + return (0); + + /* in case of unexpected EOF */ +fail: + free(tab); + free(rws); + return (err); +} diff --git a/src/decode/mcs/picture.c b/src/decode/mcs/picture.c new file mode 100644 index 0000000..43d8a66 --- /dev/null +++ b/src/decode/mcs/picture.c @@ -0,0 +1,141 @@ +/* ***************************************************************************** + * decode/mcs/picture.c -- decode an MCS picture. + * 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 + +/* ************************************************************************** */ +/* Internal functions */ +/* ************************************************************************** */ +/** + * get_image: + * Allocate space, and convert monochromic image to 0x0RGB. + * + * @arg buffer the buffer to read from. + * @arg img the image to make. + * @arg width the image width. + * @arg height the image height. + */ + +static int get_image(g1m_buffer_t *buffer, uint32_t ***img, + unsigned int width, unsigned int height) +{ + /* get raw pixels */ + size_t linesize = width / 8 + !!(width % 8); + size_t bufsize = height * linesize; + uint8_t buf[bufsize]; + READ(buf, bufsize) + + /* alloc */ + *img = malloc(height * (sizeof(uint32_t*)) + + width * height * sizeof(uint32_t)); + if (!*img) + return (g1m_error_alloc); + + /* fill */ + uint32_t **image = *img; + for (uint_fast16_t y = 0; y < height; y++) { + /* setup index */ + image[y] = (uint32_t*)&image[height] + y * 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 < width; x++) { + /* set pixel */ + image[y][x] = *b & bit ? 0xffffff : 0x000000; + + /* go further */ + b += bit & 1; + bit = (bit >> 1) | ((bit & 1) << 7); + } + } + + /* no error */ + return (0); +} + +/* ************************************************************************** */ +/* Real decode functions */ +/* ************************************************************************** */ +/** + * g1m_decode_mcs_capture: + * Decode a capture. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg length the data length. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcs_capture(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t length) +{ + /* read header */ + DREAD(hd, mcs_captureheader) + + /* correct endianess */ + hd.width = be16toh(hd.width); + hd.height = be16toh(hd.height); + + /* store */ + handle->width = hd.width; + handle->height = hd.height; + + /* print info */ + log_info("capture is %dx%d sized", handle->width, handle->height); + + /* get the image and return */ + return (get_image(buffer, &handle->image, handle->width, handle->height)); +} + +/** + * g1m_decode_mcs_picture: + * Decode a picture. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg length the data length. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcs_picture(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t length) +{ + int err; + + /* store some dimensions, in case. */ + handle->width = 128; + handle->height = 64; + + /* get the first image */ + if ((err = get_image(buffer, &handle->image, 128, 64))) { + log_fatal("Failed to get the first image."); + return (err); + } + + /* and the second */ + if ((err = get_image(buffer, &handle->second_image, 128, 64))) { + log_fatal("Failed to get the second image."); + return (err); + } + + /* no error */ + return (0); +} diff --git a/src/decode/mcs/program.c b/src/decode/mcs/program.c new file mode 100644 index 0000000..7af8505 --- /dev/null +++ b/src/decode/mcs/program.c @@ -0,0 +1,55 @@ +/* ***************************************************************************** + * decode/mcs/program.c -- decode an MCS program. + * 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 + +/** + * g1m_decode_mcs_program: + * Decode a program. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg length the data length. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcs_program(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t length) +{ + /* read header */ + DREAD(hd, mcs_programheader) + + /* print header data */ + log_info("Program password is '%.8s'.", hd.password); + + /* store info */ + strncpy(handle->password, (char*)hd.password, 8); + handle->password[8] = 0; + + /* get content */ + size_t content_size = length - sizeof(struct mcs_programheader); + log_info("Getting program content (%" PRIuSIZE "o)", content_size); + handle->content = malloc(content_size + 1); + handle->head.size = content_size + 1; + if (!handle->content) return (g1m_error_alloc); + READ(handle->content, content_size); + handle->content[content_size] = 0; + + /* no error */ + return (0); +} diff --git a/include/libg1m/format/fxi.h b/src/decode/mcs/setup.c similarity index 65% rename from include/libg1m/format/fxi.h rename to src/decode/mcs/setup.c index 85a8cff..815ad68 100644 --- a/include/libg1m/format/fxi.h +++ b/src/decode/mcs/setup.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * libg1m/format/fxi.h -- the FXI file format description. + * decode/mcs/setup.c -- decode an MCS setup file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -16,13 +16,24 @@ * You should have received a copy of the GNU Lesser General Public License * along with libg1m; if not, see . * ************************************************************************** */ -#ifndef LIBG1M_FORMAT_FXI_H -# define LIBG1M_FORMAT_FXI_H -# include -# include -# pragma pack(1) +#include -/* TODO, I guess? */ +/** + * g1m_decode_mcs_setup: + * Decode settings. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg length the data length. + * @return the error code (0 if ok). + */ -# pragma pack() -#endif +int g1m_decode_mcs_setup(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t length) +{ + (void)handle; + log_info("Settings MCS file is not managed yet."); + /* TODO */ + SKIP(length) + return (0); +} diff --git a/src/decode/mcs/spreadsheet.c b/src/decode/mcs/spreadsheet.c new file mode 100644 index 0000000..167b340 --- /dev/null +++ b/src/decode/mcs/spreadsheet.c @@ -0,0 +1,140 @@ +/* ***************************************************************************** + * decode/mcs/spreadsheet.c -- decode an MCS spreadsheet. + * 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 + +/** + * g1m_decode_mcs_spreadsheet: + * Decode a spreadsheet. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg length the data length. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcs_spreadsheet(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t length) +{ + /* read header */ + DREAD(hd, mcs_spreadsheetheader) + + /* check if the spreadsheet type is known */ + if (hd.has_subheader != 0x01) + return (0); + + /* read subheader */ + DREAD(shd, mcs_spreadsheet_subheader) + + /* correct endianness */ + uint_fast32_t colcount = hd.column_count; + colcount = be32toh(colcount << 8); + shd.defs_size = be32toh(shd.defs_size); + + /* 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; + + /* log some info */ + log_info("%" PRIuFAST32 " columns to read!", colcount); + + if (colcount) { + /* get the column directory */ + uint32_t column_directory[colcount]; + READ(&column_directory, sizeof(uint32_t) * colcount) + + /* browse columns */ + for (uint_fast32_t c = 0; c < colcount; c++) { + /* check if column is empty */ + if (!column_directory[c]) + continue; + + /* get the row directory */ + uint8_t row_directory[0x80]; + READ(&row_directory, (size_t)0x80) + + /* initialize loop values */ + uint8_t *rd = row_directory; + int bit = 1 << 7; + + /* explore each cell */ + for (uint_fast32_t i = 0; i < 1000; i++) { + /* check if used */ + if (*rd & bit) { + /* get cell */ + g1m_bcd_t cell; + DREAD(rawcell, bcd) + g1m_bcd_frommcs(&rawcell, &cell); + + /* store it */ + cells[c * 1000 + i] = (g1m_mcs_cell_t){ + .used = 1, + .real = cell, + .imgn = (g1m_bcd_t){} + }; + + /* check things (max row, max col, cells count) */ + rows = max(rows, i); + cols = c; + cells_count++; + } + + /* iterate bit and rd */ + rd += (bit & 1); + bit = (bit >> 1) | ((bit & 1) << 7); + } + } + } + + /* we have max rows and columns, increment to have sizes */ + rows++, cols++; + + /* create final tab */ + handle->cells = NULL; + handle->columns = 0; + handle->rows = 0; + if (cells_count) { + handle->columns = cols; + handle->rows = rows; + + /* alloc */ + g1m_mcs_cell_t **tab = malloc(sizeof(g1m_mcs_cell_t*) * cols); + if (!tab) return (g1m_error_alloc); + g1m_mcs_cell_t *rws = malloc(sizeof(g1m_mcs_cell_t) * cols * rows); + if (!rws) { free(tab); return (g1m_error_alloc); } + + /* main copying loop */ + for (uint_fast32_t y = 0; y < cols; y++) { + /* prepare index */ + tab[y] = &rws[y * rows]; + + /* copy each cell */ + for (uint_fast32_t x = 0; x < rows; x++) + tab[y][x] = cells[x * 1000 + y]; + } + + /* i used to be a cow. */ + handle->cells = tab; + } + + /* no error */ + return (0); +} diff --git a/src/decode/mcs/string.c b/src/decode/mcs/string.c new file mode 100644 index 0000000..bb74fbd --- /dev/null +++ b/src/decode/mcs/string.c @@ -0,0 +1,41 @@ +/* ***************************************************************************** + * decode/mcs/string.c.c -- decode an MCS string. + * 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 + +/** + * g1m_decode_mcs_string: + * Decode an MCS string. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg length the data length. + * @return the error code (0 if ok). + */ + +int g1m_decode_mcs_string(g1m_mcsfile_t *handle, g1m_buffer_t *buffer, + uint_fast32_t length) +{ + (void)handle; + log_info("String MCS file is not managed yet. Content:"); + uint8_t str[length]; + READ(str, length); + logm_info(str, length); + /* TODO */ + return (0); +} diff --git a/src/decode/newcat.c b/src/decode/newcat.c.draft similarity index 100% rename from src/decode/newcat.c rename to src/decode/newcat.c.draft diff --git a/src/decode/main.c b/src/decode/std.c similarity index 72% rename from src/decode/main.c rename to src/decode/std.c index 14bcf41..3388b1b 100644 --- a/src/decode/main.c +++ b/src/decode/std.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * decode/main.c -- decode a file. + * decode/std.c -- decode a "standard" CASIO file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -15,59 +15,58 @@ * * You should have received a copy of the GNU Lesser General Public License * along with libg1m; if not, see . - * - * Actually, this file implements the general decoding function, and the - * standard header files general decoding function ("""historical""" reasons). * ************************************************************************** */ #include +#define FUNC(NAME) g1m_decode_std_##NAME /* ************************************************************************** */ /* Getting the parsing function */ /* ************************************************************************** */ /* Correspondance type */ +typedef int (*decode_func)(g1m_t*, g1m_buffer_t*, struct standard_header*); struct corresp { unsigned int platform; unsigned int type; /* result */ - g1m_decode_function *decode; + decode_func decode; }; /* The correspondances */ static struct corresp parsing_functions[] = { /* add-ins */ {g1m_platform_fx, g1m_type_addin, - g1m_decode_addin}, + FUNC(addin)}, {g1m_platform_cg, g1m_type_addin, - g1m_decode_addin_cg}, + FUNC(addin_cg)}, /* mcs */ {g1m_platform_fx, g1m_type_mcs, - g1m_decode_mcs}, + FUNC(mcs)}, {g1m_platform_cg, g1m_type_mcs, - g1m_decode_mcs}, + FUNC(mcs)}, /* language files */ {g1m_platform_fx, g1m_type_lang, - g1m_decode_lang}, + FUNC(lang)}, {g1m_platform_cg, g1m_type_lang, - g1m_decode_lang_cg}, + FUNC(lang_cg)}, /* function keys file */ {g1m_platform_fx, g1m_type_fkey, - g1m_decode_fkey}, + FUNC(fkey)}, {g1m_platform_cg, g1m_type_fkey, - g1m_decode_lang_cg}, + FUNC(lang_cg)}, /* e-activities */ {g1m_platform_fx, g1m_type_eact, - g1m_decode_eact}, + FUNC(eact)}, /* pictures */ {g1m_platform_cg, g1m_type_pict, - g1m_decode_g3p}, + FUNC(g3p)}, {g1m_platform_cp, g1m_type_pict, - g1m_decode_c2p}, + FUNC(c2p)}, /* storage */ /*{g1m_platform_none, g1m_type_storage, @@ -88,7 +87,7 @@ static struct corresp parsing_functions[] = { */ static int find_decode_function(g1m_t *handle, const char *path, - struct standard_header *std, g1m_decode_function **rd) + struct standard_header *std, decode_func *rd) { /* get the type */ unsigned int platform, type; @@ -134,7 +133,7 @@ static int find_decode_function(g1m_t *handle, const char *path, /* Main standard header decoding function */ /* ************************************************************************** */ /** - * decode_std: + * g1m_decode_std: * Decode a file with standard header. * * @arg handle the handle. @@ -145,7 +144,7 @@ static int find_decode_function(g1m_t *handle, const char *path, * @return the error code (0 if ok). */ -static int decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer, +int g1m_decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer, struct standard_header *std, g1m_type_t expected_types) { /* reverse the standard header */ @@ -162,7 +161,7 @@ static int decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer, std->number = be16toh(std->number); /* get type */ - g1m_decode_function *read_func; int err; + decode_func read_func; int err; if ((err = find_decode_function(handle, path, std, &read_func))) return (err); @@ -177,38 +176,3 @@ static int decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer, /* subdecode. */ return ((*read_func)(handle, buffer, std)); } - -/* ************************************************************************** */ -/* Main decoding function */ -/* ************************************************************************** */ -/** - * g1m_decode: - * Decode a file. - * - * Read the standard header, correct endianness, check magic numbers, - * then read subparts according to the G1M type. - * - * @arg handle the handle. - * @arg path the file path. - * @arg buffer the buffer to read from. - * @arg expected_types the expected types. - * @return the error code (0 if ok). - */ - -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)); - - /* identify a CAS file */ - unsigned char buf[0x20]; READ(buf, 1) - if (buf[0] == ':') - return (g1m_decode_cas(handle, buffer, expected_types)); - - /* identify a standard header (send a _copy_) */ - READ(&buf[1], 0x1F) - uint8_t altbuf[0x20]; memcpy(altbuf, buf, 0x20); - return (decode_std(handle, path, buffer, (struct standard_header*)altbuf, - expected_types)); -} diff --git a/src/decode/addin.c b/src/decode/std/addin.c similarity index 96% rename from src/decode/addin.c rename to src/decode/std/addin.c index c51f338..76e240e 100644 --- a/src/decode/addin.c +++ b/src/decode/std/addin.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * decode/addin.c -- decode an add-in file. + * decode/std/addin.c -- decode an add-in file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -74,7 +74,7 @@ static void addin_set_data(g1m_t *handle, } /** - * g1m_decode_addin: + * g1m_decode_std_addin: * Decodes a "normal" add-in (after Standard Header). * * @arg handle the handle. @@ -82,7 +82,7 @@ static void addin_set_data(g1m_t *handle, * @return the error code (0 if ok). */ -int g1m_decode_addin(g1m_t *handle, g1m_buffer_t *buffer, +int g1m_decode_std_addin(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { int err = 0; @@ -127,7 +127,7 @@ int g1m_decode_addin(g1m_t *handle, g1m_buffer_t *buffer, } /** - * g1m_decode_addin_cg: + * g1m_decode_std_addin_cg: * Decode fx-CG add-in (after Standard Header). * * @arg handle the handle. @@ -136,7 +136,7 @@ int g1m_decode_addin(g1m_t *handle, g1m_buffer_t *buffer, * @return the error code (0 if ok). */ -int g1m_decode_addin_cg(g1m_t *handle, g1m_buffer_t *buffer, +int g1m_decode_std_addin_cg(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { int err = 0; diff --git a/src/decode/eact.c b/src/decode/std/eact.c similarity index 98% rename from src/decode/eact.c rename to src/decode/std/eact.c index 0f548c2..03d4ed6 100644 --- a/src/decode/eact.c +++ b/src/decode/std/eact.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * decode/eact.c -- decode an e-activity file. + * decode/std/eact.c -- decode an e-activity file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -423,7 +423,7 @@ static int eact_decode_line(g1m_line_t *handle, uint8_t *buf, size_t size, /* Main parsing functions */ /* ************************************************************************** */ /** - * g1m_decode_eact: + * g1m_decode_std_eact: * Decodes an EACT. * * Thanks to Julese50 for his help on e-acts parsing. @@ -433,7 +433,7 @@ static int eact_decode_line(g1m_line_t *handle, uint8_t *buf, size_t size, * @return the error code (0 if ok). */ -int g1m_decode_eact(g1m_t * handle, g1m_buffer_t *buffer, +int g1m_decode_std_eact(g1m_t * handle, g1m_buffer_t *buffer, struct standard_header *std) { (void)std; diff --git a/src/decode/fkey.c b/src/decode/std/fkey.c similarity index 97% rename from src/decode/fkey.c rename to src/decode/std/fkey.c index 7a7c529..f08d56c 100644 --- a/src/decode/fkey.c +++ b/src/decode/std/fkey.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * decode/fkey.c -- decode a function keys file. + * decode/std/fkey.c -- decode a function keys file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -61,7 +61,7 @@ static uint32_t **fkeydup3(uint8_t *fkey) /* fx function keys file parsing utilities */ /* ************************************************************************** */ /** - * g1m_decode_fkey: + * g1m_decode_std_fkey: * Decode fx function keys files. * * @arg handle the libg1m handle. @@ -70,7 +70,7 @@ static uint32_t **fkeydup3(uint8_t *fkey) * @return the error code (0 if ok). */ -int g1m_decode_fkey(g1m_t *handle, g1m_buffer_t *buffer, +int g1m_decode_std_fkey(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { (void)std; diff --git a/src/decode/lang.c b/src/decode/std/lang.c similarity index 97% rename from src/decode/lang.c rename to src/decode/std/lang.c index f7d9d81..50034eb 100644 --- a/src/decode/lang.c +++ b/src/decode/std/lang.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * decode/lang.c -- decode a language file. + * decode/std/lang.c -- decode a language file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -22,7 +22,7 @@ /* fx language files parsing */ /* ************************************************************************** */ /** - * g1m_decode_lang: + * g1m_decode_std_lang: * Decode fx language files. * * @arg handle the libg1m handle. @@ -30,7 +30,7 @@ * @return the error code (0 if ok). */ -int g1m_decode_lang(g1m_t *handle, g1m_buffer_t *buffer, +int g1m_decode_std_lang(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { (void)std; @@ -192,7 +192,7 @@ fail: } /** - * g1m_decode_lang_cg: + * g1m_decode_std_lang_cg: * Decode fx-CG language files. * * @arg handle the libg1m handle. @@ -201,7 +201,7 @@ fail: * @return the error code (0 if ok). */ -int g1m_decode_lang_cg(g1m_t *handle, g1m_buffer_t *buffer, +int g1m_decode_std_lang_cg(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { /* set handle type */ diff --git a/src/decode/std/mcs.c b/src/decode/std/mcs.c new file mode 100644 index 0000000..9bf2d8d --- /dev/null +++ b/src/decode/std/mcs.c @@ -0,0 +1,295 @@ +/* ***************************************************************************** + * decode/std/mcs.c -- decode an MCS archive 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*, uint_fast32_t); + +/* Correspondance type */ +struct mcs_corresp { + unsigned int type; + mcs_decode_func_t decode; +}; + +/* All correspondances */ +static struct mcs_corresp mcs_types[] = { + {g1m_mcstype_program, FUNC(program)}, + {g1m_mcstype_list, FUNC(list)}, + {g1m_mcstype_mat, FUNC(matrix)}, + {g1m_mcstype_vct, FUNC(matrix)}, + {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(alphamem)}, + {g1m_mcstype_variable, FUNC(alphamem)}, + {} +}; + +/** + * 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(unsigned int 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); +} + +/* ************************************************************************** */ +/* Public file functions */ +/* ************************************************************************** */ +/** + * 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 */ + if (g1m_mcstype_get((char*)groupname, (char*)filename, raw_type, + &head->type, &head->id)) + head->type = g1m_mcstype_unknown; + log_info("libg1m file type is 0x%04X", head->type); +#if LOGLEVEL <= ll_info + if (g1m_mcstype_uses_id(head->type)) { + log_info("libg1m file id is (%d, %d)", g1m_get_id_major(head->id), + g1m_get_id_minor(head->id)); + } +#endif + + /* copy the name and size */ + memcpy(head->name, filename, 8); head->name[8] = 0; + head->size = filesize; + + /* save raw data */ + head->_rawtype = raw_type; + memcpy(head->_group, groupname, 16); head->_group[16] = 0; + if (dirname) { + memcpy(head->_dirname, dirname, 8); head->_dirname[8] = 0; + } else memset(head->_dirname, 0, 9); + + /* everything went well! */ + return (0); +} + +/** + * 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); + + /* create handle */ + *handle = malloc(sizeof(g1m_mcsfile_t)); + if (!handle) return (g1m_error_alloc); + g1m_mcsfile_t *h = *handle; + memset(h, 0, sizeof(g1m_mcsfile_t)); + + /* copy the head */ + memcpy(&h->head, head, sizeof(g1m_mcshead_t)); + + /* look for the parsing function */ + mcs_decode_func_t decode = lookup_mcsfile_decode(head->type); + if (!decode) { + log_error("No dedicated parsing function for this type was found!"); + goto notparsing; + } + + /* read the buffer (safer) */ + uint8_t *buf = malloc(head->size); + if (!buf) return (g1m_error_alloc); + READ(buf, head->size) + + /* decode */ + g1m_buffer_t membuf = MEMBUFFER(buf, head->size); + err = (*decode)(h, &membuf, head->size); + free(buf); + if (err) goto fail; + + /* no error :D */ + return (0); + +notparsing: + /* allocate enough space */ + h->content = malloc(head->size); + err = g1m_error_alloc; + if (!h->content) goto fail; + + /* read the content */ + GREAD(h->content, head->size) + + /* log */ + log_info("File content:"); + logm_info(h->content, head->size); + + /* saved normally */ + return (0); + +fail: + if (h) { + if (h->content) free(h->content); + free(h); + } + *handle = NULL; + 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)); +} + +/* ************************************************************************** */ +/* Main file function */ +/* ************************************************************************** */ +/** + * g1m_decode_std_mcs: + * Decode an MCS file, after the Standard Header. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @arg num number of sizes. + * @return the error code (0 if ok). + */ + +int g1m_decode_std_mcs(g1m_t *handle, g1m_buffer_t *buffer, + struct standard_header *std) +{ + int err = g1m_error_alloc; + /* get number of subparts from the standard header */ + uint_fast16_t num = std->number; + + /* allocate memory for the files index */ + handle->count = 0; + handle->_size = num; + if (num) { + handle->files = malloc(sizeof(g1m_mcsfile_t*) * num); + if (!handle->files) return (g1m_error_alloc); + } + + /* read all of the parts */ + log_info("%" PRIuFAST16 " total mcs files to browse", num); + while (handle->count < (int)num) { + /* get the subheader */ + GDREAD(hd, mcs_subheader) + + /* correct endianess */ + hd.subcount = be32toh(hd.subcount); + + /* log info about part */ + log_info("New group! Group name is '%.16s'.", hd.intname); + log_info("%d mcs files to browse in that group", hd.subcount); + + /* foreach subpart */ + for (uint_fast32_t i = 0; i < hd.subcount; i++) { + /* get the part header */ + GDREAD(fhd, mcs_fileheader) + + /* correct endianess */ + fhd.datalength = be32toh(fhd.datalength); + + /* log info about the subpart */ + log_info("[%" PRIuFAST32 "] directory name is '%.8s'", + i, fhd.dirname); + log_info("[%" PRIuFAST32 "] filename is '%.8s'", i, fhd.filename); + log_info("[%" PRIuFAST32 "] data length is %" PRIu32, + i, fhd.datalength); + + /* decode the head */ + g1m_mcshead_t head; + g1m_decode_mcsfile_head(&head, fhd.filetype, hd.intname, + fhd.dirname, fhd.filename, fhd.datalength); + + /* decode */ + handle->files[handle->count] = NULL; + err = g1m_decode_mcsfile(&handle->files[handle->count], + &head, buffer); + if (err) goto fail; + handle->count++; + } + } + + /* no error */ + return (0); + + /* was error! */ +fail: + g1m_free_mcs(handle); + return (err); +} diff --git a/src/decode/picture.c b/src/decode/std/picture.c similarity index 95% rename from src/decode/picture.c rename to src/decode/std/picture.c index eb80fd6..2efe2fa 100644 --- a/src/decode/picture.c +++ b/src/decode/std/picture.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * decode/picture.c -- decode a picture file. + * decode/std/picture.c -- decode a picture file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -36,7 +36,7 @@ static void g3p_deobfuscate(uint8_t *buf, size_t n) } /** - * g1m_decode_g3p: + * g1m_decode_std_g3p: * Decode a G3P file. * * @arg handle the handle. @@ -45,7 +45,7 @@ static void g3p_deobfuscate(uint8_t *buf, size_t n) * @return the error code (0 if ok). */ -int g1m_decode_g3p(g1m_t *handle, g1m_buffer_t *buffer, +int g1m_decode_std_g3p(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { /* get the G3P global header */ @@ -142,7 +142,7 @@ int g1m_decode_g3p(g1m_t *handle, g1m_buffer_t *buffer, } /** - * g1m_decode_c2p: + * g1m_decode_std_c2p: * Decode Classpad images. * * @arg handle the handle. @@ -150,7 +150,7 @@ int g1m_decode_g3p(g1m_t *handle, g1m_buffer_t *buffer, * @return the error code (0 if ok). */ -int g1m_decode_c2p(g1m_t *handle, g1m_buffer_t *buffer, +int g1m_decode_std_c2p(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { (void)std; diff --git a/src/decode/storage.c.draft b/src/decode/std/storage.c.draft similarity index 97% rename from src/decode/storage.c.draft rename to src/decode/std/storage.c.draft index bb60661..af3312a 100644 --- a/src/decode/storage.c.draft +++ b/src/decode/std/storage.c.draft @@ -1,5 +1,5 @@ /* ***************************************************************************** - * decode/storage.c -- decode a storage file. + * decode/std/storage.c -- decode a storage file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -35,7 +35,7 @@ * @return the error code (0 if ok). */ -int g1m_decode_storage(g1m_t *handle, g1m_buffer_t *buffer, +int g1m_decode_std_storage(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { (void)std; int err, ret = 0; diff --git a/src/utils/castype.c b/src/type/cas.c similarity index 96% rename from src/utils/castype.c rename to src/type/cas.c index f3f66f9..b0988cc 100644 --- a/src/utils/castype.c +++ b/src/type/cas.c @@ -1,6 +1,5 @@ /* ***************************************************************************** - * utils/castypes.c -- get the CAS type and data types out of raw - * identification data. + * type/cas.c -- get the CAS type and data types out of raw identification data. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -40,6 +39,8 @@ struct type_corresp { #define TTERM {NULL, 0} static struct type_corresp cas_groups[] = { + {"PG", g1m_mcstype_program}, + /* not implemented yet types, described by Tom Wheeley and Tom Lynn */ {"AA", 0}, // dynamic graph functions {"AD", 0}, // variable memory @@ -78,8 +79,7 @@ static struct type_corresp cas_groups[] = { {"VM", 0}, // Variable (A-Z, etc) {"WD", 0}, // window data - /* implemented types */ - {"PG", g1m_mcstype_program}, + /* terminating entry */ TTERM }; diff --git a/src/utils/type.c b/src/type/main.c similarity index 98% rename from src/utils/type.c rename to src/type/main.c index 760cf47..04c2b35 100644 --- a/src/utils/type.c +++ b/src/type/main.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * utils/type.c -- extract the G1M file type out of raw identification data. + * type/main.c -- extract the G1M file type out of raw identification data. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. diff --git a/src/utils/mcstype.c b/src/type/mcs.c similarity index 99% rename from src/utils/mcstype.c rename to src/type/mcs.c index 7615229..77f0a36 100644 --- a/src/utils/mcstype.c +++ b/src/type/mcs.c @@ -1,5 +1,5 @@ /* ***************************************************************************** - * utils/mcstype.c -- get the MCS type out of raw identification data. + * type/mcs.c -- get the MCS type out of raw identification data. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. diff --git a/src/utils/limbuffer.c b/src/utils/limbuffer.c new file mode 100644 index 0000000..36cd8ca --- /dev/null +++ b/src/utils/limbuffer.c @@ -0,0 +1,58 @@ +/* ***************************************************************************** + * utils/limbuffer.c -- limited libg1m buffer utilities. + * 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 + +/** + * g1m_limbuffer_read: + * Read from a filebuffer. + * + * @arg vcookie the FILE* (uncasted) + * @arg buf the buffer to fill. + * @arg size the size to read. + * @return the error (if any). + */ + +int g1m_limbuffer_read(void *vcookie, unsigned char *buf, size_t size) +{ + /* check if the size is okay */ + g1m_limited_t *lim = (void*)vcookie; + if (size > lim->left) return (g1m_error_eof); + g1m_buffer_t *buffer = lim->buffer; + + /* read */ + READ(buf, size) + + /* no error */ + return (0); +} + +/** + * g1m_empty_limbuffer: + * Empty the limit buffer. + * + * @arg limbuf the limbuffer. + */ + +int g1m_empty_limbuffer(g1m_buffer_t *limbuffer) +{ + g1m_limited_t *lim = (void*)limbuffer->cookie; + g1m_buffer_t *buffer = lim->buffer; + SKIP(lim->left) + return (0); +} diff --git a/src/utils/membuffer.c b/src/utils/membuffer.c index 4a941d9..a365ed7 100644 --- a/src/utils/membuffer.c +++ b/src/utils/membuffer.c @@ -31,8 +31,11 @@ int g1m_membuffer_read(void *vcookie, unsigned char *dest, size_t size) { - const unsigned char **p = (void*)vcookie; - memcpy(dest, *p, size); - *p += size; + g1m_cursor_t *cursor = (void*)vcookie; + + if (size > cursor->left) + return (g1m_error_eof); + memcpy(dest, cursor->p, size); + cursor->p += size; return (0); } diff --git a/src/utils/skip.c b/src/utils/skip.c index 04e1d6f..cad2d06 100644 --- a/src/utils/skip.c +++ b/src/utils/skip.c @@ -38,7 +38,8 @@ int g1m_skip(g1m_buffer_t *buffer, size_t size, uint_fast32_t *checksum) size_t curlen = min(size, 1024); size -= curlen; if ((err = (*buffer->read)(buffer->cookie, buf, curlen))) { - log_error("Skipping has failed after %zu bytes", size); + log_error("Skipping has failed after %" PRIuSIZE " bytes", + orig - size); return (err); }