/* ***************************************************************************** * 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 to make. * @arg buffer the buffer to read from. * @arg head the pre-filled head to complete and use. * @return the error code (0 if ok). */ int g1m_decode_mcs_spreadsheet(g1m_mcsfile_t **handle, g1m_buffer_t *buffer, g1m_mcshead_t *head) { /* read header */ DREAD(hd, g1m_mcs_spreadsheet_header_s) if (hd.g1m_mcs_spreadsheet_header_has_subheader != 0x01) return (0); /* read subheader */ DREAD(shd, g1m_mcs_spreadsheet_subheader_s) uint_fast32_t colcount = hd.g1m_mcs_spreadsheet_header_column_count; colcount = be32toh(colcount << 8); shd.g1m_mcs_spreadsheet_subheader_defs_size = be32toh(shd.g1m_mcs_spreadsheet_subheader_defs_size); /* prepare */ g1m_mcscell_t cells[1000 * colcount]; bzero(cells, sizeof(g1m_mcscell_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, g1m_mcsbcd_s) g1m_bcd_frommcs(&rawcell, &cell); /* store it */ cells[c * 1000 + i] = (g1m_mcscell_t){ .g1m_mcscell_real = cell, .g1m_mcscell_imgn = (g1m_bcd_t){}, .g1m_mcscell_flags = g1m_mcscellflag_used }; /* 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 */ head->g1m_mcshead_width = 0; head->g1m_mcshead_height = 0; if (cells_count) { head->g1m_mcshead_width = cols; head->g1m_mcshead_height = rows; } int err = g1m_make_mcsfile(handle, head); if (err) return (err); /* main copying loop */ g1m_mcscell_t **tab = (*handle)->g1m_mcsfile_cells; for (uint_fast32_t y = 0; y < head->g1m_mcshead_height; y++) for (uint_fast32_t x = 0; x < head->g1m_mcshead_width; x++) tab[y][x] = cells[x * 1000 + y]; /* no error */ return (0); }