#include "munga.h" #include "windows.h" #pragma hdrstop #include "resource.h" #include "resver.h" ResourceDescription::ResourceDescription( ResourceFile *file, const char* name, ResourceDescription::ResourceType type, int priority, LWord flags, const void* address, size_t size, ResourceDescription::ResourceID index ) { Check(this); Check_Pointer(name); resourceFile = file; resourceID = index; resourceType = type; Str_Copy(resourceName, name, sizeof(resourceName)); for (int i = strlen(resourceName) + 1; iLoadResource(this); Verify(resourceAddress); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical ResourceDescription::TestInstance() const { return True; } //############################################################################# //########################## ResourceFile ############################### //############################################################################# //############################################################################# // ResourceFile CONSTRUCTORS & DESTRUCTORS // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceFile::ResourceFile(): labOnly(0), resourceArray(NULL), resourceArraySize(0), maxResourceID(ResourceDescription::NullResourceID), lastPreallocatedResourceID(ResourceDescription::NullResourceID) { versionArray[0] = RESOURCE_FORMAT_VERSION; versionArray[1] = 0; versionArray[2] = 0; versionArray[3] = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceFile::~ResourceFile() { if (resourceArray) { for (int i=maxResourceID; i>=0; i--) { if (resourceArray[i]) { Unregister_Object(resourceArray[i]); delete resourceArray[i]; } } Unregister_Pointer(resourceArray); delete[] resourceArray; } versionArray[0] = RESOURCE_FORMAT_VERSION; versionArray[1] = 0; versionArray[2] = 0; versionArray[3] = 0; labOnly = 0; resourceArraySize = 0; maxResourceID = ResourceDescription::NullResourceID; resourceArray = NULL; } //############################################################################## // ResourceFile METHODS // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceDescription* ResourceFile::AddResource( const char* name, ResourceDescription::ResourceType type, int priority, LWord load_flag, const void* address, size_t size, ResourceDescription::ResourceID index ) { Check(this); Check_Pointer(name); int i; // //------------------------------------------------------------------------- // If we asked for the next available ID number, find out what it should be //------------------------------------------------------------------------- // if (index == ResourceDescription::NullResourceID) { index = lastPreallocatedResourceID + 1; if (resourceArray) { Check_Pointer(resourceArray); for (; index<=resourceArraySize; ++index) { if (!resourceArray[index]) { break; } } } } // //------------------------------------------------------------- // Check to see if the resource index table needs to be created //------------------------------------------------------------- // if (!resourceArray) { resourceArraySize = index + IndexBlockSize; resourceArray = new ResourceDescription* [resourceArraySize]; Register_Pointer(resourceArray); for (i=0; i= resourceArraySize) { // //---------------------------------------- // Allocate a new table for the main index //---------------------------------------- // ResourceDescription **new_index = new ResourceDescription* [index + IndexBlockSize]; Register_Pointer(new_index); // //------------------------------------ // Copy the old table into the new one //------------------------------------ // Check_Pointer(resourceArray); for (i=0; i maxResourceID) { maxResourceID = index; } resourceArray[index] = new ResourceDescription( this, name, type, priority, load_flag, address, size, index ); // //---------------------------------------------------------------------- // The caller of this function is responsible for registering the memory //---------------------------------------------------------------------- // Register_Object(resourceArray[index]); return resourceArray[index]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceDescription* ResourceFile::AddResourceList( const char* name, ResourceDescription::ResourceType type, int priority, LWord load_flag, const ResourceDescription::ResourceID* address, int count, ResourceDescription::ResourceID index ) { Check(this); Check_Pointer(name); Check_Pointer(address); // //-------------------------------------------------------- // prefix the directory table with the count of references //-------------------------------------------------------- // ResourceDescription::ResourceID *table = new ResourceDescription::ResourceID[count+1]; Register_Pointer(table); for (int i=0; iGetBytesUsed(); memory_stream->Rewind(); return AddResource( name, type, priority, load_flag, memory_stream->GetPointer(), size, index ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ResourceFile::DeleteResource(ResourceDescription *resource) { Check(this); Check(resource); Check_Pointer(resourceArray); Verify(!resource->IsLocked()); // //------------------------------------------------------------------------ // Delete pointer from resoureArray if it was there //------------------------------------------------------------------------ // if (resource->resourceID != ResourceDescription::NullResourceID ) { resourceArray[resource->resourceID] = NULL; // //------------------------------------------------------------------------ // Find new maxResourceID //------------------------------------------------------------------------ // if (resource->resourceID == maxResourceID ) { ResourceDescription::ResourceID i; for (i = maxResourceID; i>=0; i--) { if(resourceArray[i] != NULL) { Check(resourceArray[i]); break; } } maxResourceID = i; } } // //------------------------------------------------------------------------ // The caller of this function is responsible for unregistering the memory //------------------------------------------------------------------------ // delete resource; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceDescription* ResourceFile::FindResourceDescription(ResourceDescription::ResourceID index) { Check(this); if (index<0 || index>maxResourceID || !resourceArray) { return NULL; } Check_Pointer(resourceArray); ResourceDescription *res = resourceArray[index]; return res; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceDescription* ResourceFile::FindResourceDescription( const char* name, ResourceDescription::ResourceType type, ResourceDescription::ResourceID after ) { Check(this); ResourceDescription *desc; ResourceDescription::ResourceID i; for (i=after+1; i<=maxResourceID; ++i) { desc = FindResourceDescription(i); if (desc) { Check(desc); if ( type == desc->resourceType && (!name || !strcmp(name, desc->resourceName)) ) { break; } } } if (i > maxResourceID) { desc = NULL; } return desc; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceDescription* ResourceFile::SearchList( ResourceDescription::ResourceID list_id, ResourceDescription::ResourceType type ) { ResourceDescription *list_res = FindResourceDescription(list_id); if (list_res) { Check(list_res); list_res->Lock(); Verify( list_res->resourceType <= ResourceDescription::MaxListResourceType ); ResourceDescription::ResourceID *list = (ResourceDescription::ResourceID*)list_res->resourceAddress; Check_Pointer(list); for (int i=1; i<=*list; ++i) { ResourceDescription *res = FindResourceDescription(list[i]); Check(res); if (res->resourceType == type) { list_res->Unlock(); return res; } } list_res->Unlock(); } return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceDescription* ResourceFile::SearchList( ResourceDescription::ResourceID list_id, const char* name ) { Check_Pointer(name); ResourceDescription *list_res = FindResourceDescription(list_id); if (list_res) { Check(list_res); list_res->Lock(); Verify( list_res->resourceType <= ResourceDescription::MaxListResourceType ); ResourceDescription::ResourceID *list = (ResourceDescription::ResourceID*)list_res->resourceAddress; Check_Pointer(list); for (int i=1; i<=*list; ++i) { ResourceDescription *res = FindResourceDescription(list[i]); Check(res); if (!strcmp(name, res->resourceName)) { list_res->Unlock(); return res; } } list_res->Unlock(); } return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ResourceFile::ReleaseUnlockedResources() { for (ResourceDescription::ResourceID i = maxResourceID; i>=0; i--) { if(resourceArray[i] != NULL) { ResourceDescription *res = resourceArray[i]; Check(res); res->ReleaseUnlockedResource(); } } } //############################################################################# // ResourceFile Test Support // Logical ResourceFile::TestInstance() const { return True; } //############################################################################## //########################## StreamableResourceFile ###################### //############################################################################## // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ StreamableResourceFile::StreamableResourceFile() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ StreamableResourceFile::StreamableResourceFile(const char* file_name) { Open(file_name); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ StreamableResourceFile::StreamableResourceFile(const char* file_name, Byte version_array[3], int match_level) { Open(file_name); int i; for (i=0; i> labOnly >> maxResourceID; // //------------------------------------------------------------------ // Read in main index table first, and make room for expansion later //------------------------------------------------------------------ // size_t *offset_table = new size_t[maxResourceID]; Register_Pointer(offset_table); diskFile.ReadBytes(offset_table, maxResourceID*sizeof(size_t)); resourceArraySize = maxResourceID + IndexBlockSize; resourceArray = new ResourceDescription*[resourceArraySize]; Register_Pointer(resourceArray); int i; for (i=0; i> buffer; // //------------------------------------------------- // If the preload flag is set, read in the resource //------------------------------------------------- // char *data = NULL; if (buffer.resourceFlags == ResourceDescription::Preload && buffer.resourceLength > 0) { data = new char[buffer.resourceLength]; Register_Pointer(data); diskFile.SetPointer(buffer.resourceOffset); diskFile.ReadBytes(data, buffer.resourceLength); } if (buffer.resourceType > ResourceDescription::MaxListResourceType || !data) { resourceArray[i] = AddResource( buffer.resourceName, buffer.resourceType, buffer.downloadPriority, buffer.resourceFlags, data, buffer.resourceLength, buffer.resourceID ); } else { resourceArray[i] = AddResourceList( buffer.resourceName, buffer.resourceType, buffer.downloadPriority, buffer.resourceFlags, (int*)data + 1, *(int*)data, buffer.resourceID ); } resourceArray[i]->offsetInFile = buffer.resourceOffset; if (data) { resourceArray[i]->Lock(); Unregister_Pointer(data); delete[] data; } } Unregister_Pointer(offset_table); delete[] offset_table; return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int StreamableResourceFile::Save() { Check(this); if (!resourceArray) { return False; } // //----------------------------------------------------------------------- // Make sure to load any unloaded resources before closing the input file //----------------------------------------------------------------------- // ResourceDescription *desc; ResourceDescription::ResourceID i; for (i=0; i<=maxResourceID; ++i) { desc = resourceArray[i]; if (desc) { Check(desc); desc->LoadResource(); } } // //------------------------------------------- // Close the current file, and open a new one //------------------------------------------- // if (diskFile.IsFileOpened()) { diskFile.Close(); } diskFile.Open(resourceFilename, True); Verify(diskFile.IsFileOpened()); // //------------------------------------- // Write out resource count and version //------------------------------------- // ++maxResourceID; diskFile.WriteBytes(&versionArray, sizeof(versionArray)); diskFile << labOnly << maxResourceID; // //-------------------------------------------------------------------------- // Write out main index table first. This is just filling up space, and the // offsets will have to be written back into this section later //-------------------------------------------------------------------------- // size_t *offset_table = new size_t[maxResourceID]; Register_Pointer(offset_table); diskFile.WriteBytes(offset_table, maxResourceID*sizeof(size_t)); // //------------------------------------------------------------------------- // Step through the index table, writing out each description as we find it //------------------------------------------------------------------------- // for (i=0; iresourceAddress, desc->resourceSize); // //-------------------------- // Write out the description //-------------------------- // offset_table[i] = diskFile.GetIndex(); buffer.resourceID = desc->resourceID; buffer.resourceType = desc->resourceType; //#if sizeof(buffer.resourceName) < sizeof(desc->resourceName) //# error ResourceDescription::resourceName is too big! //#endif memcpy( buffer.resourceName, desc->resourceName, sizeof(desc->resourceName) ); buffer.resourceLength = desc->resourceSize; buffer.downloadPriority = desc->downloadPriority; buffer.resourceFlags = desc->resourceFlags & ~ResourceDescription::LoadedFlag; diskFile << buffer; } diskFile.SetPointer( sizeof(maxResourceID) + sizeof(versionArray) + sizeof(labOnly) ); diskFile.WriteBytes(offset_table, maxResourceID*sizeof(long)); Unregister_Pointer(offset_table); delete(offset_table); --maxResourceID; diskFile.Close(); return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int StreamableResourceFile::SaveAs(const char* file_name) { Str_Copy(resourceFilename, file_name, sizeof(resourceFilename)); return Save(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StreamableResourceFile::LoadResource(ResourceDescription *res) { ResourceFile::LoadResource(res); Verify(!res->resourceAddress); res->resourceAddress = new char[res->resourceSize]; Register_Pointer(res->resourceAddress); diskFile.SetPointer(res->offsetInFile); diskFile.ReadBytes(res->resourceAddress, res->resourceSize); } //############################################################################# // StreamableResourceFile Test Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical StreamableResourceFile::TestInstance() const { return True; } #if defined(TEST_CLASS) #include "resource.tcp" #endif