summaryrefslogtreecommitdiff
path: root/src/win95/chunk.cpp
diff options
context:
space:
mode:
authorSteven Fuller <relnev@icculus.org>2001-07-01 00:55:22 +0000
committerPatryk Obara <dreamer.tan@gmail.com>2019-08-20 02:09:04 +0200
commit2186d5f3f95cd74a070a490d899291648d58667a (patch)
tree55241a1afa3e1a22e0b6593a8dead0b703800f44 /src/win95/chunk.cpp
parent218ca90543758a20ac326e444ca0643174ca7384 (diff)
Initial revision
Diffstat (limited to 'src/win95/chunk.cpp')
-rw-r--r--src/win95/chunk.cpp599
1 files changed, 599 insertions, 0 deletions
diff --git a/src/win95/chunk.cpp b/src/win95/chunk.cpp
new file mode 100644
index 0000000..a123ba0
--- /dev/null
+++ b/src/win95/chunk.cpp
@@ -0,0 +1,599 @@
+#include <string.h>
+
+#include "chunk.hpp"
+
+#if engine
+
+#define UseLocalAssert No
+#include "ourasert.h"
+#define assert(x) GLOBALASSERT(x)
+
+#else
+
+#if cencon
+#include "ccassert.h"
+#else
+#include <assert.h>
+#endif
+
+#endif
+
+
+#if cencon
+#include "environs.hpp"
+#else
+#define twprintf printf
+
+#ifdef cencon
+#define new my_new
+#endif
+
+char * users_name = "Player";
+#endif
+
+#include "hash_tem.hpp"
+Chunk * Parent_File;
+
+// Non class functions ( only one as yet )
+
+void list_chunks_in_file(List<int> * pList, HANDLE hand, char const * chunk_id)
+{
+ unsigned long bytes_read;
+
+ char buffer[8];
+ BOOL ok = TRUE;
+
+ while (pList->size())
+ pList->delete_first_entry();
+
+ // assuming we start at the front of a parent chunk,
+ // containing the child chunk specified
+
+ int init_file_pos = SetFilePointer (hand,0,0,FILE_CURRENT);
+ int file_pos;
+ int file_length = GetFileSize(hand, 0);
+
+ SetFilePointer (hand,8,0,FILE_CURRENT);
+
+ int chunk_length;
+ int sub_chunk_ln;
+
+ ReadFile (hand, (long *) &chunk_length, 4, &bytes_read, 0);
+
+ if ((init_file_pos + chunk_length) > file_length) return;
+
+ while ((file_pos = SetFilePointer (hand,0,0,FILE_CURRENT))
+ < (init_file_pos + chunk_length) && ok) {
+
+ ok = ReadFile (hand, (long *) buffer, 8, &bytes_read, 0);
+ if (strncmp(buffer, chunk_id, 8) == 0)
+ pList->add_entry(file_pos);
+
+ ok = ReadFile (hand, (long *) &sub_chunk_ln, 4, &bytes_read, 0);
+
+ SetFilePointer (hand,sub_chunk_ln-12,0,FILE_CURRENT);
+ }
+}
+
+#ifndef RIFF_OPTIMIZE
+List<int> list_chunks_in_file (HANDLE & hand, const char * chunk_id)
+{
+
+ List<int> chunk_list;
+
+ list_chunks_in_file(&chunk_list, hand, chunk_id);
+
+ return chunk_list;
+}
+#endif
+
+//////////////////////////////////////////////
+
+
+// Class Chunk functions
+
+Chunk::~Chunk()
+{
+ if (parent) {
+ if (parent->children == this) {
+ parent->children = next;
+ if (next)
+ next->previous = previous;
+ }
+ else {
+ if (previous)
+ previous->next = next;
+ if (next)
+ next->previous = previous;
+ }
+ }
+}
+
+Chunk::Chunk(Chunk_With_Children * _parent, const char * _identifier)
+: error_code(0)
+{
+ strncpy (identifier_store, _identifier, 8);
+ identifier_store[8] = 0;
+ identifier = identifier_store;
+ parent = _parent;
+ next = NULL;
+ previous = NULL;
+
+ if (parent){
+ if (parent->children) {
+ Chunk * pTail = parent->children;
+ while (pTail->next)
+ pTail = pTail->next;
+ pTail->next = this;
+ previous = pTail;
+ }
+ else
+ parent->children = this;
+ }
+}
+
+BOOL Chunk::output_chunk (HANDLE & hand)
+{
+ unsigned long junk;
+ BOOL ok;
+ char * data_block;
+
+ data_block = make_data_block_from_chunk();
+
+ if (data_block)
+ {
+ ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0);
+ delete [] data_block;
+
+ if (!ok) return FALSE;
+ }
+ else if (chunk_size)
+ {
+ return(FALSE);
+ }
+ return TRUE;
+}
+
+
+
+char * Chunk::make_data_block_from_chunk ()
+{
+ char * data_block;
+ size_t block_size;
+
+ block_size = size_chunk();
+
+ if (!chunk_size)
+ {
+ return(0);
+ }
+
+ data_block = new char [block_size];
+
+ this->fill_data_block(data_block);
+
+ return data_block;
+}
+
+char * Chunk::make_data_block_for_process ()
+{
+ char * data_block;
+ size_t block_size;
+
+ block_size = size_chunk_for_process();
+
+ if (!chunk_size)
+ {
+ return(0);
+ }
+
+ data_block = new char [block_size];
+
+ fill_data_block_for_process(data_block);
+
+ return data_block;
+}
+
+
+size_t Chunk::size_chunk_for_process()
+{
+ return size_chunk();
+}
+
+
+void Chunk::fill_data_block_for_process(char * data_start)
+{
+ fill_data_block(data_start);
+}
+
+Chunk_With_Children * Chunk::GetRootChunk(void)
+{
+ Chunk * retp = this;
+
+ while (retp->parent) retp = retp->parent;
+
+ return (Chunk_With_Children *) retp;
+}
+
+Chunk_With_Children const * Chunk::GetRootChunk(void) const
+{
+ Chunk const * retp = this;
+
+ while (retp->parent) retp = retp->parent;
+
+ return (Chunk_With_Children const *) retp;
+}
+
+
+///////////////////////////////////////
+
+// Class Miscellaneous_Chunk functions
+
+Miscellaneous_Chunk::Miscellaneous_Chunk (Chunk_With_Children * parent, const char * identifier,
+ const char * _data, size_t _data_size)
+: Chunk (parent, identifier),
+data(NULL), data_size (_data_size)
+{
+ if (data_size)
+ {
+ data_store = new char [data_size];
+
+ *((char **) &data) = data_store;
+
+ for (int i = 0; i < (signed)data_size; i++)
+ data_store[i] = _data[i];
+ }
+ else
+ {
+ data_store = NULL;
+ }
+
+}
+
+void Miscellaneous_Chunk::fill_data_block (char * data_start)
+{
+ strncpy (data_start, identifier, 8);
+
+ data_start += 8;
+
+ *((int *) data_start) = chunk_size;
+
+ data_start += 4;
+
+ for (int i = 0; i<(signed)(chunk_size-12); i++)
+ data_start[i] = data[i];
+}
+
+Miscellaneous_Chunk::~Miscellaneous_Chunk ()
+{
+ delete [] data_store;
+}
+
+///////////////////////////////////////
+
+// Class Chunk_With_Children functions
+
+Chunk_With_Children::~Chunk_With_Children()
+{
+ while (children)
+ delete children;
+}
+
+size_t Chunk_With_Children::size_chunk ()
+{
+ Chunk * child_ptr = children;
+
+ chunk_size = 12; // identifier + length
+
+ if (children)
+ while (child_ptr != NULL) {
+ chunk_size += child_ptr->size_chunk();
+ child_ptr = child_ptr->next;
+ }
+
+ return chunk_size;
+
+}
+
+BOOL Chunk_With_Children::output_chunk (HANDLE &hand)
+{
+ unsigned long junk;
+ Chunk * child_ptr = children;
+ BOOL ok;
+
+ ok = WriteFile (hand, (long *) identifier, 8, &junk, 0);
+
+ if (!ok) return FALSE;
+
+ ok = WriteFile (hand, (long *) &chunk_size, 4, &junk, 0);
+
+ if (!ok) return FALSE;
+
+ if (children)
+ while (child_ptr != NULL && ok){
+ ok = child_ptr->output_chunk(hand);
+ child_ptr = child_ptr->next;
+ }
+
+ if (!ok) return FALSE;
+
+ return TRUE;
+
+
+}
+
+
+size_t Chunk_With_Children::size_chunk_for_process()
+{
+ Chunk * child_ptr = children;
+
+ chunk_size = 12; // identifier + length
+
+ if (children)
+ while (child_ptr != NULL) {
+ chunk_size += child_ptr->size_chunk_for_process();
+ child_ptr = child_ptr->next;
+ }
+
+ return chunk_size;
+
+}
+
+
+void Chunk_With_Children::fill_data_block_for_process(char * data_start)
+{
+ strncpy (data_start, identifier, 8);
+
+ data_start += 8;
+
+ *((int *) data_start) = chunk_size;
+
+ data_start += 4;
+
+ Chunk * child_ptr = children;
+
+ if (children)
+ while (child_ptr != NULL) {
+ child_ptr->fill_data_block_for_process (data_start);
+ data_start += child_ptr->chunk_size;
+ child_ptr = child_ptr->next;
+ }
+
+}
+
+
+
+void Chunk_With_Children::fill_data_block(char * data_start)
+{
+ strncpy (data_start, identifier, 8);
+
+ data_start += 8;
+
+ *((int *) data_start) = chunk_size;
+
+ data_start += 4;
+
+ Chunk * child_ptr = children;
+
+ if (children)
+ while (child_ptr != NULL) {
+ child_ptr->fill_data_block (data_start);
+ data_start += child_ptr->chunk_size;
+ child_ptr = child_ptr->next;
+ }
+
+}
+
+#ifndef RIFF_OPTIMIZE
+List<Chunk *> Chunk_With_Children::lookup_child (const char * class_ident) const
+{
+ List<Chunk *> child_list;
+
+ lookup_child(class_ident,child_list);
+
+ return child_list;
+}
+#endif
+
+void Chunk_With_Children::lookup_child (const char * class_ident,List<Chunk*>& child_list) const
+{
+ //make sure the list is empty first
+ while(child_list.size())
+ {
+ child_list.delete_first_entry();
+ }
+
+ Chunk * child_ptr = children;
+
+ if (children)
+ while (child_ptr != NULL) {
+ if (strncmp (class_ident, child_ptr->identifier, 8) == NULL)
+ {
+ assert (!child_ptr->r_u_miscellaneous());
+ child_list.add_entry(child_ptr);
+ }
+ child_ptr = child_ptr->next;
+ }
+
+
+}
+
+unsigned Chunk_With_Children::count_children (char const * class_ident) const
+{
+ unsigned nChildren = 0;
+
+ Chunk * child_ptr = children;
+
+ if (children)
+ while (child_ptr != NULL) {
+ if (strncmp (class_ident, child_ptr->identifier, 8) == NULL)
+ {
+ assert (!child_ptr->r_u_miscellaneous());
+ ++ nChildren;
+ }
+ child_ptr = child_ptr->next;
+ }
+
+ return nChildren;
+}
+
+Chunk* Chunk_With_Children::lookup_single_child (const char * class_ident) const
+{
+ #if debug
+ //if debug make sure there is at most one of the required chunk type
+ Chunk * child_ptr = children;
+ Chunk * chunk_found=0;
+ if (children)
+ while (child_ptr != NULL) {
+ if (strncmp (class_ident, child_ptr->identifier, 8) == NULL)
+ {
+ assert (!child_ptr->r_u_miscellaneous());
+ assert(!chunk_found);
+ chunk_found=child_ptr;
+ }
+ child_ptr = child_ptr->next;
+ }
+ return chunk_found;
+ #else
+ Chunk * child_ptr = children;
+
+ if (children)
+ while (child_ptr != NULL) {
+ if (strncmp (class_ident, child_ptr->identifier, 8) == NULL)
+ {
+ assert (!child_ptr->r_u_miscellaneous());
+ return child_ptr;
+ }
+ child_ptr = child_ptr->next;
+ }
+ return 0;
+ #endif
+
+
+
+}
+
+void Chunk_With_Children::prepare_for_output()
+{
+ Chunk * child_ptr = children;
+ if (children)
+ while (child_ptr != NULL){
+ child_ptr->prepare_for_output ();
+ child_ptr = child_ptr->next;
+ }
+}
+
+void Chunk_With_Children::post_input_processing()
+{
+ Chunk * child_ptr = children;
+ if (children)
+ while (child_ptr != NULL){
+ child_ptr->post_input_processing ();
+ child_ptr = child_ptr->next;
+ }
+}
+
+///////////////////////////////////////////////////
+//Chunk registering stuff
+
+
+class RifRegEntry
+{
+ public:
+ int chunk_id_1;
+ int chunk_id_2;
+ int parent_id_1;
+ int parent_id_2;
+ Chunk * (* m_pfnCreate) (Chunk_With_Children* parent,const char* data);
+
+
+ /*
+ For two members of this class to be considered similar there chunk_is members must match.
+ If both parent_id members are zero for one of the objects being compared , then they are considered
+ equal regardless of the parent_id members of the other object.
+ Otherwise the parent_id members of the two objects must match.
+ (This is done because not all of the constructors insist on a given parent)
+ */
+ inline bool operator == (RifRegEntry const & rEntry) const
+ {
+ if(chunk_id_1 != rEntry.chunk_id_1 || chunk_id_2 != rEntry.chunk_id_2) return FALSE;
+ if(parent_id_1 == 0 && parent_id_2 == 0) return TRUE;
+ if(rEntry.parent_id_1 == 0 && rEntry.parent_id_2 == 0) return TRUE;
+ return parent_id_1 == rEntry.parent_id_1 && parent_id_2 == rEntry.parent_id_2;
+ }
+ inline bool operator != (RifRegEntry const & rEntry) const
+ {
+ return ! operator == (rEntry);
+ }
+};
+
+inline unsigned HashFunction(RifRegEntry const & rEntry)
+{
+ return HashFunction(rEntry.chunk_id_1 + rEntry.chunk_id_2);
+}
+
+static HashTable<RifRegEntry> * g_pRifRegister = NULL;
+
+void Chunk::Register(const char* idChunk,const char* idParent, Chunk * (* pfnCreate) (Chunk_With_Children* parent,const char* data) )
+{
+ static HashTable<RifRegEntry> reg;
+ char temp_id[8];
+
+ g_pRifRegister = &reg;
+
+ RifRegEntry entry;
+
+ strncpy(temp_id,idChunk,8);
+ entry.chunk_id_1 = *(int*) &temp_id[0];
+ entry.chunk_id_2 = *(int*) &temp_id[4];
+ entry.m_pfnCreate = pfnCreate;
+
+ if(idParent)
+ {
+ strncpy(temp_id,idParent,8);
+ entry.parent_id_1 = *(int*) &temp_id[0];
+ entry.parent_id_2 = *(int*) &temp_id[4];
+ }
+ else
+ {
+ entry.parent_id_1 = 0;
+ entry.parent_id_2 = 0;
+ }
+
+ reg.AddAsserted(entry);
+}
+
+Chunk* Chunk_With_Children::DynCreate(const char* data)
+{
+ /*
+ Look in hash tables for a constructor for this block
+ If none exists , create a Miscellaneous_Chunk
+ */
+ if (g_pRifRegister)
+ {
+ RifRegEntry test;
+ test.chunk_id_1 = *(int*) data;
+ test.chunk_id_2 = *(int*) &data[4];
+ test.parent_id_1 = *(int*) identifier;
+ test.parent_id_2 = *(int*) &identifier[4];
+ test.m_pfnCreate = NULL;
+
+ RifRegEntry const * pEntry = g_pRifRegister->Contains(test);
+ if (pEntry)
+ {
+ return pEntry->m_pfnCreate(this,data);
+ }
+ }
+ return new Miscellaneous_Chunk(this,data,(data + 12), (*(int *) (data + 8))-12);
+}
+
+
+
+
+
+
+
+
+
+
+