Added basic parsing of storage files
This commit is contained in:
parent
a11dc9e42b
commit
ddd98ff9c4
|
@ -10,14 +10,140 @@
|
|||
#ifndef LIBG1M_FORMAT_STORAGE_H
|
||||
# define LIBG1M_FORMAT_STORAGE_H
|
||||
|
||||
/* Storage files (G1S) contain backups of the storage memory.
|
||||
/* Storage backup files (G1S) contain backups of the storage memory.
|
||||
* It corresponds exactly to the on-calc storage memory structure.
|
||||
*
|
||||
* According to Simon Lothar, the files contain zeroes up to 0x00270000
|
||||
* (the location of the MCS in real fx-9860 calculators), then it has the
|
||||
* same structure than on the calculator. These files exist because FA-124
|
||||
* implements Bfile as well as the calculator (brilliant, huh?).
|
||||
* (including the StandardHeader; this is the location of the SMEM in real
|
||||
* fx-9860 calculators), then it has the same structure than the one
|
||||
* used by the calculator.
|
||||
*
|
||||
* The structure has been documented by Simon Lothar, but I haven't
|
||||
* worked on it yet: TODO. */
|
||||
* It looks like these files are not managed by the calculator (not directly);
|
||||
* however, they are managed by FA-124. */
|
||||
/* ************************************************************************** */
|
||||
/* Directory list */
|
||||
/* ************************************************************************** */
|
||||
/* The SMEM (content of the G1S file once 0x270000 bytes were skipped) starts
|
||||
* with a big entry list. An entry is 32-bytes long: it starts with a common
|
||||
* part, then with a type-specific part (then unused bytes if the subheader
|
||||
* is less than 28-bytes long). Here is its structure: */
|
||||
|
||||
struct storage_entry {
|
||||
/* the type number - see below */
|
||||
uint16_t type;
|
||||
|
||||
/* the unique number of the entry */
|
||||
uint16_t uuid;
|
||||
|
||||
/* the raw subheader */
|
||||
uint8_t raw_subheader[28];
|
||||
};
|
||||
|
||||
/* The `type` is composed of three nibbles of identification (`type & 0xFFF`)
|
||||
* and a (high) nibble of special properties, keep that in mind.
|
||||
* Here are the known types: */
|
||||
|
||||
enum storage_entry_type {
|
||||
storage_entrytype_sector = 0x200,
|
||||
storage_entrytype_directory = 0x110,
|
||||
storage_entrytype_file = 0x120,
|
||||
storage_entrytype_fragment = 0x130,
|
||||
};
|
||||
|
||||
/* There is no count of the entries, but there is a terminating entry,
|
||||
* identified by its type being 0xFFFF. */
|
||||
/* ************************************************************************** */
|
||||
/* Sectors */
|
||||
/* ************************************************************************** */
|
||||
/* Sectors represent the physical sectors of the storage memory (space!).
|
||||
* Simon Lothar says that there are 27 entries for them (or 25 "not on the
|
||||
* AU" in the other documentation, whatever that means).
|
||||
*
|
||||
* Their special nibble is either 0x04 or 0x00, I don't know why yet.
|
||||
* Here is their subheader structure: */
|
||||
|
||||
struct storage_sector {
|
||||
/* the sector start address - 0xFF */
|
||||
uint32_t startaddr;
|
||||
|
||||
/* the sector ID - because for some reason, fragments won't use the uuid */
|
||||
uint32_t logical_sector_number;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Directories */
|
||||
/* ************************************************************************** */
|
||||
/* After the sectors come the directories.
|
||||
*
|
||||
* Their special nibble is either 0x05 if active or 0x00 if deleted.
|
||||
* Here is their subheader structure: */
|
||||
|
||||
struct storage_directory {
|
||||
/* the directory reference - looks unusable */
|
||||
uint32_t directory_reference;
|
||||
|
||||
/* the name (FONTCHARACTER-encoded) */
|
||||
FONTCHARACTER name[12];
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Files */
|
||||
/* ************************************************************************** */
|
||||
/* After the directories come the files (interrupted by fragments - see after).
|
||||
*
|
||||
* Their special nibble have the same meaning that for directories.
|
||||
* Here is their subheader structure: */
|
||||
|
||||
struct storage_file {
|
||||
/* the directory reference
|
||||
* - is `storage_entrytype_directory` if the file is in a subdirectory.
|
||||
* - is 0xFFFF otherwise. */
|
||||
uint16_t directory_reference;
|
||||
|
||||
/* the directory number - should be read only if is in a subdirectory. */
|
||||
uint16_t directory_number;
|
||||
|
||||
/* the name (FONTCHARACTER-encoded) */
|
||||
FONTCHARACTER name[12];
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* File fragments */
|
||||
/* ************************************************************************** */
|
||||
/* After each file entry comes the corresponding fragments entries.
|
||||
* Fragments are in fact links to the sectors, with some more info.
|
||||
*
|
||||
* Their special nibble have the same meaning that for files... but are not
|
||||
* always accurate, so only check on files.
|
||||
* Here is their subheader structure: */
|
||||
|
||||
struct storage_fragment {
|
||||
/* the file ID */
|
||||
uint32_t file_uuid;
|
||||
|
||||
/* the file type (probably detected when the file is transferred):
|
||||
* - 0x01 for an unknown type;
|
||||
* - 0x02 for an add-in (G1A);
|
||||
* - 0x06 for an MCS archive (G1M);
|
||||
* - 0x2E for an MCS archive with setup (G1R).
|
||||
*
|
||||
* why is it here and not in the file entry data? you've got a point. */
|
||||
uint16_t file_type;
|
||||
|
||||
/* the fragment count */
|
||||
uint16_t fragment_count;
|
||||
|
||||
/* the fragment number */
|
||||
uint16_t fragment_id;
|
||||
|
||||
/* the sector id that the fragment is linked to */
|
||||
uint16_t fragment_sector_id;
|
||||
|
||||
/* offset of the used bytes in sector */
|
||||
uint16_t used_bytes_offset;
|
||||
|
||||
/* number of used bytes in sector */
|
||||
uint16_t used_bytes;
|
||||
};
|
||||
|
||||
#endif /* LIBG1M_FORMAT_STORAGE_H */
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#define SUB(V, TYPE) \
|
||||
case storage_entrytype_##TYPE:; \
|
||||
struct storage_##TYPE *V = (struct storage_##TYPE*)&entry.raw_subheader;
|
||||
|
||||
/**
|
||||
* g1m_parse_storage:
|
||||
|
@ -23,12 +26,89 @@ int g1m_parse_storage(g1m_t *handle, FILE *stream,
|
|||
struct standard_header *std)
|
||||
{
|
||||
(void)std;
|
||||
handle->type = 0x00;
|
||||
/* skip the first 0x270000 - 0x20 bytes */
|
||||
SKIP(0x270000 - sizeof(struct standard_header))
|
||||
|
||||
/* then read and stuff... not yet. */
|
||||
log_error("Storage files are not managed yet.");
|
||||
handle->type = 0x00;
|
||||
/* read */
|
||||
log_info("Storage memory!");
|
||||
|
||||
/* read the entries */
|
||||
#if LOGLEVEL <= ll_info
|
||||
for (int id = 1;; id++) {
|
||||
#else
|
||||
for (;;) {
|
||||
#endif
|
||||
/* read the entry */
|
||||
DREAD(entry, storage_entry)
|
||||
if (entry.type == 0xFFFF)
|
||||
break;
|
||||
entry.type = be16toh(entry.type);
|
||||
entry.uuid = be16toh(entry.uuid);
|
||||
|
||||
/* read it */
|
||||
int special = (entry.type & 0xF000) >> 12;
|
||||
switch (entry.type & 0xFFF) {
|
||||
SUB(sh, sector)
|
||||
int unused = (sh->logical_sector_number == 0xFFFFFFFF);
|
||||
log_info("[%02d,%02" PRIu16 "] Is a%ssector.", id, entry.uuid,
|
||||
(unused) ? "n unused " : " ");
|
||||
log_info("- Starts at address 0x%08" PRIx32,
|
||||
be32toh(sh->startaddr));
|
||||
#if LOGLEVEL <= ll_info
|
||||
if (!unused) log_info("- Logical number: 0x%08" PRIu32,
|
||||
be32toh(sh->logical_sector_number));
|
||||
#endif
|
||||
break;
|
||||
SUB(dh, directory)
|
||||
log_info("[%02d,%02" PRIu16 "] Is a %s directory.", id, entry.uuid,
|
||||
(special == 0x05) ? "deleted" : "active");
|
||||
#if LOGLEVEL <= ll_info
|
||||
FONTCHARACTER rawdir[13]; rawdir[12] = 0;
|
||||
memcpy(rawdir, dh->name, 12 * sizeof(FONTCHARACTER));
|
||||
{
|
||||
int i;
|
||||
for (i = 0; rawdir[i] != 0xffff && i < 12; i++)
|
||||
rawdir[i] = be16toh(rawdir[i]);
|
||||
rawdir[i] = 0;
|
||||
}
|
||||
char dirname[25]; g1m_fcstombs(dirname, rawdir, 0);
|
||||
log_info("- Directory name: %s", dirname);
|
||||
#endif
|
||||
break;
|
||||
SUB(fh, file)
|
||||
log_info("[%02d,%02" PRIu16 "] Is a %s file.", id, entry.uuid,
|
||||
(special == 0x05) ? "deleted" : "active");
|
||||
#if LOGLEVEL <= ll_inf
|
||||
FONTCHARACTER rawname[13]; rawname[12] = 0;
|
||||
memcpy(rawname, fh->name, 12 * sizeof(FONTCHARACTER));
|
||||
{
|
||||
int i;
|
||||
for (i = 0; rawname[i] != 0xffff && i < 12; i++)
|
||||
rawname[i] = be16toh(rawname[i]);
|
||||
rawname[i] = 0;
|
||||
}
|
||||
char name[25]; g1m_fcstombs(name, rawname, 0);
|
||||
log_info("- File name: %s", name);
|
||||
#endif
|
||||
log_info("- Directory ref: %" PRIu16,
|
||||
be16toh(fh->directory_reference));
|
||||
log_info("- Directory num: %" PRIu16,
|
||||
be16toh(fh->directory_number));
|
||||
break;
|
||||
SUB(fgh, fragment)
|
||||
log_info("[%02d,%02" PRIu16 "] Is a fragment.", id, entry.uuid);
|
||||
log_info("- Points at sector #%" PRIu16,
|
||||
be16toh(fgh->fragment_sector_id));
|
||||
log_info("- Is %" PRIu16 "/%" PRIu16
|
||||
" (%" PRIu16 "o at offset 0x%04" PRIx16 ")",
|
||||
be16toh(fgh->fragment_id), be16toh(fgh->fragment_count),
|
||||
be16toh(fgh->used_bytes), be16toh(fgh->used_bytes_offset));
|
||||
break;
|
||||
default:
|
||||
log_info("[%02d,%02" PRIu16 "] Is unknown.", id, entry.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
|
|
|
@ -120,7 +120,7 @@ struct ext_corresp {
|
|||
|
||||
/* Extension correspondances */
|
||||
static struct ext_corresp ext_types[] = {
|
||||
/* raw MCS */
|
||||
/* storage files */
|
||||
{"g1s", "Storage file", g1m_platform_none, g1m_type_storage},
|
||||
|
||||
/* fx types with non-checked header */
|
||||
|
|
Reference in New Issue