/* ***************************************************************************** * decode/storage.c -- decode a storage 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 #define MAX_SECTORS 27 #define SUB(V, TYPE) \ case storage_entrytype_##TYPE:; struct storage_##TYPE *V = \ (struct storage_##TYPE*)&entry->raw_subheader; /* ************************************************************************** */ /* Main functions */ /* ************************************************************************** */ /** * g1m_decode_storage: * Decode storage files. * * @arg handle the libg1m handle to make. * @arg buffer the buffer to read from. * @return the error code (0 if ok). */ int g1m_decode_storage(g1m_handle_t **h, g1m_buffer_t *buffer) { (void)std; int err, ret = 0; handle->type = 0x00; log_info("Storage memory!"); /* go to offset 0x270000 of the file */ SKIP(0x270000) /* get the entries */ struct storage_entry storage_entries[0x800]; READ(storage_entries, 0x800 * sizeof(struct storage_entry)) /* read the sectors and directories */ uint32_t sectors[MAX_SECTORS] = {NULL}; /* sectors offsets */ uint32_t max_sector_end = 0; for (int id = 0; id < 0x800; id++) { struct storage_entry *entry = storage_entries[id]; entry->type = be16toh(entry.type); entry->uuid = be16toh(entry.uuid); int special = (entry.type & 0xF000) >> 12; switch (entry.type & 0xFFF) { SUB(sh, sector) uint32_t addr = be32toh(sh->startaddr); uint32_t logical = be32toh(sh->logical_sector_number); if (addr > max_sector_end) max_sector_end = addr; if (logical != 0xFFFFFFFF) sectors[logical] - 0x290000; break; SUB(dh, directory) break; } } /* correct sector end, and calculate how much data we need to gather */ max_sector_end = max_sector_end + 0x10000; uint8_t *buf = malloc(max_sector_end - 0x290000); if (!buf) return (g1m_error_alloc); GREAD(buf, max_sector_end - 0x290000); /* look for files and fragments */ for (int id = 0; id < 0x800; id++) { struct storage_entry *entry = storage_entries[id]; /* check that entry is a directory */ if ((entry->type & 0xFFF) != storage_entrytype_file || !entry->uuid) continue; int special = (entry.type & 0xF000) >> 12; /* get subheader */ struct storage_file *fh = (struct storage_file*)entry->raw_subheader; fh->directory_reference = be16toh(fh->directory_number); fh->directory_number = be16toh(fh->directory_number); /* check if is in a directory */ unsigned int indir = 0; //if (fh->directory_reference != 0xFFFF && if (fh->directory_reference == storage_entrytype_directory) indir = fh->directory_number; /* work out */ uint_fast32_t size = 0; int id_f = id; for (; id_f < 0x800; id_f++) { /* check that entry is fragment */ struct storage_entry *entry = storage_entries[id_f]; if ((entry.type & 0xFFF) != storage_entrytype_fragment) break; /* add size */ size += used_bytes; } } /* no error */ ret = 0; fail: free(buf); return (ret); }