home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Elysian Archive
/
AmigaElysianArchive.iso
/
games
/
utils
/
ztools.lha
/
ztools
/
src
/
txio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-01
|
11KB
|
418 lines
/* txio.c V1.2
*
* I/O routines for Z code disassembler and story file dumper.
*
* Mark Howell 26 August 1992 howell_ma@movies.enet.dec.com
*
* History:
* Add support for old type 3 data files with no file size in header
* Use stat to get the file length
*/
#include "tx.h"
#ifdef UNIX
#include <unistd.h>
#endif
#include <stat.h>
zbyte_t h_type;
zword_t h_version;
zword_t h_data_size;
zword_t h_start_pc;
zword_t h_words_offset;
zword_t h_objects_offset;
zword_t h_globals_offset;
zword_t h_restart_size;
zword_t h_synonyms_offset;
zword_t h_file_size;
zword_t h_checksum;
zword_t h_function_keys_offset;
zword_t h_alternate_alphabet_offset;
int story_scaler;
int story_shift;
int property_mask;
int property_size_mask;
zbyte_t *datap;
char *story_file_name = NULL;
const char *lookup_table[3] = {
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
" 0123456789.,!?_#'\"/\\-:()"
};
typedef struct cache_entry {
struct cache_entry *flink;
unsigned int page_number;
zbyte_t data[PAGE_SIZE];
} cache_entry_t;
#ifdef __STDC__
static cache_entry_t *update_cache (unsigned int page_number);
static int get_story_size (void);
#else
static cache_entry_t *update_cache ();
static int get_story_size ();
#endif
static FILE *gfp = NULL;
static unsigned int cache_pages = 0;
static cache_entry_t *cache = NULL;
static unsigned int current_data_page = 0;
static cache_entry_t *current_data_cachep = NULL;
static unsigned int data_size;
#ifdef __STDC__
void configure (int min_version, int max_version)
#else
void configure (min_version, max_version)
int min_version;
int max_version;
#endif
{
zbyte_t buffer[PAGE_SIZE];
assert (sizeof (zheader_t) <= PAGE_SIZE);
read_page (0, buffer);
datap = buffer;
h_type = get_byte (H_TYPE);
if (h_type < min_version || h_type > max_version || (get_byte (H_CONFIG) & CONFIG_BYTE_SWAPPED)) {
fprintf (stderr, "\nFatal: wrong game or version\n");
exit (EXIT_FAILURE);
}
if (h_type == V3) {
story_scaler = 2;
story_shift = 1;
property_mask = P3_MAX_PROPERTIES - 1;
property_size_mask = 0xe0;
} else if (h_type == V4 || h_type == V5) {
story_scaler = 4;
story_shift = 2;
property_mask = P4_MAX_PROPERTIES - 1;
property_size_mask = 0x3f;
} else {
story_scaler = 8;
story_shift = 3;
property_mask = P4_MAX_PROPERTIES - 1;
property_size_mask = 0x3f;
}
h_version = get_word (H_VERSION);
h_data_size = get_word (H_DATA_SIZE);
h_start_pc = get_word (H_START_PC);
h_words_offset = get_word (H_WORDS_OFFSET);
h_objects_offset = get_word (H_OBJECTS_OFFSET);
h_globals_offset = get_word (H_GLOBALS_OFFSET);
h_restart_size = get_word (H_RESTART_SIZE);
h_synonyms_offset = get_word (H_SYNONYMS_OFFSET);
h_file_size = get_word (H_FILE_SIZE);
if (h_file_size == 0)
h_file_size = get_story_size ();
h_checksum = get_word (H_CHECKSUM);
h_function_keys_offset = get_word (H_FUNCTION_KEYS_OFFSET);
h_alternate_alphabet_offset = get_word (H_ALTERNATE_ALPHABET_OFFSET);
}/* configure */
#ifdef __STDC__
void open_story (char *storyname)
#else
void open_story (storyname)
char *storyname;
#endif
{
gfp = fopen (storyname, "rb");
if (gfp == NULL) {
fprintf (stderr, "Fatal: game file not found");
exit (EXIT_FAILURE);
}
story_file_name = storyname;
}/* open_story */
#ifdef __STDC__
void close_story (void)
#else
void close_story ()
#endif
{
if (gfp != NULL)
fclose (gfp);
}/* close_story */
#ifdef __STDC__
void read_page (unsigned int page, void *buffer)
#else
void read_page (page, buffer)
unsigned int page;
zbyte_t *buffer;
#endif
{
unsigned long file_size;
unsigned int pages, offset;
fseek (gfp, (long) page * PAGE_SIZE, SEEK_SET);
if (fread (buffer, PAGE_SIZE, 1, gfp) != 1) {
file_size = (unsigned long) h_file_size * story_scaler;
pages = (unsigned int) ((unsigned long) file_size / PAGE_SIZE);
offset = (unsigned int) ((unsigned long) file_size & PAGE_MASK);
if ((unsigned int) page == pages) {
fseek (gfp, (long) page * PAGE_SIZE, SEEK_SET);
if (fread (buffer, offset, 1, gfp) == 1)
return;
}
fprintf (stderr, "Fatal: game file read error");
exit (EXIT_FAILURE);
}
}/* read_page */
#ifdef __STDC__
void load_cache (void)
#else
void load_cache ()
#endif
{
unsigned int file_pages, data_pages;
unsigned int i;
cache_entry_t *cachep, *lastp = NULL;
if (h_type == V3) {
story_scaler = 2;
story_shift = 1;
} else {
story_scaler = 4;
story_shift = 2;
}
file_pages = (h_file_size >> (PAGE_SHIFT - story_shift)) + 1;
data_pages = (h_data_size + PAGE_MASK) >> PAGE_SHIFT;
cache_pages = file_pages - data_pages;
data_size = data_pages * PAGE_SIZE;
datap = (zbyte_t *) malloc (data_size);
if (datap == NULL) {
fprintf (stderr, "Fatal: insufficient memory to play game");
exit (EXIT_FAILURE);
}
for (i = 0; i < data_pages; i++)
read_page (i, &datap[i * PAGE_SIZE]);
for (i = 0; i < cache_pages; i++) {
cachep = (cache_entry_t *) malloc (sizeof (cache_entry_t));
if (cachep == NULL) {
cache_pages = i;
i = 512 + 1;
} else {
if (i == 0)
cache = cachep;
else
lastp->flink = cachep;
cachep->flink = NULL;
cachep->page_number = data_pages + i;
lastp = cachep;
read_page (cachep->page_number, cachep->data);
}
}
}/* load_cache */
#ifdef __STDC__
zword_t read_data_word (unsigned long *addr)
#else
zword_t read_data_word (addr)
unsigned long *addr;
#endif
{
zword_t w;
w = (zword_t) read_data_byte (addr) << 8;
w |= (zword_t) read_data_byte (addr);
return (w);
}/* read_data_word */
#ifdef __STDC__
zbyte_t read_data_byte (unsigned long *addr)
#else
zbyte_t read_data_byte (addr)
unsigned long *addr;
#endif
{
unsigned int page_number, page_offset;
zbyte_t value;
if (*addr < (unsigned long) data_size)
value = datap[*addr];
else {
page_number = (int) (*addr >> PAGE_SHIFT);
page_offset = (int) *addr & PAGE_MASK;
if (page_number != current_data_page) {
current_data_cachep = update_cache (page_number);
current_data_page = page_number;
}
value = current_data_cachep->data[page_offset];
}
(*addr)++;
return (value);
}/* read_data_byte */
#ifdef __STDC__
int decode_text (unsigned long *address)
#else
int decode_text (address)
unsigned long *address;
#endif
{
int i, synonym_flag = 0, ascii_flag = 0, char_count = 0;
short data, code, sindex = 0;
short prefix = 0, saved_prefix = 0;
unsigned long addr;
do {
data = read_data_word (address);
for (i = 10; i >= 0; i -= 5) {
code = (data >> i) & 0x1f;
if (synonym_flag == TRUE) {
synonym_flag = FALSE;
addr = (unsigned long) get_word (h_synonyms_offset + sindex + (code * 2)) * 2;
char_count += decode_text (&addr);
prefix = saved_prefix;
} else {
if (prefix == 3 || ascii_flag == TRUE) {
if (ascii_flag == TRUE) {
ascii_flag = FALSE;
putchar (((prefix & 3) << 5) | code);
char_count++;
prefix = saved_prefix;
} else {
ascii_flag = TRUE;
prefix = code;
}
} else {
if (code >= 6) {
if (prefix == 2 && code <= 7) {
if (code != 7)
prefix++;
else {
putchar ('\n');
char_count++;
prefix = saved_prefix;
}
} else {
putchar (lookup_table[prefix][code - 6]);
char_count++;
prefix = saved_prefix;
}
} else {
if (code == 0) {
putchar (' ');
char_count++;
prefix = saved_prefix;
} else {
if (code <= 3) {
synonym_flag = TRUE;
sindex = (code - 1) * 64;
} else {
code -= 3;
if (prefix == 0)
prefix = code;
else {
if (code != prefix)
prefix = 0;
saved_prefix = prefix;
}
}
}
}
}
}
}
} while (data >= 0);
return (char_count);
}/* decode_text */
#ifdef __STDC__
static cache_entry_t *update_cache (unsigned int page_number)
#else
static cache_entry_t *update_cache (page_number)
unsigned int page_number;
#endif
{
cache_entry_t *cachep, *lastp;
for (lastp = cache, cachep = cache;
cachep->flink != NULL &&
cachep->page_number &&
cachep->page_number != page_number;
lastp = cachep, cachep = cachep->flink)
;
if (cachep->page_number != page_number) {
if (cachep->flink == NULL && cachep->page_number) {
if (current_data_page == (unsigned int) cachep->page_number)
current_data_page = 0;
}
cachep->page_number = page_number;
read_page (page_number, cachep->data);
}
if (lastp != cache) {
lastp->flink = cachep->flink;
cachep->flink = cache;
cache = cachep;
}
return (cachep);
}/* update_cache */
/*
* get_story_size
*
* Calculate the size of the game file. Only used for very old games that do not
* have the game file size in the header.
*
*/
#ifdef __STDC__
int get_story_size (void)
#else
int get_story_size ()
#endif
{
struct stat statbuf;
unsigned long file_length;
if (stat (story_file_name, &statbuf)) {
fprintf (stderr, "stat on story file failed.\n");
exit (EXIT_FAILURE);
}
file_length = statbuf.st_size;
/* Calculate length of file in game allocation units */
file_length = (file_length + (unsigned long) (story_scaler - 1)) / (unsigned long) story_scaler;
return ((int) file_length);
}/* get_story_size */