home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / games / utils / ztools.lha / ztools / src / txio.c < prev    next >
C/C++ Source or Header  |  1993-03-01  |  11KB  |  418 lines

  1. /* txio.c V1.2
  2.  *
  3.  * I/O routines for Z code disassembler and story file dumper.
  4.  *
  5.  * Mark Howell 26 August 1992 howell_ma@movies.enet.dec.com
  6.  *
  7.  * History:
  8.  *     Add support for old type 3 data files with no file size in header
  9.  *     Use stat to get the file length
  10.  */
  11.  
  12. #include "tx.h"
  13. #ifdef UNIX
  14. #include <unistd.h>
  15. #endif
  16. #include <stat.h>
  17.  
  18. zbyte_t h_type;
  19. zword_t h_version;
  20. zword_t h_data_size;
  21. zword_t h_start_pc;
  22. zword_t h_words_offset;
  23. zword_t h_objects_offset;
  24. zword_t h_globals_offset;
  25. zword_t h_restart_size;
  26. zword_t h_synonyms_offset;
  27. zword_t h_file_size;
  28. zword_t h_checksum;
  29. zword_t h_function_keys_offset;
  30. zword_t h_alternate_alphabet_offset;
  31.  
  32. int story_scaler;
  33. int story_shift;
  34. int property_mask;
  35. int property_size_mask;
  36.  
  37. zbyte_t *datap;
  38.  
  39. char *story_file_name = NULL;
  40.  
  41. const char *lookup_table[3] = {
  42.     "abcdefghijklmnopqrstuvwxyz",
  43.     "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  44.     "  0123456789.,!?_#'\"/\\-:()"
  45. };
  46.  
  47. typedef struct cache_entry {
  48.     struct cache_entry *flink;
  49.     unsigned int page_number;
  50.     zbyte_t data[PAGE_SIZE];
  51. } cache_entry_t;
  52.  
  53. #ifdef __STDC__
  54. static cache_entry_t *update_cache (unsigned int page_number);
  55. static int get_story_size (void);
  56. #else
  57. static cache_entry_t *update_cache ();
  58. static int get_story_size ();
  59. #endif
  60.  
  61. static FILE *gfp = NULL;
  62.  
  63. static unsigned int cache_pages = 0;
  64. static cache_entry_t *cache = NULL;
  65.  
  66. static unsigned int current_data_page = 0;
  67. static cache_entry_t *current_data_cachep = NULL;
  68.  
  69. static unsigned int data_size;
  70.  
  71. #ifdef __STDC__
  72. void configure (int min_version, int max_version)
  73. #else
  74. void configure (min_version, max_version)
  75. int min_version;
  76. int max_version;
  77. #endif
  78. {
  79.     zbyte_t buffer[PAGE_SIZE];
  80.  
  81.     assert (sizeof (zheader_t) <= PAGE_SIZE);
  82.  
  83.     read_page (0, buffer);
  84.     datap = buffer;
  85.  
  86.     h_type = get_byte (H_TYPE);
  87.  
  88.     if (h_type < min_version || h_type > max_version || (get_byte (H_CONFIG) & CONFIG_BYTE_SWAPPED)) {
  89.         fprintf (stderr, "\nFatal: wrong game or version\n");
  90.         exit (EXIT_FAILURE);
  91.     }
  92.  
  93.     if (h_type == V3) {
  94.         story_scaler = 2;
  95.         story_shift = 1;
  96.         property_mask = P3_MAX_PROPERTIES - 1;
  97.         property_size_mask = 0xe0;
  98.     } else if (h_type == V4 || h_type == V5) {
  99.         story_scaler = 4;
  100.         story_shift = 2;
  101.         property_mask = P4_MAX_PROPERTIES - 1;
  102.         property_size_mask = 0x3f;
  103.     } else {
  104.         story_scaler = 8;
  105.         story_shift = 3;
  106.         property_mask = P4_MAX_PROPERTIES - 1;
  107.         property_size_mask = 0x3f;
  108.     }
  109.  
  110.     h_version = get_word (H_VERSION);
  111.     h_data_size = get_word (H_DATA_SIZE);
  112.     h_start_pc = get_word (H_START_PC);
  113.     h_words_offset = get_word (H_WORDS_OFFSET);
  114.     h_objects_offset = get_word (H_OBJECTS_OFFSET);
  115.     h_globals_offset = get_word (H_GLOBALS_OFFSET);
  116.     h_restart_size = get_word (H_RESTART_SIZE);
  117.     h_synonyms_offset = get_word (H_SYNONYMS_OFFSET);
  118.     h_file_size = get_word (H_FILE_SIZE);
  119.     if (h_file_size == 0)
  120.         h_file_size = get_story_size ();
  121.     h_checksum = get_word (H_CHECKSUM);
  122.     h_function_keys_offset = get_word (H_FUNCTION_KEYS_OFFSET);
  123.     h_alternate_alphabet_offset = get_word (H_ALTERNATE_ALPHABET_OFFSET);
  124.  
  125. }/* configure */
  126.  
  127. #ifdef __STDC__
  128. void open_story (char *storyname)
  129. #else
  130. void open_story (storyname)
  131. char *storyname;
  132. #endif
  133. {
  134.  
  135.     gfp = fopen (storyname, "rb");
  136.     if (gfp == NULL) {
  137.         fprintf (stderr, "Fatal: game file not found");
  138.         exit (EXIT_FAILURE);
  139.     }
  140.  
  141.     story_file_name = storyname;
  142.  
  143. }/* open_story */
  144.  
  145. #ifdef __STDC__
  146. void close_story (void)
  147. #else
  148. void close_story ()
  149. #endif
  150. {
  151.  
  152.     if (gfp != NULL)
  153.         fclose (gfp);
  154.  
  155. }/* close_story */
  156.  
  157. #ifdef __STDC__
  158. void read_page (unsigned int page, void *buffer)
  159. #else
  160. void read_page (page, buffer)
  161. unsigned int page;
  162. zbyte_t *buffer;
  163. #endif
  164. {
  165.     unsigned long file_size;
  166.     unsigned int pages, offset;
  167.  
  168.     fseek (gfp, (long) page * PAGE_SIZE, SEEK_SET);
  169.     if (fread (buffer, PAGE_SIZE, 1, gfp) != 1) {
  170.         file_size = (unsigned long) h_file_size * story_scaler;
  171.         pages = (unsigned int) ((unsigned long) file_size / PAGE_SIZE);
  172.         offset = (unsigned int) ((unsigned long) file_size & PAGE_MASK);
  173.         if ((unsigned int) page == pages) {
  174.             fseek (gfp, (long) page * PAGE_SIZE, SEEK_SET);
  175.             if (fread (buffer, offset, 1, gfp) == 1)
  176.                 return;
  177.         }
  178.         fprintf (stderr, "Fatal: game file read error");
  179.         exit (EXIT_FAILURE);
  180.     }
  181.  
  182. }/* read_page */
  183.  
  184. #ifdef __STDC__
  185. void load_cache (void)
  186. #else
  187. void load_cache ()
  188. #endif
  189. {
  190.     unsigned int file_pages, data_pages;
  191.     unsigned int i;
  192.     cache_entry_t *cachep, *lastp = NULL;
  193.  
  194.     if (h_type == V3) {
  195.         story_scaler = 2;
  196.         story_shift = 1;
  197.     } else {
  198.         story_scaler = 4;
  199.         story_shift = 2;
  200.     }
  201.  
  202.     file_pages = (h_file_size >> (PAGE_SHIFT - story_shift)) + 1;
  203.     data_pages = (h_data_size + PAGE_MASK) >> PAGE_SHIFT;
  204.     cache_pages = file_pages - data_pages;
  205.  
  206.     data_size = data_pages * PAGE_SIZE;
  207.     datap = (zbyte_t *) malloc (data_size);
  208.     if (datap == NULL) {
  209.         fprintf (stderr, "Fatal: insufficient memory to play game");
  210.         exit (EXIT_FAILURE);
  211.     }
  212.     for (i = 0; i < data_pages; i++)
  213.         read_page (i, &datap[i * PAGE_SIZE]);
  214.  
  215.     for (i = 0; i < cache_pages; i++) {
  216.         cachep = (cache_entry_t *) malloc (sizeof (cache_entry_t));
  217.         if (cachep == NULL) {
  218.             cache_pages = i;
  219.             i = 512 + 1;
  220.         } else {
  221.             if (i == 0)
  222.                 cache = cachep;
  223.             else
  224.                 lastp->flink = cachep;
  225.             cachep->flink = NULL;
  226.             cachep->page_number = data_pages + i;
  227.             lastp = cachep;
  228.             read_page (cachep->page_number, cachep->data);
  229.         }
  230.     }
  231.  
  232. }/* load_cache */
  233.  
  234. #ifdef __STDC__
  235. zword_t read_data_word (unsigned long *addr)
  236. #else
  237. zword_t read_data_word (addr)
  238. unsigned long *addr;
  239. #endif
  240. {
  241.     zword_t w;
  242.  
  243.     w = (zword_t) read_data_byte (addr) << 8;
  244.     w |= (zword_t) read_data_byte (addr);
  245.  
  246.     return (w);
  247.  
  248. }/* read_data_word */
  249.  
  250. #ifdef __STDC__
  251. zbyte_t read_data_byte (unsigned long *addr)
  252. #else
  253. zbyte_t read_data_byte (addr)
  254. unsigned long *addr;
  255. #endif
  256. {
  257.     unsigned int page_number, page_offset;
  258.     zbyte_t value;
  259.  
  260.     if (*addr < (unsigned long) data_size)
  261.         value = datap[*addr];
  262.     else {
  263.         page_number = (int) (*addr >> PAGE_SHIFT);
  264.         page_offset = (int) *addr & PAGE_MASK;
  265.         if (page_number != current_data_page) {
  266.             current_data_cachep = update_cache (page_number);
  267.         current_data_page = page_number;
  268.         }
  269.         value = current_data_cachep->data[page_offset];
  270.     }
  271.     (*addr)++;
  272.  
  273.     return (value);
  274.  
  275. }/* read_data_byte */
  276.  
  277. #ifdef __STDC__
  278. int decode_text (unsigned long *address)
  279. #else
  280. int decode_text (address)
  281. unsigned long *address;
  282. #endif
  283. {
  284.     int i, synonym_flag = 0, ascii_flag = 0, char_count = 0;
  285.     short data, code, sindex = 0;
  286.     short prefix = 0, saved_prefix = 0;
  287.     unsigned long addr;
  288.  
  289.     do {
  290.         data = read_data_word (address);
  291.         for (i = 10; i >= 0; i -= 5) {
  292.             code = (data >> i) & 0x1f;
  293.             if (synonym_flag == TRUE) {
  294.                 synonym_flag = FALSE;
  295.                 addr = (unsigned long) get_word (h_synonyms_offset + sindex + (code * 2)) * 2;
  296.                 char_count += decode_text (&addr);
  297.                 prefix = saved_prefix;
  298.             } else {
  299.                 if (prefix == 3 || ascii_flag == TRUE) {
  300.                     if (ascii_flag == TRUE) {
  301.                         ascii_flag = FALSE;
  302.                         putchar (((prefix & 3) << 5) | code);
  303.                         char_count++;
  304.                         prefix = saved_prefix;
  305.                     } else {
  306.                         ascii_flag = TRUE;
  307.                         prefix = code;
  308.                     }
  309.                 } else {
  310.                     if (code >= 6) {
  311.                         if (prefix == 2 && code <= 7) {
  312.                             if (code != 7)
  313.                                 prefix++;
  314.                             else {
  315.                                 putchar ('\n');
  316.                                 char_count++;
  317.                                 prefix = saved_prefix;
  318.                             }
  319.                         } else {
  320.                             putchar (lookup_table[prefix][code - 6]);
  321.                             char_count++;
  322.                             prefix = saved_prefix;
  323.                         }
  324.                     } else {
  325.                         if (code == 0) {
  326.                             putchar (' ');
  327.                             char_count++;
  328.                             prefix = saved_prefix;
  329.                         } else {
  330.                             if (code <= 3) {
  331.                                 synonym_flag = TRUE;
  332.                                 sindex = (code - 1) * 64;
  333.                             } else {
  334.                                 code -= 3;
  335.                                 if (prefix == 0)
  336.                                     prefix = code;
  337.                                 else {
  338.                                     if (code != prefix)
  339.                                         prefix = 0;
  340.                                     saved_prefix = prefix;
  341.                                 }
  342.                             }
  343.                         }
  344.                     }
  345.                 }
  346.             }
  347.         }
  348.     } while (data >= 0);
  349.  
  350.     return (char_count);
  351.  
  352. }/* decode_text */
  353.  
  354. #ifdef __STDC__
  355. static cache_entry_t *update_cache (unsigned int page_number)
  356. #else
  357. static cache_entry_t *update_cache (page_number)
  358. unsigned int page_number;
  359. #endif
  360. {
  361.     cache_entry_t *cachep, *lastp;
  362.  
  363.     for (lastp = cache, cachep = cache;
  364.          cachep->flink != NULL &&
  365.          cachep->page_number &&
  366.          cachep->page_number != page_number;
  367.          lastp = cachep, cachep = cachep->flink)
  368.         ;
  369.     if (cachep->page_number != page_number) {
  370.         if (cachep->flink == NULL && cachep->page_number) {
  371.             if (current_data_page == (unsigned int) cachep->page_number)
  372.                 current_data_page = 0;
  373.         }
  374.         cachep->page_number = page_number;
  375.         read_page (page_number, cachep->data);
  376.     }
  377.     if (lastp != cache) {
  378.         lastp->flink = cachep->flink;
  379.         cachep->flink = cache;
  380.         cache = cachep;
  381.     }
  382.  
  383.     return (cachep);
  384.  
  385. }/* update_cache */
  386.  
  387. /*
  388.  * get_story_size
  389.  *
  390.  * Calculate the size of the game file. Only used for very old games that do not
  391.  * have the game file size in the header.
  392.  *
  393.  */
  394.  
  395. #ifdef __STDC__
  396. int get_story_size (void)
  397. #else
  398. int get_story_size ()
  399. #endif
  400. {
  401.     struct stat statbuf;
  402.     unsigned long file_length;
  403.  
  404.     if (stat (story_file_name, &statbuf)) {
  405.         fprintf (stderr, "stat on story file failed.\n");
  406.         exit (EXIT_FAILURE);
  407.     }
  408.  
  409.     file_length = statbuf.st_size;
  410.  
  411.     /* Calculate length of file in game allocation units */
  412.  
  413.     file_length = (file_length + (unsigned long) (story_scaler - 1)) / (unsigned long) story_scaler;
  414.  
  415.     return ((int) file_length);
  416.  
  417. }/* get_story_size */
  418.