1128 lines
32 KiB
C
1128 lines
32 KiB
C
|
//
|
||
|
// FakeResources.c
|
||
|
// ReClassicfication
|
||
|
//
|
||
|
// Created by Uli Kusterer on 20.02.13.
|
||
|
// Copyright (c) 2013 Uli Kusterer. All rights reserved.
|
||
|
//
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <string.h> // for memmove().
|
||
|
#include <unistd.h>
|
||
|
#include "FakeResources.h"
|
||
|
#include "EndianStuff.h"
|
||
|
|
||
|
|
||
|
// Turn this on if you want to read actual Mac resource forks on a Mac or Darwin
|
||
|
// but using the ANSI file APIs (uses Apple's "/..namedfork/rsrc" trick).
|
||
|
#define READ_REAL_RESOURCE_FORKS 1
|
||
|
|
||
|
|
||
|
/*
|
||
|
resource data offset 4 bytes
|
||
|
resource map offset 4 bytes
|
||
|
resource data length 4 bytes
|
||
|
resource map length 4 bytes
|
||
|
Reserved for system use 112 bytes
|
||
|
Application data 128 bytes
|
||
|
resource data ...
|
||
|
resource map ...
|
||
|
|
||
|
|
||
|
Resource data is 4-byte-long-counted, followed by actual data.
|
||
|
|
||
|
|
||
|
Resource map:
|
||
|
|
||
|
copy of resource header in RAM 16 bytes
|
||
|
next resource map in RAM 4 bytes
|
||
|
file reference number in RAM 2 bytes
|
||
|
Resource file attributes 2 bytes
|
||
|
type list offset (resource map-relative) 2 bytes
|
||
|
name list offset (resource map-relative) 2 bytes
|
||
|
*/
|
||
|
|
||
|
struct FakeResourceMap
|
||
|
{
|
||
|
struct FakeResourceMap* nextResourceMap;
|
||
|
bool dirty; // per-file tracking of whether FakeUpdateResFile() needs to write
|
||
|
FILE* fileDescriptor;
|
||
|
int16_t fileRefNum;
|
||
|
uint16_t resFileAttributes;
|
||
|
uint16_t numTypes;
|
||
|
struct FakeTypeListEntry* typeList;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
Type list:
|
||
|
|
||
|
number of types (-1) 2 bytes
|
||
|
resource type 4 bytes
|
||
|
number of resources (-1) 2 bytes
|
||
|
offset to reference list (type list relative) 2 bytes
|
||
|
*/
|
||
|
|
||
|
struct FakeTypeListEntry
|
||
|
{
|
||
|
uint32_t resourceType;
|
||
|
uint16_t numberOfResourcesOfType; // -1
|
||
|
struct FakeReferenceListEntry* resourceList;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
Reference list:
|
||
|
|
||
|
resource ID 2 bytes
|
||
|
resource name offset (relative to resource name list) 2 bytes
|
||
|
resource attributes 1 byte
|
||
|
resource data offset (resource data relative) 3 bytes
|
||
|
handle to resource in RAM 4 bytes
|
||
|
*/
|
||
|
|
||
|
struct FakeReferenceListEntry
|
||
|
{
|
||
|
int16_t resourceID;
|
||
|
uint8_t resourceAttributes;
|
||
|
Handle resourceHandle;
|
||
|
char resourceName[257]; // 257 = 1 Pascal length byte, 255 characters for actual string, 1 byte for C terminator \0.
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
Resource names are stored as byte-counted strings. (I.e. packed P-Strings)
|
||
|
Look-up by name is case-insensitive but case-preserving and diacritic-sensitive.
|
||
|
*/
|
||
|
|
||
|
|
||
|
struct FakeResourceMap * gResourceMap = NULL; // Linked list.
|
||
|
struct FakeResourceMap * gCurrResourceMap = NULL; // Start search of map here.
|
||
|
int16_t gFileRefNumSeed = 0;
|
||
|
int16_t gFakeResError = noErr;
|
||
|
struct FakeTypeCountEntry* gLoadedTypes = NULL;
|
||
|
int16_t gNumLoadedTypes = 0;
|
||
|
|
||
|
|
||
|
struct FakeTypeCountEntry
|
||
|
{
|
||
|
uint32_t type;
|
||
|
int16_t retainCount;
|
||
|
};
|
||
|
|
||
|
|
||
|
size_t FakeFWriteUInt32BE( uint32_t inInt, FILE* theFile )
|
||
|
{
|
||
|
inInt = BIG_ENDIAN_32(inInt);
|
||
|
return fwrite( &inInt, sizeof(inInt), 1, theFile );
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t FakeFWriteInt16BE( int16_t inInt, FILE* theFile )
|
||
|
{
|
||
|
inInt = BIG_ENDIAN_16(inInt);
|
||
|
return fwrite( &inInt, sizeof(inInt), 1, theFile );
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t FakeFWriteUInt16BE( uint16_t inInt, FILE* theFile )
|
||
|
{
|
||
|
inInt = BIG_ENDIAN_16(inInt);
|
||
|
return fwrite( &inInt, sizeof(inInt), 1, theFile );
|
||
|
}
|
||
|
|
||
|
|
||
|
void FakeFSeek( FILE* inFile, long inOffset, int inMode )
|
||
|
{
|
||
|
int theResult = fseek( inFile, inOffset, inMode );
|
||
|
if( theResult != 0 )
|
||
|
printf( "Seek to %ld result %d\n", inOffset, theResult );
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeResError()
|
||
|
{
|
||
|
return gFakeResError;
|
||
|
}
|
||
|
|
||
|
|
||
|
// To be able to iterate types across files without duplicates, we build a list
|
||
|
// of all types in open files and keep track of how many files contain each type
|
||
|
// by "retaining" each type and "releasing" it when a file closes.
|
||
|
void FakeRetainType( uint32_t resType )
|
||
|
{
|
||
|
if( gLoadedTypes == NULL )
|
||
|
{
|
||
|
gLoadedTypes = malloc( sizeof(struct FakeTypeCountEntry) );
|
||
|
gLoadedTypes[0].type = resType;
|
||
|
gLoadedTypes[0].retainCount = 1;
|
||
|
}
|
||
|
|
||
|
for( int x = 0; x < gNumLoadedTypes; x++ )
|
||
|
{
|
||
|
if( gLoadedTypes[x].type == resType )
|
||
|
{
|
||
|
gLoadedTypes[x].retainCount++;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gNumLoadedTypes++;
|
||
|
gLoadedTypes = realloc( gLoadedTypes, gNumLoadedTypes * sizeof(struct FakeTypeCountEntry) );
|
||
|
gLoadedTypes[gNumLoadedTypes -1].type = resType;
|
||
|
gLoadedTypes[gNumLoadedTypes -1].retainCount = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
// The converse of FakeRetainType (see for more info):
|
||
|
void FakeReleaseType( uint32_t resType )
|
||
|
{
|
||
|
for( int x = 0; x < gNumLoadedTypes; x++ )
|
||
|
{
|
||
|
if( gLoadedTypes[x].type == resType )
|
||
|
{
|
||
|
gLoadedTypes[x].retainCount--;
|
||
|
if( gLoadedTypes[x].retainCount == 0 )
|
||
|
{
|
||
|
gNumLoadedTypes--;
|
||
|
if( gNumLoadedTypes > 0 )
|
||
|
gLoadedTypes[x] = gLoadedTypes[gNumLoadedTypes];
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
struct FakeResourceMap* FakeFindResourceMap( int16_t inFileRefNum, struct FakeResourceMap*** outPrevMapPtr )
|
||
|
{
|
||
|
struct FakeResourceMap* currMap = gResourceMap;
|
||
|
if( outPrevMapPtr )
|
||
|
*outPrevMapPtr = &gResourceMap;
|
||
|
|
||
|
while( currMap != NULL && currMap->fileRefNum != inFileRefNum )
|
||
|
{
|
||
|
if( outPrevMapPtr )
|
||
|
*outPrevMapPtr = &currMap->nextResourceMap;
|
||
|
currMap = currMap->nextResourceMap;
|
||
|
}
|
||
|
return currMap;
|
||
|
}
|
||
|
|
||
|
|
||
|
struct FakeResourceMap* FakeResFileOpen( const char* inPath, const char* inMode )
|
||
|
{
|
||
|
FILE * theFile = fopen( inPath, inMode );
|
||
|
if( !theFile )
|
||
|
{
|
||
|
gFakeResError = fnfErr;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
uint32_t resourceDataOffset = 0;
|
||
|
uint32_t resourceMapOffset = 0;
|
||
|
uint32_t lengthOfResourceData = 0;
|
||
|
uint32_t lengthOfResourceMap = 0;
|
||
|
|
||
|
struct FakeResourceMap * newMap = calloc( 1, sizeof(struct FakeResourceMap) );
|
||
|
newMap->fileDescriptor = theFile;
|
||
|
newMap->fileRefNum = gFileRefNumSeed++;
|
||
|
|
||
|
if( fread( &resourceDataOffset, 1, sizeof(resourceDataOffset), theFile ) != sizeof(resourceDataOffset) )
|
||
|
{
|
||
|
gFakeResError = eofErr;
|
||
|
free( newMap );
|
||
|
newMap = NULL;
|
||
|
return NULL;
|
||
|
}
|
||
|
resourceDataOffset = BIG_ENDIAN_32(resourceDataOffset);
|
||
|
printf("resourceDataOffset %d\n", resourceDataOffset);
|
||
|
|
||
|
if( fread( &resourceMapOffset, 1, sizeof(resourceMapOffset), theFile ) != sizeof(resourceMapOffset) )
|
||
|
{
|
||
|
gFakeResError = eofErr;
|
||
|
free( newMap );
|
||
|
newMap = NULL;
|
||
|
return NULL;
|
||
|
}
|
||
|
resourceMapOffset = BIG_ENDIAN_32(resourceMapOffset);
|
||
|
printf("resourceMapOffset %d\n", resourceMapOffset);
|
||
|
|
||
|
if( fread( &lengthOfResourceData, 1, sizeof(lengthOfResourceData), theFile ) != sizeof(lengthOfResourceData) )
|
||
|
{
|
||
|
gFakeResError = eofErr;
|
||
|
free( newMap );
|
||
|
newMap = NULL;
|
||
|
return NULL;
|
||
|
}
|
||
|
lengthOfResourceData = BIG_ENDIAN_32(lengthOfResourceData);
|
||
|
|
||
|
if( fread( &lengthOfResourceMap, 1, sizeof(lengthOfResourceMap), theFile ) != sizeof(lengthOfResourceMap) )
|
||
|
{
|
||
|
gFakeResError = eofErr;
|
||
|
free( newMap );
|
||
|
newMap = NULL;
|
||
|
return NULL;
|
||
|
}
|
||
|
lengthOfResourceMap = BIG_ENDIAN_32(lengthOfResourceMap);
|
||
|
|
||
|
FakeFSeek( theFile, 112, SEEK_CUR ); // Skip system data.
|
||
|
FakeFSeek( theFile, 128, SEEK_CUR ); // Skip application data.
|
||
|
|
||
|
FakeFSeek( theFile, resourceMapOffset, SEEK_SET );
|
||
|
FakeFSeek( theFile, 16, SEEK_CUR ); // Skip resource file header copy.
|
||
|
FakeFSeek( theFile, 4, SEEK_CUR ); // Skip next resource map placeholder.
|
||
|
FakeFSeek( theFile, 2, SEEK_CUR ); // Skip file ref num placeholder.
|
||
|
fread( &newMap->resFileAttributes, 1, sizeof(uint16_t), theFile ); // Read file attributes.
|
||
|
newMap->resFileAttributes = BIG_ENDIAN_16(newMap->resFileAttributes);
|
||
|
printf("resFileAttributes %d\n", newMap->resFileAttributes);
|
||
|
|
||
|
uint16_t typeListOffset = 0;
|
||
|
uint16_t nameListOffset = 0;
|
||
|
|
||
|
fread( &typeListOffset, 1, sizeof(typeListOffset), theFile );
|
||
|
typeListOffset = BIG_ENDIAN_16(typeListOffset);
|
||
|
fread( &nameListOffset, 1, sizeof(nameListOffset), theFile );
|
||
|
nameListOffset = BIG_ENDIAN_16(nameListOffset);
|
||
|
|
||
|
long typeListSeekPos = resourceMapOffset +(long)typeListOffset;
|
||
|
printf("typeListSeekPos %ld\n", typeListSeekPos);
|
||
|
FakeFSeek( theFile, typeListSeekPos, SEEK_SET );
|
||
|
|
||
|
uint16_t numTypes = 0;
|
||
|
fread( &numTypes, 1, sizeof(numTypes), theFile );
|
||
|
numTypes = BIG_ENDIAN_16(numTypes) +1;
|
||
|
printf("numTypes %d\n", numTypes);
|
||
|
|
||
|
newMap->typeList = calloc( ((int)numTypes), sizeof(struct FakeTypeListEntry) );
|
||
|
newMap->numTypes = numTypes;
|
||
|
for( int x = 0; x < ((int)numTypes); x++ )
|
||
|
{
|
||
|
uint32_t currType = 0;
|
||
|
fread( &currType, 1, sizeof(uint32_t), theFile ); // Read type code (4CC).
|
||
|
char typeStr[5] = {0};
|
||
|
memmove( typeStr, &currType, 4 );
|
||
|
printf( "currType '%s'\n", typeStr );
|
||
|
currType = BIG_ENDIAN_32( currType );
|
||
|
newMap->typeList[x].resourceType = currType;
|
||
|
|
||
|
FakeRetainType( currType );
|
||
|
|
||
|
uint16_t numResources = 0;
|
||
|
fread( &numResources, 1, sizeof(numResources), theFile );
|
||
|
numResources = BIG_ENDIAN_16(numResources);
|
||
|
printf("\tnumResources %d\n", numResources +1);
|
||
|
|
||
|
uint16_t refListOffset = 0;
|
||
|
fread( &refListOffset, 1, sizeof(refListOffset), theFile );
|
||
|
refListOffset = BIG_ENDIAN_16(refListOffset);
|
||
|
|
||
|
long oldOffset = ftell(theFile);
|
||
|
|
||
|
long refListSeekPos = typeListSeekPos +(long)refListOffset;
|
||
|
printf("\trefListSeekPos %ld\n", refListSeekPos);
|
||
|
FakeFSeek( theFile, refListSeekPos, SEEK_SET );
|
||
|
|
||
|
newMap->typeList[x].resourceList = calloc( ((int)numResources) +1, sizeof(struct FakeReferenceListEntry) );
|
||
|
newMap->typeList[x].numberOfResourcesOfType = ((int)numResources) +1;
|
||
|
for( int y = 0; y < ((int)numResources) +1; y++ )
|
||
|
{
|
||
|
fread( &newMap->typeList[x].resourceList[y].resourceID, 1, sizeof(uint16_t), theFile );
|
||
|
newMap->typeList[x].resourceList[y].resourceID = BIG_ENDIAN_16(newMap->typeList[x].resourceList[y].resourceID);
|
||
|
|
||
|
uint16_t nameOffset = 0;
|
||
|
fread( &nameOffset, 1, sizeof(nameOffset), theFile );
|
||
|
nameOffset = BIG_ENDIAN_16(nameOffset);
|
||
|
|
||
|
unsigned char attributesAndDataOffset[4];
|
||
|
uint32_t dataOffset = 0;
|
||
|
fread( &attributesAndDataOffset, 1, sizeof(attributesAndDataOffset), theFile );
|
||
|
newMap->typeList[x].resourceList[y].resourceAttributes = attributesAndDataOffset[0];
|
||
|
memmove( ((char*)&dataOffset) +1, attributesAndDataOffset +1, 3 );
|
||
|
dataOffset = BIG_ENDIAN_32(dataOffset);
|
||
|
FakeFSeek( theFile, 4, SEEK_CUR ); // Skip resource Handle placeholder.
|
||
|
|
||
|
long innerOldOffset = ftell(theFile);
|
||
|
long dataSeekPos = resourceDataOffset +(long)dataOffset;
|
||
|
FakeFSeek( theFile, dataSeekPos, SEEK_SET );
|
||
|
uint32_t dataLength = 0;
|
||
|
fread( &dataLength, 1, sizeof(dataLength), theFile );
|
||
|
dataLength = BIG_ENDIAN_32(dataLength);
|
||
|
newMap->typeList[x].resourceList[y].resourceHandle = FakeNewHandle(dataLength);
|
||
|
fread( (*newMap->typeList[x].resourceList[y].resourceHandle), 1, dataLength, theFile );
|
||
|
|
||
|
if( -1 != (long)nameOffset )
|
||
|
{
|
||
|
long nameSeekPos = resourceMapOffset +(long)nameListOffset +(long)nameOffset;
|
||
|
FakeFSeek( theFile, nameSeekPos, SEEK_SET );
|
||
|
uint8_t nameLength = 0;
|
||
|
fread( &nameLength, 1, sizeof(nameLength), theFile );
|
||
|
newMap->typeList[x].resourceList[y].resourceName[0] = nameLength;
|
||
|
if( nameLength > 0 )
|
||
|
fread( newMap->typeList[x].resourceList[y].resourceName +1, 1, nameLength, theFile );
|
||
|
}
|
||
|
|
||
|
printf( "\t%d: \"%s\"\n", newMap->typeList[x].resourceList[y].resourceID, newMap->typeList[x].resourceList[y].resourceName +1 );
|
||
|
|
||
|
FakeFSeek( theFile, innerOldOffset, SEEK_SET );
|
||
|
}
|
||
|
|
||
|
FakeFSeek( theFile, oldOffset, SEEK_SET );
|
||
|
}
|
||
|
|
||
|
newMap->nextResourceMap = gResourceMap;
|
||
|
gResourceMap = newMap;
|
||
|
gFakeResError = noErr;
|
||
|
|
||
|
gCurrResourceMap = gResourceMap;
|
||
|
|
||
|
return newMap;
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeOpenResFile( const unsigned char* inPath )
|
||
|
{
|
||
|
#if READ_REAL_RESOURCE_FORKS
|
||
|
const char* resForkSuffix = "/..namedfork/rsrc";
|
||
|
#endif // READ_REAL_RESOURCE_FORKS
|
||
|
char thePath[256 +17] = {0};
|
||
|
memmove(thePath,inPath +1,inPath[0]);
|
||
|
#if READ_REAL_RESOURCE_FORKS
|
||
|
memmove(thePath +inPath[0],resForkSuffix,17);
|
||
|
#endif // READ_REAL_RESOURCE_FORKS
|
||
|
struct FakeResourceMap* theMap = FakeResFileOpen( thePath, "r+" );
|
||
|
if( !theMap )
|
||
|
theMap = FakeResFileOpen( thePath, "r" );
|
||
|
if( theMap )
|
||
|
return theMap->fileRefNum;
|
||
|
else
|
||
|
return gFakeResError;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool FakeFindResourceHandleInMap( Handle theResource, struct FakeTypeListEntry** outTypeEntry, struct FakeReferenceListEntry** outRefEntry, struct FakeResourceMap* inMap )
|
||
|
{
|
||
|
if( (theResource != NULL) && (inMap != NULL) )
|
||
|
{
|
||
|
for( int x = 0; x < inMap->numTypes; x++ )
|
||
|
{
|
||
|
for( int y = 0; y < inMap->typeList[x].numberOfResourcesOfType; y++ )
|
||
|
{
|
||
|
if( inMap->typeList[x].resourceList[y].resourceHandle == theResource )
|
||
|
{
|
||
|
if (outTypeEntry)
|
||
|
{
|
||
|
*outTypeEntry = &inMap->typeList[x];
|
||
|
}
|
||
|
|
||
|
if (outRefEntry)
|
||
|
{
|
||
|
*outRefEntry = &inMap->typeList[x].resourceList[y];
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (outTypeEntry)
|
||
|
{
|
||
|
*outTypeEntry = NULL;
|
||
|
}
|
||
|
|
||
|
if (outRefEntry)
|
||
|
{
|
||
|
*outRefEntry = NULL;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool FakeFindResourceHandle( Handle theResource, struct FakeResourceMap** outMap, struct FakeTypeListEntry** outTypeEntry, struct FakeReferenceListEntry** outRefEntry )
|
||
|
{
|
||
|
struct FakeResourceMap* currMap = gResourceMap;
|
||
|
while( currMap != NULL )
|
||
|
{
|
||
|
if( FakeFindResourceHandleInMap(theResource, outTypeEntry, outRefEntry, currMap) )
|
||
|
{
|
||
|
if( outMap )
|
||
|
{
|
||
|
*outMap = currMap;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
currMap = currMap->nextResourceMap;
|
||
|
}
|
||
|
|
||
|
if ( outMap )
|
||
|
{
|
||
|
*outMap = NULL;
|
||
|
}
|
||
|
|
||
|
if (outTypeEntry)
|
||
|
{
|
||
|
*outTypeEntry = NULL;
|
||
|
}
|
||
|
|
||
|
if (outRefEntry)
|
||
|
{
|
||
|
*outRefEntry = NULL;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
static struct FakeTypeListEntry* FakeFindTypeListEntry(struct FakeResourceMap* inMap, uint32_t theType)
|
||
|
{
|
||
|
if( inMap != NULL )
|
||
|
{
|
||
|
for( int x = 0; x < inMap->numTypes; x++ )
|
||
|
{
|
||
|
if( inMap->typeList[x].resourceType == theType )
|
||
|
{
|
||
|
return &inMap->typeList[x];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int16_t FakeHomeResFile( Handle theResource )
|
||
|
{
|
||
|
struct FakeResourceMap* currMap = NULL;
|
||
|
|
||
|
if( FakeFindResourceHandle( theResource, &currMap, NULL, NULL) )
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
return currMap->fileRefNum;
|
||
|
}
|
||
|
|
||
|
gFakeResError = resNotFound;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FakeUpdateResFile( int16_t inFileRefNum )
|
||
|
{
|
||
|
const long kResourceHeaderLength = 16;
|
||
|
const long kResourceHeaderMapOffsetPos = 4;
|
||
|
const long kResourceHeaderMapLengthPos = 4 + 4 + 4;
|
||
|
const long kResourceHeaderReservedLength = 112;
|
||
|
const long kResourceHeaderAppReservedLength = 128;
|
||
|
const long kReservedHeaderLength = kResourceHeaderReservedLength + kResourceHeaderAppReservedLength;
|
||
|
const long kResourceDataSizeLength = 4;
|
||
|
const long kResourceMapNextHandleLength = 4;
|
||
|
const long kResourceMapFileRefLength = 2;
|
||
|
const long kResourceMapTypeListOffsetLength = 2;
|
||
|
const long kResourceMapNameListOffsetLength = 2;
|
||
|
const long kResourceMapNumTypesLength = 2;
|
||
|
const long kResourceRefLength = 2 + 2 + 1 + 3 + 4;
|
||
|
const long kResourceTypeLength = 4 + 2 + 2;
|
||
|
|
||
|
struct FakeResourceMap* currMap = FakeFindResourceMap( inFileRefNum, NULL );
|
||
|
long headerLength = kResourceHeaderLength + kReservedHeaderLength;
|
||
|
uint32_t resMapOffset = 0;
|
||
|
long refListSize = 0;
|
||
|
|
||
|
if (!currMap->dirty)
|
||
|
return;
|
||
|
|
||
|
// Write header:
|
||
|
FakeFSeek( currMap->fileDescriptor, 0, SEEK_SET );
|
||
|
uint32_t resDataOffset = (uint32_t)headerLength;
|
||
|
FakeFWriteUInt32BE( resDataOffset, currMap->fileDescriptor );
|
||
|
FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // placeholder offset to resource map
|
||
|
FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // placeholder resource data length
|
||
|
FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // placeholder resource map length
|
||
|
|
||
|
// reserved
|
||
|
for( int x = 0; x < (kResourceHeaderReservedLength / sizeof(uint32_t)); x++ )
|
||
|
FakeFWriteUInt32BE( 0, currMap->fileDescriptor );
|
||
|
for( int x = 0; x < (kResourceHeaderAppReservedLength / sizeof(uint32_t)); x++ )
|
||
|
FakeFWriteUInt32BE( 0, currMap->fileDescriptor );
|
||
|
|
||
|
resMapOffset = (uint32_t)headerLength;
|
||
|
|
||
|
// Write out data for each resource and calculate space needed:
|
||
|
for( int x = 0; x < currMap->numTypes; x++ )
|
||
|
{
|
||
|
for( int y = 0; y < currMap->typeList[x].numberOfResourcesOfType; y++ )
|
||
|
{
|
||
|
uint32_t theSize = (uint32_t)FakeGetHandleSize( currMap->typeList[x].resourceList[y].resourceHandle );
|
||
|
FakeFWriteUInt32BE( theSize, currMap->fileDescriptor );
|
||
|
resMapOffset += sizeof(theSize);
|
||
|
fwrite( *currMap->typeList[x].resourceList[y].resourceHandle, 1, theSize, currMap->fileDescriptor );
|
||
|
resMapOffset += theSize;
|
||
|
}
|
||
|
|
||
|
refListSize += currMap->typeList[x].numberOfResourcesOfType * kResourceRefLength;
|
||
|
}
|
||
|
|
||
|
// Write out what we know into the header now:
|
||
|
FakeFSeek( currMap->fileDescriptor, kResourceHeaderMapOffsetPos, SEEK_SET );
|
||
|
FakeFWriteUInt32BE( resMapOffset, currMap->fileDescriptor );
|
||
|
uint32_t resDataLength = resMapOffset -(uint32_t)headerLength;
|
||
|
FakeFWriteUInt32BE( resDataLength, currMap->fileDescriptor );
|
||
|
|
||
|
// Start writing resource map after data:
|
||
|
uint32_t resMapLength = 0;
|
||
|
FakeFSeek( currMap->fileDescriptor, resMapOffset, SEEK_SET );
|
||
|
|
||
|
// Copy what we know from the resource header
|
||
|
FakeFWriteUInt32BE( resDataOffset, currMap->fileDescriptor );
|
||
|
FakeFWriteUInt32BE( resMapOffset, currMap->fileDescriptor );
|
||
|
FakeFWriteUInt32BE( resDataLength, currMap->fileDescriptor );
|
||
|
FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // Placeholder
|
||
|
|
||
|
// Fake a next handle
|
||
|
FakeFWriteUInt32BE( 0, currMap->fileDescriptor );
|
||
|
|
||
|
resMapLength += kResourceHeaderLength + kResourceMapNextHandleLength + kResourceMapFileRefLength; // reserved: copy of resource header, next resource handle, file ref
|
||
|
FakeFWriteInt16BE( inFileRefNum, currMap->fileDescriptor );
|
||
|
FakeFWriteUInt16BE( currMap->resFileAttributes, currMap->fileDescriptor );
|
||
|
resMapLength += sizeof(uint16_t);
|
||
|
|
||
|
uint16_t typeListOffset = ftell(currMap->fileDescriptor)
|
||
|
+kResourceMapTypeListOffsetLength +kResourceMapNameListOffsetLength -resMapOffset;
|
||
|
FakeFWriteUInt16BE( typeListOffset, currMap->fileDescriptor ); // Res map relative, points to the type count
|
||
|
long refListStartPosition = typeListOffset + kResourceMapNumTypesLength + currMap->numTypes * kResourceTypeLength; // Calc where we'll start to put resource lists (right after types).
|
||
|
|
||
|
uint16_t nameListOffset = refListStartPosition +refListSize; // Calc where we'll start to put name lists (right after resource lists).
|
||
|
FakeFWriteUInt16BE( nameListOffset, currMap->fileDescriptor ); // Res map relative.
|
||
|
|
||
|
// Now write type list and ref lists:
|
||
|
uint32_t nameListStartOffset = 0;
|
||
|
FakeFWriteUInt16BE( currMap->numTypes -1, currMap->fileDescriptor );
|
||
|
uint32_t resDataCurrOffset = 0; // Keep track of where we wrote the associated data for each resource, relative to the start of resource data
|
||
|
|
||
|
refListStartPosition = kResourceMapNumTypesLength + currMap->numTypes * kResourceTypeLength; // relative to beginning of resource type list
|
||
|
|
||
|
for( int x = 0; x < currMap->numTypes; x++ )
|
||
|
{
|
||
|
// Write entry for this type:
|
||
|
uint32_t currType = currMap->typeList[x].resourceType;
|
||
|
FakeFWriteUInt32BE( currType, currMap->fileDescriptor );
|
||
|
|
||
|
uint16_t numResources = currMap->typeList[x].numberOfResourcesOfType -1;
|
||
|
FakeFWriteUInt16BE( numResources, currMap->fileDescriptor );
|
||
|
|
||
|
uint16_t refListOffset = refListStartPosition;
|
||
|
FakeFWriteUInt16BE( refListOffset, currMap->fileDescriptor );
|
||
|
|
||
|
// Jump to ref list location and write ref list out:
|
||
|
long oldOffsetAfterPrevType = ftell(currMap->fileDescriptor);
|
||
|
|
||
|
FakeFSeek( currMap->fileDescriptor, resMapOffset + typeListOffset + refListStartPosition, SEEK_SET );
|
||
|
|
||
|
for( int y = 0; y < currMap->typeList[x].numberOfResourcesOfType; y++ )
|
||
|
{
|
||
|
FakeFWriteInt16BE( currMap->typeList[x].resourceList[y].resourceID, currMap->fileDescriptor );
|
||
|
|
||
|
// Write name to name table:
|
||
|
if( currMap->typeList[x].resourceList[y].resourceName[0] == 0 )
|
||
|
FakeFWriteInt16BE( -1, currMap->fileDescriptor ); // Don't have a name, mark as -1.
|
||
|
else
|
||
|
{
|
||
|
FakeFWriteUInt16BE( nameListStartOffset, currMap->fileDescriptor ); // Associate name in name table with this.
|
||
|
|
||
|
long oldOffsetAfterNameOffset = ftell( currMap->fileDescriptor );
|
||
|
FakeFSeek( currMap->fileDescriptor, resMapOffset +nameListOffset +nameListStartOffset, SEEK_SET );
|
||
|
fwrite( currMap->typeList[x].resourceList[y].resourceName, currMap->typeList[x].resourceList[y].resourceName[0] +1, sizeof(uint8_t), currMap->fileDescriptor );
|
||
|
|
||
|
long currMapLen = (ftell(currMap->fileDescriptor) -resMapOffset);
|
||
|
if( currMapLen > resMapLength )
|
||
|
resMapLength = (uint32_t)currMapLen;
|
||
|
|
||
|
FakeFSeek( currMap->fileDescriptor, oldOffsetAfterNameOffset, SEEK_SET );
|
||
|
nameListStartOffset += currMap->typeList[x].resourceList[y].resourceName[0] +1; // Make sure we write next name *after* this one.
|
||
|
}
|
||
|
|
||
|
fwrite( &currMap->typeList[x].resourceList[y].resourceAttributes, 1, sizeof(uint8_t), currMap->fileDescriptor );
|
||
|
uint32_t resDataCurrOffsetBE = BIG_ENDIAN_32(resDataCurrOffset);
|
||
|
fwrite( ((uint8_t*)&resDataCurrOffsetBE) +1, 1, 3, currMap->fileDescriptor );
|
||
|
resDataCurrOffset += kResourceDataSizeLength + FakeGetHandleSize(currMap->typeList[x].resourceList[y].resourceHandle);
|
||
|
FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // Handle placeholder.
|
||
|
|
||
|
long currMapLen = (ftell(currMap->fileDescriptor) -resMapOffset);
|
||
|
if( currMapLen > resMapLength )
|
||
|
resMapLength = (uint32_t)currMapLen;
|
||
|
}
|
||
|
|
||
|
refListStartPosition += currMap->typeList[x].numberOfResourcesOfType * kResourceRefLength;
|
||
|
|
||
|
// Jump back to after our type entry so we can write the next one:
|
||
|
FakeFSeek( currMap->fileDescriptor, oldOffsetAfterPrevType, SEEK_SET );
|
||
|
}
|
||
|
|
||
|
// Write res map length:
|
||
|
FakeFSeek( currMap->fileDescriptor, kResourceHeaderMapLengthPos, SEEK_SET );
|
||
|
FakeFWriteUInt32BE( resMapLength, currMap->fileDescriptor );
|
||
|
FakeFSeek( currMap->fileDescriptor, resMapOffset + kResourceHeaderMapLengthPos, SEEK_SET );
|
||
|
FakeFWriteUInt32BE( resMapLength, currMap->fileDescriptor );
|
||
|
|
||
|
ftruncate(fileno(currMap->fileDescriptor), resMapOffset + resMapLength);
|
||
|
|
||
|
currMap->dirty = false;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FakeRedirectResFileToPath( int16_t inFileRefNum, const char* cPath )
|
||
|
{
|
||
|
struct FakeResourceMap** prevMapPtr = NULL;
|
||
|
struct FakeResourceMap* currMap = FakeFindResourceMap( inFileRefNum, &prevMapPtr );
|
||
|
if( currMap )
|
||
|
{
|
||
|
fclose( currMap->fileDescriptor );
|
||
|
currMap->fileDescriptor = fopen( cPath, "w" );
|
||
|
currMap->dirty = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void FakeCloseResFile( int16_t inFileRefNum )
|
||
|
{
|
||
|
struct FakeResourceMap** prevMapPtr = NULL;
|
||
|
struct FakeResourceMap* currMap = FakeFindResourceMap( inFileRefNum, &prevMapPtr );
|
||
|
if( currMap )
|
||
|
{
|
||
|
FakeUpdateResFile(inFileRefNum);
|
||
|
|
||
|
*prevMapPtr = currMap->nextResourceMap; // Remove this from the linked list.
|
||
|
if( gCurrResourceMap == currMap )
|
||
|
gCurrResourceMap = currMap->nextResourceMap;
|
||
|
|
||
|
for( int x = 0; x < currMap->numTypes; x++ )
|
||
|
{
|
||
|
FakeReleaseType( currMap->typeList[x].resourceType );
|
||
|
|
||
|
for( int y = 0; y < currMap->typeList[x].numberOfResourcesOfType; y++ )
|
||
|
{
|
||
|
FakeDisposeHandle( currMap->typeList[x].resourceList[y].resourceHandle );
|
||
|
}
|
||
|
free( currMap->typeList[x].resourceList );
|
||
|
}
|
||
|
free( currMap->typeList );
|
||
|
|
||
|
fclose( currMap->fileDescriptor );
|
||
|
free( currMap );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
Handle FakeGet1ResourceFromMap( uint32_t resType, int16_t resID, struct FakeResourceMap* inMap )
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
|
||
|
if( inMap != NULL )
|
||
|
{
|
||
|
for( int x = 0; x < inMap->numTypes; x++ )
|
||
|
{
|
||
|
uint32_t currType = inMap->typeList[x].resourceType;
|
||
|
if( currType == resType )
|
||
|
{
|
||
|
for( int y = 0; y < inMap->typeList[x].numberOfResourcesOfType; y++ )
|
||
|
{
|
||
|
if( inMap->typeList[x].resourceList[y].resourceID == resID )
|
||
|
{
|
||
|
return inMap->typeList[x].resourceList[y].resourceHandle;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gFakeResError = resNotFound;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
Handle FakeGet1Resource( uint32_t resType, int16_t resID )
|
||
|
{
|
||
|
return FakeGet1ResourceFromMap( resType, resID, gCurrResourceMap );
|
||
|
}
|
||
|
|
||
|
|
||
|
Handle FakeGetResource( uint32_t resType, int16_t resID )
|
||
|
{
|
||
|
struct FakeResourceMap * currMap = gCurrResourceMap;
|
||
|
Handle theRes = NULL;
|
||
|
|
||
|
while( theRes == NULL && currMap != NULL )
|
||
|
{
|
||
|
theRes = FakeGet1ResourceFromMap( resType, resID, currMap );
|
||
|
if( theRes != NULL )
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
return theRes;
|
||
|
}
|
||
|
|
||
|
currMap = currMap->nextResourceMap;
|
||
|
}
|
||
|
|
||
|
gFakeResError = resNotFound;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeCount1ResourcesInMap( uint32_t resType, struct FakeResourceMap* inMap )
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
|
||
|
if( inMap != NULL )
|
||
|
{
|
||
|
for( int x = 0; x < inMap->numTypes; x++ )
|
||
|
{
|
||
|
uint32_t currType = inMap->typeList[x].resourceType;
|
||
|
if( currType == resType )
|
||
|
return inMap->typeList[x].numberOfResourcesOfType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeCount1TypesInMap( struct FakeResourceMap* inMap )
|
||
|
{
|
||
|
if( inMap == NULL )
|
||
|
return 0;
|
||
|
|
||
|
return inMap->numTypes;
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeCount1Types()
|
||
|
{
|
||
|
return FakeCount1TypesInMap( gCurrResourceMap );
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeCount1Resources( uint32_t resType )
|
||
|
{
|
||
|
return FakeCount1ResourcesInMap( resType, gCurrResourceMap );
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeCountResources( uint32_t resType )
|
||
|
{
|
||
|
int16_t numRes = 0;
|
||
|
struct FakeResourceMap* theMap = gCurrResourceMap;
|
||
|
|
||
|
while( theMap )
|
||
|
{
|
||
|
numRes += FakeCount1ResourcesInMap( resType, theMap );
|
||
|
|
||
|
theMap = theMap->nextResourceMap;
|
||
|
}
|
||
|
|
||
|
return numRes;
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeCountTypes()
|
||
|
{
|
||
|
return gNumLoadedTypes;
|
||
|
}
|
||
|
|
||
|
|
||
|
int16_t FakeCurResFile()
|
||
|
{
|
||
|
struct FakeResourceMap* currMap = gCurrResourceMap;
|
||
|
|
||
|
if( !currMap )
|
||
|
return 0;
|
||
|
|
||
|
return currMap->fileRefNum;
|
||
|
}
|
||
|
|
||
|
void FakeUseResFile( int16_t resRefNum )
|
||
|
{
|
||
|
struct FakeResourceMap* currMap = FakeFindResourceMap( resRefNum, NULL );
|
||
|
if( !currMap )
|
||
|
currMap = gResourceMap;
|
||
|
|
||
|
gCurrResourceMap = currMap;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FakeGet1IndType( uint32_t * resType, int16_t index )
|
||
|
{
|
||
|
if( resType == NULL )
|
||
|
return;
|
||
|
|
||
|
*resType = 0;
|
||
|
|
||
|
struct FakeResourceMap* currMap = gCurrResourceMap;
|
||
|
if( (index <= 0) || (index > FakeCount1Types()) || !currMap )
|
||
|
{
|
||
|
gFakeResError = resNotFound;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
*resType = currMap->typeList[index-1].resourceType;
|
||
|
|
||
|
gFakeResError = noErr;
|
||
|
}
|
||
|
|
||
|
Handle FakeGet1IndResource( uint32_t resType, int16_t index )
|
||
|
{
|
||
|
struct FakeResourceMap* currMap = gCurrResourceMap;
|
||
|
|
||
|
if( !currMap || (index <= 0) || (index > FakeCount1Resources(resType)))
|
||
|
{
|
||
|
gFakeResError = resNotFound;
|
||
|
}
|
||
|
|
||
|
for( int x = 0; x < currMap->numTypes; x++ )
|
||
|
{
|
||
|
uint32_t currType = currMap->typeList[x].resourceType;
|
||
|
if( currType == resType )
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
return currMap->typeList[x].resourceList[index-1].resourceHandle;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gFakeResError = resNotFound;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void FakeGetResInfo( Handle theResource, int16_t * theID, uint32_t * theType, FakeStr255 * name )
|
||
|
{
|
||
|
struct FakeTypeListEntry* typeEntry = NULL;
|
||
|
struct FakeReferenceListEntry* refEntry = NULL;
|
||
|
|
||
|
|
||
|
if( FakeFindResourceHandle(theResource, NULL, &typeEntry, &refEntry) )
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
if( theID )
|
||
|
{
|
||
|
*theID = refEntry->resourceID;
|
||
|
}
|
||
|
|
||
|
if( theType )
|
||
|
{
|
||
|
*theType = typeEntry->resourceType;
|
||
|
}
|
||
|
|
||
|
if( name )
|
||
|
{
|
||
|
memcpy(name, refEntry->resourceName, sizeof(FakeStr255));
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
gFakeResError = resNotFound;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FakeSetResInfo( Handle theResource, int16_t theID, FakeStr255 name )
|
||
|
{
|
||
|
struct FakeReferenceListEntry* refEntry = NULL;
|
||
|
|
||
|
if( !theResource || !FakeFindResourceHandle( theResource, NULL, NULL, &refEntry) )
|
||
|
{
|
||
|
gFakeResError = resNotFound;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( (refEntry->resourceAttributes & resProtected) != 0 )
|
||
|
{
|
||
|
gFakeResError = resAttrErr;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
refEntry->resourceID = theID;
|
||
|
memcpy(refEntry->resourceName, name, sizeof(FakeStr255));
|
||
|
|
||
|
gFakeResError = noErr;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FakeAddResource( Handle theData, uint32_t theType, int16_t theID, FakeStr255 name )
|
||
|
{
|
||
|
struct FakeResourceMap* currMap = gCurrResourceMap;
|
||
|
struct FakeTypeListEntry* typeEntry = NULL;
|
||
|
struct FakeReferenceListEntry* resourceEntry = NULL;
|
||
|
|
||
|
// AddResource() only ensures that the handle is not a resource, but doesn't check whether the type/ID are already in use
|
||
|
if( !theData || FakeFindResourceHandleInMap( theData, &typeEntry, &resourceEntry, currMap ) )
|
||
|
{
|
||
|
gFakeResError = addResFailed;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
typeEntry = FakeFindTypeListEntry( currMap, theType );
|
||
|
if( !typeEntry )
|
||
|
{
|
||
|
currMap->numTypes++;
|
||
|
currMap->typeList = realloc(currMap->typeList, currMap->numTypes * sizeof(struct FakeTypeListEntry));
|
||
|
|
||
|
typeEntry = currMap->typeList + (currMap->numTypes - 1);
|
||
|
typeEntry->resourceType = theType;
|
||
|
typeEntry->numberOfResourcesOfType = 0;
|
||
|
typeEntry->resourceList = NULL;
|
||
|
|
||
|
FakeRetainType(theType);
|
||
|
}
|
||
|
|
||
|
typeEntry->numberOfResourcesOfType++;
|
||
|
|
||
|
if( typeEntry->resourceList )
|
||
|
{
|
||
|
typeEntry->resourceList = realloc( typeEntry->resourceList, typeEntry->numberOfResourcesOfType * sizeof(struct FakeReferenceListEntry) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
typeEntry->resourceList = calloc(typeEntry->numberOfResourcesOfType, sizeof(struct FakeReferenceListEntry));
|
||
|
}
|
||
|
|
||
|
resourceEntry = typeEntry->resourceList + ( typeEntry->numberOfResourcesOfType - 1 );
|
||
|
resourceEntry->resourceAttributes = 0;
|
||
|
resourceEntry->resourceID = theID;
|
||
|
memcpy(resourceEntry->resourceName, name, sizeof(FakeStr255));
|
||
|
resourceEntry->resourceHandle = theData;
|
||
|
|
||
|
currMap->dirty = true;
|
||
|
|
||
|
gFakeResError = noErr;
|
||
|
}
|
||
|
|
||
|
void FakeChangedResource( Handle theResource )
|
||
|
{
|
||
|
struct FakeResourceMap* theMap = NULL;
|
||
|
struct FakeReferenceListEntry* theEntry = NULL;
|
||
|
if( !FakeFindResourceHandle( theResource, &theMap, NULL, &theEntry ) )
|
||
|
{
|
||
|
gFakeResError = resNotFound;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( (theEntry->resourceAttributes & resProtected) == 0 )
|
||
|
{
|
||
|
theMap->dirty = true;
|
||
|
gFakeResError = noErr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gFakeResError = resAttrErr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE: you must call DisposeHandle(theResource) manually to release the memory. Normally,
|
||
|
// the Resource Manager will dispose the handle on update or file close, but this implementation
|
||
|
// does not track removed resource handles for later disposal.
|
||
|
void FakeRemoveResource( Handle theResource )
|
||
|
{
|
||
|
struct FakeResourceMap* currMap = gCurrResourceMap;
|
||
|
struct FakeTypeListEntry* typeEntry = NULL;
|
||
|
struct FakeReferenceListEntry* resEntry = NULL;
|
||
|
if( !currMap || !FakeFindResourceHandleInMap( theResource, &typeEntry, &resEntry, currMap ) || ((resEntry->resourceAttributes & resProtected) != 0) )
|
||
|
{
|
||
|
gFakeResError = rmvResFailed;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
struct FakeReferenceListEntry* nextResEntry = resEntry + 1;
|
||
|
int resourcesListSize = typeEntry->numberOfResourcesOfType * sizeof(struct FakeReferenceListEntry);
|
||
|
long nextResEntryOffset = (void*)nextResEntry - (void*)typeEntry->resourceList;
|
||
|
|
||
|
typeEntry->numberOfResourcesOfType--;
|
||
|
|
||
|
if( typeEntry->numberOfResourcesOfType > 0 )
|
||
|
{
|
||
|
memcpy( resEntry, nextResEntry, resourcesListSize - nextResEntryOffset );
|
||
|
typeEntry->resourceList = realloc( typeEntry->resourceList, resourcesListSize - sizeof(struct FakeReferenceListEntry) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// got rid of the last resource reference, release the memory
|
||
|
free(typeEntry->resourceList);
|
||
|
typeEntry->resourceList = NULL;
|
||
|
|
||
|
// now remove the type entry
|
||
|
struct FakeTypeListEntry* nextTypeEntry = typeEntry + 1;
|
||
|
int typeListSize = currMap->numTypes * sizeof(struct FakeTypeListEntry);
|
||
|
long nextTypeEntryOffset = (void*)nextTypeEntry - (void*)currMap->typeList;
|
||
|
|
||
|
currMap->numTypes--;
|
||
|
FakeReleaseType(typeEntry->resourceType);
|
||
|
|
||
|
if( currMap->numTypes > 0 )
|
||
|
{
|
||
|
memcpy( typeEntry, nextTypeEntry, typeListSize - nextTypeEntryOffset );
|
||
|
currMap->typeList = realloc( currMap->typeList, typeListSize - sizeof(struct FakeTypeListEntry) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// got rid of the last type entry
|
||
|
free(currMap->typeList);
|
||
|
currMap->typeList = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
currMap->dirty = true;
|
||
|
gFakeResError = noErr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// NOTE: effectively a no-op since we don't have a way to write a resource without writing the whole map
|
||
|
void FakeWriteResource( Handle theResource )
|
||
|
{
|
||
|
struct FakeReferenceListEntry* resEntry = NULL;
|
||
|
if( !theResource || !FakeFindResourceHandle( theResource, NULL, NULL, &resEntry ))
|
||
|
{
|
||
|
gFakeResError = resNotFound;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE: effectively a no-op since we don't have a way to load an individual resource from disk right now.
|
||
|
// All resources are already loaded at file open time.
|
||
|
void FakeLoadResource( Handle theResource )
|
||
|
{
|
||
|
struct FakeReferenceListEntry* resEntry = NULL;
|
||
|
if( !theResource || !FakeFindResourceHandle( theResource, NULL, NULL, &resEntry ))
|
||
|
{
|
||
|
gFakeResError = resNotFound;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE: effectively a no-op since we don't have a way to reload a released resource from disk right now
|
||
|
void FakeReleaseResource( Handle theResource )
|
||
|
{
|
||
|
struct FakeReferenceListEntry* resEntry = NULL;
|
||
|
if( !theResource || !FakeFindResourceHandle( theResource, NULL, NULL, &resEntry ))
|
||
|
{
|
||
|
gFakeResError = resNotFound;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gFakeResError = noErr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void FakeSetResLoad(bool load)
|
||
|
{
|
||
|
// NOTE: a no-op since resources are always loaded at file open time
|
||
|
}
|
||
|
|
||
|
|
||
|
|