diff options
Diffstat (limited to 'engines/glk/adrift/sctaffil.cpp')
-rw-r--r-- | engines/glk/adrift/sctaffil.cpp | 944 |
1 files changed, 450 insertions, 494 deletions
diff --git a/engines/glk/adrift/sctaffil.cpp b/engines/glk/adrift/sctaffil.cpp index c8a25edaeb..f365a7fa46 100644 --- a/engines/glk/adrift/sctaffil.cpp +++ b/engines/glk/adrift/sctaffil.cpp @@ -27,15 +27,15 @@ #include "common/memstream.h" #if defined(USE_ZLIB) - #ifdef __SYMBIAN32__ - #include <zlib\zlib.h> - #else - #include <zlib.h> - #endif - - #if ZLIB_VERNUM < 0x1204 - #error Version 1.2.0.4 or newer of zlib is required for this code - #endif +#ifdef __SYMBIAN32__ +#include <zlib\zlib.h> +#else +#include <zlib.h> +#endif + +#if ZLIB_VERNUM < 0x1204 +#error Version 1.2.0.4 or newer of zlib is required for this code +#endif #endif namespace Glk { @@ -49,14 +49,14 @@ namespace Adrift { /* Assorted definitions and constants. */ static const sc_uint TAF_MAGIC = 0x5bdcfa41; -enum -{ VERSION_HEADER_SIZE = 14, - V400_HEADER_EXTRA = 8 +enum { + VERSION_HEADER_SIZE = 14, + V400_HEADER_EXTRA = 8 }; -enum -{ OUT_BUFFER_SIZE = 31744, - IN_BUFFER_SIZE = 16384, - GROW_INCREMENT = 8 +enum { + OUT_BUFFER_SIZE = 31744, + IN_BUFFER_SIZE = 16384, + GROW_INCREMENT = 8 }; static const sc_char NEWLINE = '\n'; static const sc_char CARRIAGE_RETURN = '\r'; @@ -64,17 +64,20 @@ static const sc_char NUL = '\0'; /* Version 4.0, version 3.9, and version 3.8 TAF file signatures. */ static const sc_byte - V400_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, - 0xc2, 0xcf, 0x93, 0x45, 0x3e, 0x61, - 0x39, 0xfa}; +V400_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, + 0xc2, 0xcf, 0x93, 0x45, 0x3e, 0x61, + 0x39, 0xfa + }; static const sc_byte - V390_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, - 0xc2, 0xcf, 0x94, 0x45, 0x37, 0x61, - 0x39, 0xfa}; +V390_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, + 0xc2, 0xcf, 0x94, 0x45, 0x37, 0x61, + 0x39, 0xfa + }; static const sc_byte - V380_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, - 0xc2, 0xcf, 0x94, 0x45, 0x36, 0x61, - 0x39, 0xfa}; +V380_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, + 0xc2, 0xcf, 0x94, 0x45, 0x36, 0x61, + 0x39, 0xfa + }; /* * Game TAF data structure. The game structure contains the original TAF @@ -87,22 +90,21 @@ static const sc_byte * header. So for files of this type, the header is all zeroes. */ struct sc_slabdesc_t { - sc_byte *data; - sc_int size; + sc_byte *data; + sc_int size; }; typedef sc_slabdesc_t *sc_slabdescref_t; -typedef struct sc_taf_s -{ - sc_uint magic; - sc_byte header[VERSION_HEADER_SIZE + V400_HEADER_EXTRA]; - sc_int version; - sc_int total_in_bytes; - sc_slabdescref_t slabs; - sc_int slab_count; - sc_int slabs_allocated; - sc_bool is_unterminated; - sc_int current_slab; - sc_int current_offset; +typedef struct sc_taf_s { + sc_uint magic; + sc_byte header[VERSION_HEADER_SIZE + V400_HEADER_EXTRA]; + sc_int version; + sc_int total_in_bytes; + sc_slabdescref_t slabs; + sc_int slab_count; + sc_int slabs_allocated; + sc_bool is_unterminated; + sc_int current_slab; + sc_int current_offset; } sc_taf_t; @@ -124,18 +126,16 @@ static sc_int taf_random_state = 0x00a09e86; * range 0..254. Thanks to Rik Snel for uncovering this obfuscation. */ static sc_byte -taf_random (void) -{ - /* Generate and return the next pseudo-random number. */ - taf_random_state = (taf_random_state * PRNG_CST1 + PRNG_CST2) & PRNG_CST3; - return (UCHAR_MAX * (sc_uint) taf_random_state) / (sc_uint) (PRNG_CST3 + 1); +taf_random(void) { + /* Generate and return the next pseudo-random number. */ + taf_random_state = (taf_random_state * PRNG_CST1 + PRNG_CST2) & PRNG_CST3; + return (UCHAR_MAX * (sc_uint) taf_random_state) / (sc_uint)(PRNG_CST3 + 1); } static void -taf_random_reset (void) -{ - /* Reset PRNG to initial conditions. */ - taf_random_state = PRNG_INITIAL_STATE; +taf_random_reset(void) { + /* Reset PRNG to initial conditions. */ + taf_random_state = PRNG_INITIAL_STATE; } @@ -145,9 +145,8 @@ taf_random_reset (void) * Return TRUE if pointer is a valid TAF structure, FALSE otherwise. */ static sc_bool -taf_is_valid (sc_tafref_t taf) -{ - return taf && taf->magic == TAF_MAGIC; +taf_is_valid(sc_tafref_t taf) { + return taf && taf->magic == TAF_MAGIC; } @@ -157,25 +156,24 @@ taf_is_valid (sc_tafref_t taf) * Allocate and return a new, empty TAF structure. */ static sc_tafref_t -taf_create_empty (void) -{ - sc_tafref_t taf; - - /* Create an empty TAF structure. */ - taf = (sc_tafref_t)sc_malloc(sizeof (*taf)); - taf->magic = TAF_MAGIC; - memset (taf->header, 0, sizeof (taf->header)); - taf->version = TAF_VERSION_NONE; - taf->total_in_bytes = 0; - taf->slabs = NULL; - taf->slab_count = 0; - taf->slabs_allocated = 0; - taf->is_unterminated = FALSE; - taf->current_slab = 0; - taf->current_offset = 0; - - /* Return the new TAF structure. */ - return taf; +taf_create_empty(void) { + sc_tafref_t taf; + + /* Create an empty TAF structure. */ + taf = (sc_tafref_t)sc_malloc(sizeof(*taf)); + taf->magic = TAF_MAGIC; + memset(taf->header, 0, sizeof(taf->header)); + taf->version = TAF_VERSION_NONE; + taf->total_in_bytes = 0; + taf->slabs = NULL; + taf->slab_count = 0; + taf->slabs_allocated = 0; + taf->is_unterminated = FALSE; + taf->current_slab = 0; + taf->current_offset = 0; + + /* Return the new TAF structure. */ + return taf; } @@ -185,22 +183,21 @@ taf_create_empty (void) * Free TAF memory, and destroy a TAF structure. */ void -taf_destroy (sc_tafref_t taf) -{ - sc_int index_; - assert (taf_is_valid (taf)); - - /* First free each slab in the slabs array,... */ - for (index_ = 0; index_ < taf->slab_count; index_++) - sc_free (taf->slabs[index_].data); - - /* - * ...then free slabs growable array, and poison and free the TAF structure - * itself. - */ - sc_free (taf->slabs); - memset (taf, 0xaa, sizeof (*taf)); - sc_free (taf); +taf_destroy(sc_tafref_t taf) { + sc_int index_; + assert(taf_is_valid(taf)); + + /* First free each slab in the slabs array,... */ + for (index_ = 0; index_ < taf->slab_count; index_++) + sc_free(taf->slabs[index_].data); + + /* + * ...then free slabs growable array, and poison and free the TAF structure + * itself. + */ + sc_free(taf->slabs); + memset(taf, 0xaa, sizeof(*taf)); + sc_free(taf); } @@ -211,37 +208,32 @@ taf_destroy (sc_tafref_t taf) * strings. Nul's are used to replace carriage return and newline pairs. */ static void -taf_finalize_last_slab (sc_tafref_t taf) -{ - sc_slabdescref_t slab; - sc_int index_; - - /* Locate the final slab in the slab descriptors array. */ - assert (taf->slab_count > 0); - slab = taf->slabs + taf->slab_count - 1; - - /* - * Replace carriage return and newline pairs with nuls, and individual - * carriage returns with a single newline. - */ - for (index_ = 0; index_ < slab->size; index_++) - { - if (slab->data[index_] == CARRIAGE_RETURN) - { - if (index_ < slab->size - 1 && slab->data[index_ + 1] == NEWLINE) - { - slab->data[index_] = NUL; - slab->data[index_ + 1] = NUL; - index_++; - } - else - slab->data[index_] = NEWLINE; - } - - /* Also protect against unlikely incoming nul characters. */ - else if (slab->data[index_] == NUL) - slab->data[index_] = NEWLINE; - } +taf_finalize_last_slab(sc_tafref_t taf) { + sc_slabdescref_t slab; + sc_int index_; + + /* Locate the final slab in the slab descriptors array. */ + assert(taf->slab_count > 0); + slab = taf->slabs + taf->slab_count - 1; + + /* + * Replace carriage return and newline pairs with nuls, and individual + * carriage returns with a single newline. + */ + for (index_ = 0; index_ < slab->size; index_++) { + if (slab->data[index_] == CARRIAGE_RETURN) { + if (index_ < slab->size - 1 && slab->data[index_ + 1] == NEWLINE) { + slab->data[index_] = NUL; + slab->data[index_ + 1] = NUL; + index_++; + } else + slab->data[index_] = NEWLINE; + } + + /* Also protect against unlikely incoming nul characters. */ + else if (slab->data[index_] == NUL) + slab->data[index_] = NEWLINE; + } } @@ -253,26 +245,23 @@ taf_finalize_last_slab (sc_tafref_t taf) * Otherwise, return the count of usable bytes found in the buffer. */ static sc_int -taf_find_buffer_extent (const sc_byte *buffer, - sc_int length, sc_bool *is_unterminated) -{ - sc_int bytes; - - /* Search backwards from the buffer end for the final line feed. */ - for (bytes = length; bytes > 1; bytes--) - { - if (buffer[bytes - 2] == CARRIAGE_RETURN && buffer[bytes - 1] == NEWLINE) - break; - } - if (bytes < 2) - { - /* No carriage return and newline termination found. */ - *is_unterminated = TRUE; - return length; - } - - *is_unterminated = FALSE; - return bytes; +taf_find_buffer_extent(const sc_byte *buffer, + sc_int length, sc_bool *is_unterminated) { + sc_int bytes; + + /* Search backwards from the buffer end for the final line feed. */ + for (bytes = length; bytes > 1; bytes--) { + if (buffer[bytes - 2] == CARRIAGE_RETURN && buffer[bytes - 1] == NEWLINE) + break; + } + if (bytes < 2) { + /* No carriage return and newline termination found. */ + *is_unterminated = TRUE; + return length; + } + + *is_unterminated = FALSE; + return bytes; } @@ -283,75 +272,70 @@ taf_find_buffer_extent (const sc_byte *buffer, * number of characters consumed from the buffer. */ static sc_int -taf_append_buffer (sc_tafref_t taf, const sc_byte *buffer, sc_int length) -{ - sc_int bytes; - sc_bool is_unterminated; - - /* Locate the extent of appendable data in the buffer. */ - bytes = taf_find_buffer_extent (buffer, length, &is_unterminated); - - /* See if the last buffer handled contained at least one data line. */ - if (!taf->is_unterminated) - { - sc_slabdescref_t slab; - - /* Extend the slabs array if we've reached the current allocation. */ - if (taf->slab_count == taf->slabs_allocated) - { - taf->slabs_allocated += GROW_INCREMENT; - taf->slabs = (sc_slabdescref_t)sc_realloc (taf->slabs, - taf->slabs_allocated * sizeof (*taf->slabs)); - } - - /* Advance to the next unused slab in the slab descriptors array. */ - slab = taf->slabs + taf->slab_count; - taf->slab_count++; - - /* Copy the input buffer into the new slab. */ - slab->data = (sc_byte *)sc_malloc (bytes); - memcpy (slab->data, buffer, bytes); - slab->size = bytes; - } - else - { - sc_slabdescref_t slab; - - /* Locate the final slab in the slab descriptors array. */ - assert (taf->slab_count > 0); - slab = taf->slabs + taf->slab_count - 1; - - /* - * The last buffer we saw had no line endings in it. In this case, - * append the input buffer to the end of the last slab's data, rather - * than creating a new slab. This may cause allocation to overflow - * the system limits on single allocated areas on some platforms. - */ - slab->data = (sc_byte *)sc_realloc(slab->data, slab->size + bytes); - memcpy (slab->data + slab->size, buffer, bytes); - slab->size += bytes; - - /* - * Use a special case for the final carriage return and newline pairing - * that are split over two buffers; force correct termination of this - * slab. - */ - if (slab->size > 1 - && slab->data[slab->size - 2] == CARRIAGE_RETURN - && slab->data[slab->size - 1] == NEWLINE) - is_unterminated = FALSE; - } - - /* - * Note if this buffer requires that the next be coalesced with it. If it - * doesn't, finalize the last slab by breaking it into separate lines. - */ - taf->is_unterminated = is_unterminated; - if (!is_unterminated) - taf_finalize_last_slab (taf); - - /* Return count of buffer bytes consumed. */ - return bytes; +taf_append_buffer(sc_tafref_t taf, const sc_byte *buffer, sc_int length) { + sc_int bytes; + sc_bool is_unterminated; + + /* Locate the extent of appendable data in the buffer. */ + bytes = taf_find_buffer_extent(buffer, length, &is_unterminated); + + /* See if the last buffer handled contained at least one data line. */ + if (!taf->is_unterminated) { + sc_slabdescref_t slab; + + /* Extend the slabs array if we've reached the current allocation. */ + if (taf->slab_count == taf->slabs_allocated) { + taf->slabs_allocated += GROW_INCREMENT; + taf->slabs = (sc_slabdescref_t)sc_realloc(taf->slabs, + taf->slabs_allocated * sizeof(*taf->slabs)); + } + + /* Advance to the next unused slab in the slab descriptors array. */ + slab = taf->slabs + taf->slab_count; + taf->slab_count++; + + /* Copy the input buffer into the new slab. */ + slab->data = (sc_byte *)sc_malloc(bytes); + memcpy(slab->data, buffer, bytes); + slab->size = bytes; + } else { + sc_slabdescref_t slab; + + /* Locate the final slab in the slab descriptors array. */ + assert(taf->slab_count > 0); + slab = taf->slabs + taf->slab_count - 1; + + /* + * The last buffer we saw had no line endings in it. In this case, + * append the input buffer to the end of the last slab's data, rather + * than creating a new slab. This may cause allocation to overflow + * the system limits on single allocated areas on some platforms. + */ + slab->data = (sc_byte *)sc_realloc(slab->data, slab->size + bytes); + memcpy(slab->data + slab->size, buffer, bytes); + slab->size += bytes; + + /* + * Use a special case for the final carriage return and newline pairing + * that are split over two buffers; force correct termination of this + * slab. + */ + if (slab->size > 1 + && slab->data[slab->size - 2] == CARRIAGE_RETURN + && slab->data[slab->size - 1] == NEWLINE) + is_unterminated = FALSE; + } + + /* + * Note if this buffer requires that the next be coalesced with it. If it + * doesn't, finalize the last slab by breaking it into separate lines. + */ + taf->is_unterminated = is_unterminated; + if (!is_unterminated) + taf_finalize_last_slab(taf); + + /* Return count of buffer bytes consumed. */ + return bytes; } @@ -364,80 +348,75 @@ taf_append_buffer (sc_tafref_t taf, const sc_byte *buffer, sc_int length) * Assumes that the file has been read past the header. */ static sc_bool -taf_unobfuscate (sc_tafref_t taf, sc_read_callbackref_t callback, - void *opaque, sc_bool is_gamefile) -{ - sc_byte *buffer; - sc_int bytes, used_bytes, total_bytes, index_; - - /* Reset the PRNG, and synchronize with the header already read. */ - taf_random_reset (); - for (index_ = 0; index_ < VERSION_HEADER_SIZE; index_++) - taf_random (); - - /* - * Malloc buffer, done to help systems with limited stacks, and initialize - * count of bytes read and used in the buffer to zero. - */ - buffer = (sc_byte *)sc_malloc (IN_BUFFER_SIZE); - used_bytes = 0; - total_bytes = 0; - - /* Unobfuscate in buffer sized chunks. */ - do - { - /* Try to obtain more data. */ - bytes = callback (opaque, - buffer + used_bytes, IN_BUFFER_SIZE - used_bytes); - - /* Unobfuscate data read in. */ - for (index_ = 0; index_ < bytes; index_++) - buffer[used_bytes + index_] ^= taf_random (); - - /* - * Add data read in and unobfuscated to buffer used data, and if - * unobfuscated data is available, add it to the TAF. - */ - used_bytes += bytes; - if (used_bytes > 0) - { - sc_int consumed; - - /* Add lines from this buffer to the TAF. */ - consumed = taf_append_buffer (taf, buffer, used_bytes); - - /* Move unused buffer data to buffer start. */ - memmove (buffer, buffer + consumed, IN_BUFFER_SIZE - consumed); - - /* Note counts of bytes consumed and remaining in the buffer. */ - used_bytes -= consumed; - total_bytes += consumed; - } - } - while (bytes > 0); - - /* - * Unobfuscation completed, note the total bytes read. This value is - * actually not used for version 3.9 and version 3.8 games, but we maintain - * it just in case. - */ - taf->total_in_bytes = total_bytes; - if (is_gamefile) - taf->total_in_bytes += VERSION_HEADER_SIZE; - - /* Check that we found the end of the input file as expected. */ - if (used_bytes > 0) - { - sc_error ("taf_unobfuscate:" - " warning: %ld unhandled bytes in the buffer\n", used_bytes); - } - - if (taf->is_unterminated) - sc_fatal ("taf_unobfuscate: unterminated final data slab\n"); - - /* Return successfully. */ - sc_free (buffer); - return TRUE; +taf_unobfuscate(sc_tafref_t taf, sc_read_callbackref_t callback, + void *opaque, sc_bool is_gamefile) { + sc_byte *buffer; + sc_int bytes, used_bytes, total_bytes, index_; + + /* Reset the PRNG, and synchronize with the header already read. */ + taf_random_reset(); + for (index_ = 0; index_ < VERSION_HEADER_SIZE; index_++) + taf_random(); + + /* + * Malloc buffer, done to help systems with limited stacks, and initialize + * count of bytes read and used in the buffer to zero. + */ + buffer = (sc_byte *)sc_malloc(IN_BUFFER_SIZE); + used_bytes = 0; + total_bytes = 0; + + /* Unobfuscate in buffer sized chunks. */ + do { + /* Try to obtain more data. */ + bytes = callback(opaque, + buffer + used_bytes, IN_BUFFER_SIZE - used_bytes); + + /* Unobfuscate data read in. */ + for (index_ = 0; index_ < bytes; index_++) + buffer[used_bytes + index_] ^= taf_random(); + + /* + * Add data read in and unobfuscated to buffer used data, and if + * unobfuscated data is available, add it to the TAF. + */ + used_bytes += bytes; + if (used_bytes > 0) { + sc_int consumed; + + /* Add lines from this buffer to the TAF. */ + consumed = taf_append_buffer(taf, buffer, used_bytes); + + /* Move unused buffer data to buffer start. */ + memmove(buffer, buffer + consumed, IN_BUFFER_SIZE - consumed); + + /* Note counts of bytes consumed and remaining in the buffer. */ + used_bytes -= consumed; + total_bytes += consumed; + } + } while (bytes > 0); + + /* + * Unobfuscation completed, note the total bytes read. This value is + * actually not used for version 3.9 and version 3.8 games, but we maintain + * it just in case. + */ + taf->total_in_bytes = total_bytes; + if (is_gamefile) + taf->total_in_bytes += VERSION_HEADER_SIZE; + + /* Check that we found the end of the input file as expected. */ + if (used_bytes > 0) { + sc_error("taf_unobfuscate:" + " warning: %ld unhandled bytes in the buffer\n", used_bytes); + } + + if (taf->is_unterminated) + sc_fatal("taf_unobfuscate: unterminated final data slab\n"); + + /* Return successfully. */ + sc_free(buffer); + return TRUE; } #define BUFFER_SIZE 16384 @@ -448,7 +427,7 @@ taf_unobfuscate (sc_tafref_t taf, sc_read_callbackref_t callback, * Decompress a version 4.0 TAF */ static sc_bool taf_decompress(sc_tafref_t taf, sc_read_callbackref_t callback, - void *opaque, sc_bool is_gamefile) { + void *opaque, sc_bool is_gamefile) { #if USE_ZLIB Common::SeekableReadStream *src = (Common::SeekableReadStream *)opaque; assert(src); @@ -484,99 +463,88 @@ static sc_bool taf_decompress(sc_tafref_t taf, sc_read_callbackref_t callback, * in the buffer, or 0 if no more (end of file). */ static sc_tafref_t -taf_create_from_callback (sc_read_callbackref_t callback, - void *opaque, sc_bool is_gamefile) -{ - sc_tafref_t taf; - sc_bool status = FALSE; - assert (callback); - - /* Create an empty TAF structure. */ - taf = taf_create_empty (); - - /* - * Determine the TAF file version in use. For saved games, we always use - * version 4.0 format. For others, it's determined from the header. - */ - if (is_gamefile) - { - sc_int in_bytes; - - /* - * Read in the ADRIFT header for game files. Start by reading in the - * shorter header common to all. - */ - in_bytes = callback (opaque, taf->header, VERSION_HEADER_SIZE); - if (in_bytes != VERSION_HEADER_SIZE) - { - sc_error ("taf_create: not enough data for standard TAF header\n"); - taf_destroy (taf); - return NULL; - } - - /* - * Compare the header with the known TAF signatures, and set TAF version - * appropriately. - */ - if (memcmp (taf->header, V400_SIGNATURE, VERSION_HEADER_SIZE) == 0) - { - /* Read in the version 4.0 header extension. */ - in_bytes = callback (opaque, - taf->header + VERSION_HEADER_SIZE, - V400_HEADER_EXTRA); - if (in_bytes != V400_HEADER_EXTRA) - { - sc_error ("taf_create:" - " not enough data for extended TAF header\n"); - taf_destroy (taf); - return NULL; - } - - taf->version = TAF_VERSION_400; - } - else if (memcmp (taf->header, V390_SIGNATURE, VERSION_HEADER_SIZE) == 0) - taf->version = TAF_VERSION_390; - else if (memcmp (taf->header, V380_SIGNATURE, VERSION_HEADER_SIZE) == 0) - taf->version = TAF_VERSION_380; - else - { - taf_destroy (taf); - return NULL; - } - } - else - { - /* Saved games are always considered to be version 4.0. */ - taf->version = TAF_VERSION_400; - } - - /* - * Call the appropriate game file reader function. For version 4.0 games, - * data is compressed with Zlib. For version 3.9 and version 3.8 games, - * it's obfuscated with the Visual Basic PRNG. - */ - switch (taf->version) - { - case TAF_VERSION_400: - status = taf_decompress (taf, callback, opaque, is_gamefile); - break; - - case TAF_VERSION_390: - case TAF_VERSION_380: - status = taf_unobfuscate (taf, callback, opaque, is_gamefile); - break; - - default: - sc_fatal ("taf_create: invalid version\n"); - } - if (!status) - { - taf_destroy (taf); - return NULL; - } - - /* Return successfully. */ - return taf; +taf_create_from_callback(sc_read_callbackref_t callback, + void *opaque, sc_bool is_gamefile) { + sc_tafref_t taf; + sc_bool status = FALSE; + assert(callback); + + /* Create an empty TAF structure. */ + taf = taf_create_empty(); + + /* + * Determine the TAF file version in use. For saved games, we always use + * version 4.0 format. For others, it's determined from the header. + */ + if (is_gamefile) { + sc_int in_bytes; + + /* + * Read in the ADRIFT header for game files. Start by reading in the + * shorter header common to all. + */ + in_bytes = callback(opaque, taf->header, VERSION_HEADER_SIZE); + if (in_bytes != VERSION_HEADER_SIZE) { + sc_error("taf_create: not enough data for standard TAF header\n"); + taf_destroy(taf); + return NULL; + } + + /* + * Compare the header with the known TAF signatures, and set TAF version + * appropriately. + */ + if (memcmp(taf->header, V400_SIGNATURE, VERSION_HEADER_SIZE) == 0) { + /* Read in the version 4.0 header extension. */ + in_bytes = callback(opaque, + taf->header + VERSION_HEADER_SIZE, + V400_HEADER_EXTRA); + if (in_bytes != V400_HEADER_EXTRA) { + sc_error("taf_create:" + " not enough data for extended TAF header\n"); + taf_destroy(taf); + return NULL; + } + + taf->version = TAF_VERSION_400; + } else if (memcmp(taf->header, V390_SIGNATURE, VERSION_HEADER_SIZE) == 0) + taf->version = TAF_VERSION_390; + else if (memcmp(taf->header, V380_SIGNATURE, VERSION_HEADER_SIZE) == 0) + taf->version = TAF_VERSION_380; + else { + taf_destroy(taf); + return NULL; + } + } else { + /* Saved games are always considered to be version 4.0. */ + taf->version = TAF_VERSION_400; + } + + /* + * Call the appropriate game file reader function. For version 4.0 games, + * data is compressed with Zlib. For version 3.9 and version 3.8 games, + * it's obfuscated with the Visual Basic PRNG. + */ + switch (taf->version) { + case TAF_VERSION_400: + status = taf_decompress(taf, callback, opaque, is_gamefile); + break; + + case TAF_VERSION_390: + case TAF_VERSION_380: + status = taf_unobfuscate(taf, callback, opaque, is_gamefile); + break; + + default: + sc_fatal("taf_create: invalid version\n"); + } + if (!status) { + taf_destroy(taf); + return NULL; + } + + /* Return successfully. */ + return taf; } @@ -588,31 +556,28 @@ taf_create_from_callback (sc_read_callbackref_t callback, * constructed from either *.TAF (game) or *.TAS (saved game state) file data. */ sc_tafref_t -taf_create (sc_read_callbackref_t callback, void *opaque) -{ - return taf_create_from_callback (callback, opaque, TRUE); +taf_create(sc_read_callbackref_t callback, void *opaque) { + return taf_create_from_callback(callback, opaque, TRUE); } sc_tafref_t -taf_create_tas (sc_read_callbackref_t callback, void *opaque) -{ - return taf_create_from_callback (callback, opaque, FALSE); +taf_create_tas(sc_read_callbackref_t callback, void *opaque) { + return taf_create_from_callback(callback, opaque, FALSE); } - + /* * taf_first_line() * * Iterator rewind function, reset current slab location to TAF data start. */ void -taf_first_line (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); +taf_first_line(sc_tafref_t taf) { + assert(taf_is_valid(taf)); - /* Set current locations to TAF start. */ - taf->current_slab = 0; - taf->current_offset = 0; + /* Set current locations to TAF start. */ + taf->current_slab = 0; + taf->current_offset = 0; } @@ -623,35 +588,32 @@ taf_first_line (sc_tafref_t taf) * if no more lines. */ const sc_char * -taf_next_line (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); - - /* If there is a next line, return it and advance current. */ - if (taf->current_slab < taf->slab_count) - { - sc_char *line; - - /* Get the effective address of the current line. */ - line = (sc_char *) taf->slabs[taf->current_slab].data; - line += taf->current_offset; - - /* - * Advance to the next line. The + 2 skips the NULs used to replace the - * carriage return and line feed. - */ - taf->current_offset += strlen (line) + 2; - if (taf->current_offset >= taf->slabs[taf->current_slab].size) - { - taf->current_slab++; - taf->current_offset = 0; - } - - return line; - } - - /* No more lines, so return NULL. */ - return NULL; +taf_next_line(sc_tafref_t taf) { + assert(taf_is_valid(taf)); + + /* If there is a next line, return it and advance current. */ + if (taf->current_slab < taf->slab_count) { + sc_char *line; + + /* Get the effective address of the current line. */ + line = (sc_char *) taf->slabs[taf->current_slab].data; + line += taf->current_offset; + + /* + * Advance to the next line. The + 2 skips the NULs used to replace the + * carriage return and line feed. + */ + taf->current_offset += strlen(line) + 2; + if (taf->current_offset >= taf->slabs[taf->current_slab].size) { + taf->current_slab++; + taf->current_offset = 0; + } + + return line; + } + + /* No more lines, so return NULL. */ + return NULL; } @@ -661,12 +623,11 @@ taf_next_line (sc_tafref_t taf) * Iterator end function, returns TRUE if more TAF lines are readable. */ sc_bool -taf_more_lines (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); +taf_more_lines(sc_tafref_t taf) { + assert(taf_is_valid(taf)); - /* Return TRUE if not at TAF data end. */ - return taf->current_slab < taf->slab_count; + /* Return TRUE if not at TAF data end. */ + return taf->current_slab < taf->slab_count; } @@ -678,16 +639,15 @@ taf_more_lines (sc_tafref_t taf) * be located. */ sc_int -taf_get_game_data_length (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); - - /* - * Return the count of bytes inflated; this includes the TAF header length - * for TAF, rather than TAS, files. For TAS files, the count of file bytes - * read is irrelevant, and is never used. - */ - return taf->total_in_bytes; +taf_get_game_data_length(sc_tafref_t taf) { + assert(taf_is_valid(taf)); + + /* + * Return the count of bytes inflated; this includes the TAF header length + * for TAF, rather than TAS, files. For TAS files, the count of file bytes + * read is irrelevant, and is never used. + */ + return taf->total_in_bytes; } @@ -697,12 +657,11 @@ taf_get_game_data_length (sc_tafref_t taf) * Return the version number of the TAF file, 400, 390, or 380. */ sc_int -taf_get_version (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); +taf_get_version(sc_tafref_t taf) { + assert(taf_is_valid(taf)); - assert (taf->version != TAF_VERSION_NONE); - return taf->version; + assert(taf->version != TAF_VERSION_NONE); + return taf->version; } @@ -715,67 +674,64 @@ taf_get_version (sc_tafref_t taf) * slab, and therefore safe to print. */ sc_bool -taf_debug_is_taf_string (sc_tafref_t taf, const void *addr) { - const sc_byte *const addr_ = (const sc_byte *const)addr; - sc_int index_; - - /* - * Compare pointer, by address directly, against all memory contained in - * the TAF slabs. Return TRUE if in range. - */ - for (index_ = 0; index_ < taf->slab_count; index_++) - { - if (addr_ >= taf->slabs[index_].data - && addr_ < taf->slabs[index_].data + taf->slabs[index_].size) - return TRUE; - } - - return FALSE; +taf_debug_is_taf_string(sc_tafref_t taf, const void *addr) { + const sc_byte *const addr_ = (const sc_byte * const)addr; + sc_int index_; + + /* + * Compare pointer, by address directly, against all memory contained in + * the TAF slabs. Return TRUE if in range. + */ + for (index_ = 0; index_ < taf->slab_count; index_++) { + if (addr_ >= taf->slabs[index_].data + && addr_ < taf->slabs[index_].data + taf->slabs[index_].size) + return TRUE; + } + + return FALSE; } void -taf_debug_dump (sc_tafref_t taf) -{ - sc_int index_, current_slab, current_offset; - assert (taf_is_valid (taf)); - - /* Dump complete structure. */ - sc_trace ("TAFfile: debug dump follows...\n"); - sc_trace ("taf->header ="); - for (index_ = 0; index_ < (sc_int) sizeof (taf->header); index_++) - sc_trace (" %02x", taf->header[index_]); - sc_trace ("\n"); - - sc_trace ("taf->version = %s\n", - taf->version == TAF_VERSION_400 ? "4.00" : - taf->version == TAF_VERSION_390 ? "3.90" : - taf->version == TAF_VERSION_380 ? "3.80" : "[Unknown]"); - - sc_trace ("taf->slabs = \n"); - for (index_ = 0; index_ < taf->slab_count; index_++) - { - sc_trace ("%3ld : %p, %ld bytes\n", index_, - taf->slabs[index_].data, taf->slabs[index_].size); - } - - sc_trace ("taf->slab_count = %ld\n", taf->slab_count); - sc_trace ("taf->slabs_allocated = %ld\n", taf->slabs_allocated); - sc_trace ("taf->current_slab = %ld\n", taf->current_slab); - sc_trace ("taf->current_offset = %ld\n", taf->current_offset); - - /* Save current location. */ - current_slab = taf->current_slab; - current_offset = taf->current_offset; - - /* Print out taf lines using taf iterators. */ - sc_trace ("\ntaf iterators:\n"); - taf_first_line (taf); - for (index_ = 0; taf_more_lines (taf); index_++) - sc_trace ("%5ld %s\n", index_, taf_next_line (taf)); - - /* Restore current location. */ - taf->current_slab = current_slab; - taf->current_offset = current_offset; +taf_debug_dump(sc_tafref_t taf) { + sc_int index_, current_slab, current_offset; + assert(taf_is_valid(taf)); + + /* Dump complete structure. */ + sc_trace("TAFfile: debug dump follows...\n"); + sc_trace("taf->header ="); + for (index_ = 0; index_ < (sc_int) sizeof(taf->header); index_++) + sc_trace(" %02x", taf->header[index_]); + sc_trace("\n"); + + sc_trace("taf->version = %s\n", + taf->version == TAF_VERSION_400 ? "4.00" : + taf->version == TAF_VERSION_390 ? "3.90" : + taf->version == TAF_VERSION_380 ? "3.80" : "[Unknown]"); + + sc_trace("taf->slabs = \n"); + for (index_ = 0; index_ < taf->slab_count; index_++) { + sc_trace("%3ld : %p, %ld bytes\n", index_, + taf->slabs[index_].data, taf->slabs[index_].size); + } + + sc_trace("taf->slab_count = %ld\n", taf->slab_count); + sc_trace("taf->slabs_allocated = %ld\n", taf->slabs_allocated); + sc_trace("taf->current_slab = %ld\n", taf->current_slab); + sc_trace("taf->current_offset = %ld\n", taf->current_offset); + + /* Save current location. */ + current_slab = taf->current_slab; + current_offset = taf->current_offset; + + /* Print out taf lines using taf iterators. */ + sc_trace("\ntaf iterators:\n"); + taf_first_line(taf); + for (index_ = 0; taf_more_lines(taf); index_++) + sc_trace("%5ld %s\n", index_, taf_next_line(taf)); + + /* Restore current location. */ + taf->current_slab = current_slab; + taf->current_offset = current_offset; } } // End of namespace Adrift |