//macfileio.cpp //mac-specific file handling code. #include #include #include "fileio.h" #include "gamemem.h" #include "error.h" #include "config.h" #include "screen.h" extern "C"{ #include "compress.h" } #define kFileNotPackaged -1 //System specific unique file locator typedef struct{ SInt16 vRefNum; SInt16 unused; SInt32 dirID; Str255 pName; unsigned int packageOffset,packageSize; } tFileSystemLocator; //fills an FSSpecPtr with the file system information for //the host application's Bundle directory OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr) { FSRef location; CFBundleRef refMainBundle = NULL; CFURLRef refMainBundleURL = NULL; refMainBundle = CFBundleGetMainBundle(); refMainBundleURL = CFBundleCopyBundleURL (refMainBundle); CFURLGetFSRef(refMainBundleURL,&location); return FSGetCatalogInfo(&location,kFSCatInfoNone,NULL,NULL,theFSSpecPtr,NULL); } typedef struct{ unsigned int offset,unPackedSize,packedSize; char name[256]; }tPackFileHeaderEntry; typedef struct{ char magic[8]; int numEntries; int replaceFlag,unused2,unused3; tPackFileHeaderEntry entries[]; }tPackFileHeader; #define kMagicString "R3Dl1n3" tFileRef SimpleFileGetReference(char *name,tFileTableEntry *fileTable,int fileTableSize) { for(int i=0;imagic,kMagicString)) return; int numEntries=EndianU32_BtoN(header->numEntries); DisposePtr((Ptr)header); HandleError(SetFPos(ref,fsFromStart,0)); headerSize=sizeof(tPackFileHeader)+sizeof(tPackFileHeaderEntry)*numEntries; header=(tPackFileHeader*)NewPtr(headerSize); HandleError(FSRead(ref,&headerSize,header)); for(int i=0;ientries[i].name,fileTable,*fileTableSize); int replaceable=false; if(exists) { char *extension=FileGetExtension(i); if(extension) replaceable=(_stricmp(extension,kFileTypeCarDefinition)&&_stricmp(extension,kFileTypeMapDefinition)); else replaceable=true; } if(exists==-1||(header->replaceFlag&&replaceable)) { tFileRef ref; if(exists==-1) ref=(*fileTableSize)++; else ref=exists; //add file record to file reference table fileTable[ref].loaded=false; fileTable[ref].parsed=false; fileTable[ref].size=EndianU32_BtoN(header->entries[i].unPackedSize); ((tFileSystemLocator*)&(fileTable[ref].fsLoc))->vRefNum=vRefNum; ((tFileSystemLocator*)&(fileTable[ref].fsLoc))->dirID=dirID; BlockMove(name,((tFileSystemLocator*)&(fileTable[ref].fsLoc))->pName,name[0]+1); ((tFileSystemLocator*)&(fileTable[ref].fsLoc))->packageOffset=EndianU32_BtoN(header->entries[i].offset); ((tFileSystemLocator*)&(fileTable[ref].fsLoc))->packageSize=EndianU32_BtoN(header->entries[i].packedSize); strcpy(fileTable[ref].name,header->entries[i].name); } } else { ShowAlert("Too many files in Plug-ins folder.","Please remove some files from your Plug-ins folder, and restart Redline."); ExitToShell(); } DisposePtr((Ptr)header); HandleError(FSClose(ref)); } void AddFile(SInt16 vRefNum,SInt32 dirID,const Str255 name,tFileTableEntry *fileTable,int *fileTableSize,int maxSize) { char cName[256]; CopyPascalStringToC(name,cName); if(*fileTableSizevRefNum=vRefNum; ((tFileSystemLocator*)&(fileTable[*fileTableSize].fsLoc))->dirID=dirID; BlockMove(name,((tFileSystemLocator*)&(fileTable[*fileTableSize].fsLoc))->pName,name[0]+1); ((tFileSystemLocator*)&(fileTable[*fileTableSize].fsLoc))->packageOffset=kFileNotPackaged; strcpy(fileTable[*fileTableSize].name,cName); (*fileTableSize)++; } else { // if(_stricmp(cName,".DS_Store")) // PrintConsoleString("File duplicate!: %s\n",cName); } else { ShowAlert("Too many files in Plug-ins folder.","Please remove some files from your Plug-ins folder, and restart Redline."); ExitToShell(); } } #define IsPackage(i) (_stricmp(cName+strlen(cName)-strlen(kFileTypePackageFile),kFileTypePackageFile)==0) //recursivly add all files in a directory and subdirectories //to the file reference table void IterateDirectoryLevel(SInt16 vRefNum,SInt32 dirID,tFileTableEntry *fileTable,int *fileTableSize,int maxSize) { CInfoPBRec cinfo; Str255 name; for(int i=1; ;i++) { //Get info about the next file in the folder cinfo.hFileInfo.ioVRefNum = vRefNum; cinfo.hFileInfo.ioDirID = dirID; cinfo.hFileInfo.ioNamePtr = name; cinfo.hFileInfo.ioFDirIndex = i; OSErr error=PBGetCatInfoSync(&cinfo); char cName[256]; CopyPascalStringToC(name,cName); //no more files? if(error==fnfErr)break; HandleError(error); //is this a directory? if(cinfo.hFileInfo.ioFlAttrib&kioFlAttribDirMask) //recursively process subdirectory IterateDirectoryLevel(vRefNum,cinfo.dirInfo.ioDrDirID,fileTable,fileTableSize,maxSize); #ifndef __PACKER else if(IsPackage(cName)) IteratePackage(vRefNum,dirID,name,fileTable,fileTableSize,maxSize); #endif else AddFile(vRefNum,dirID,name,fileTable,fileTableSize,maxSize); } } //declared in fileio.cpp int FileTableCompare(const void *a,const void *b); SInt32 GetDirID(FSSpec *spec) { CInfoPBRec cinfo; cinfo.hFileInfo.ioVRefNum = spec->vRefNum; cinfo.hFileInfo.ioDirID = spec->parID; cinfo.hFileInfo.ioNamePtr = spec->name; cinfo.hFileInfo.ioFDirIndex = 0; OSErr error=PBGetCatInfoSync(&cinfo); return cinfo.dirInfo.ioDrDirID; } #define kPlugInDirName "Plug-Ins" #define kPlugInDirPName "\pPlug-Ins" //Initialize file reference table void FileInitFileTable(tFileTableEntry *fileTable,int maxSize,int *fileTableSize,int reInit) { FSSpec spec; OSErr err; SInt16 vRefNum; //application's vRefNum SInt32 dirID; //application's directory ID if(!reInit) *fileTableSize=0; #ifdef __TARGET_PACKER spec=packFolderFSS; #else #ifdef __TARGET_TOOLAPP err=FSMakeFSSpec(0,0,"\p::::Redline.app",&spec); if(err==fnfErr) { err=FSMakeFSSpec(0,0,"\p:::::Redline.app",&spec); if(err==fnfErr) { ShowAlert("Can't find Redline","Please run the Tool Chest apps from the same folder Redline is in, or from the Tool Chest folder inside the Redline folder."); ExitToShell(); } } #else //get FSSpec for application's Bundle GetApplicationBundleFSSpec(&spec); #endif #endif //process file's in application bundle //and subdirectories into file reference table IterateDirectoryLevel(spec.vRefNum,GetDirID(&spec),fileTable,fileTableSize,maxSize); #ifndef __TARGET_PACKER //process Plug-In folder if it exists err=FSMakeFSSpec(spec.vRefNum,spec.parID,kPlugInDirPName,&spec); if(err!=fnfErr) IterateDirectoryLevel(spec.vRefNum,GetDirID(&spec),fileTable,fileTableSize,maxSize); //get reference to Preferences folder SInt16 prefVRefNum; SInt32 prefDirID; HandleError(FindFolder(kOnAppropriateDisk,kPreferencesFolderType,kCreateFolder,&prefVRefNum,&prefDirID)); //see if Redline folder exists /* FSSpec configFolderSpec; err=FSMakeFSSpec(prefVRefNum,prefDirID,kConfigDirPName,&configFolderSpec); SInt32 configFolderDirID; //if not create it if(err==fnfErr) HandleError(FSpDirCreate(&configFolderSpec,smSystemScript,&configFolderDirID)); //otherwise get the dirID else configFolderDirID=GetDirID(&configFolderSpec); */ //see if config file exists FSSpec configSpec; err=FSMakeFSSpec(prefVRefNum,prefDirID,kConfigFilePName,&configSpec); //if not create it if(err==fnfErr) FSpCreate(&configSpec,'????','????',smSystemScript); //Add Config folder to file table AddFile(prefVRefNum,prefDirID,kConfigFilePName,fileTable,fileTableSize,maxSize); #endif //and sort the filetable by file names if(!reInit) qsort(fileTable,*fileTableSize,sizeof(tFileTableEntry),&FileTableCompare); printf("%d files.\n",*fileTableSize); #ifndef __TARGET_PACKER if(!FileGetSize(FileGetReference(kConfigFileName))) { tFileRef defaults=FileGetReference(kConfigDefault16Name); int vram=GetVRAMSize(); if(vram>16*1024*1024) defaults=FileGetReference(kConfigDefault32Name); if(vram>32*1024*1024) defaults=FileGetReference(kConfigDefault64Name); FileSetData(FileGetReference(kConfigFileName),FileGetDataPtr(defaults)); } #endif } //load a file's data int FileLoadData(tFileRef fileRef) { short ref; HandleError(HOpenDF(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->vRefNum ,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->dirID ,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->pName,fsCurPerm,&ref)); long eof; HandleError(GetEOF(ref,&eof)); if(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset==kFileNotPackaged) { gFileTable[fileRef].data=NewPtr(eof); gFileTable[fileRef].size=eof; HandleError(FSRead(ref,&eof,gFileTable[fileRef].data)); } else { long packedSize=((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageSize; Ptr packedData=NewPtr(packedSize); gFileTable[fileRef].data=NewPtr(gFileTable[fileRef].size); unsigned long offset=((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset; HandleError(SetFPos(ref,fsFromStart,offset)); HandleError(FSRead(ref,&packedSize,packedData)); compress_identity *iden; xcompress(COMPRESS_ACTION_IDENTITY,0,0,0,0,0,(ULONG*)&iden); Ptr workBuffer=NewPtr(iden->memory); UInt32 ignore; xcompress(COMPRESS_ACTION_DECOMPRESS,(UBYTE*)workBuffer,(UBYTE*)packedData,packedSize,gFileTable[fileRef].size,(UBYTE*)gFileTable[fileRef].data,(ULONG*)&ignore); DisposePtr(workBuffer); DisposePtr(packedData); } HandleError(FSClose(ref)); return true; } void *FileGetPartialDataPtr(tFileRef fileRef,int offset,int size) { if(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset==kFileNotPackaged) { short ref; HandleError(HOpenDF(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->vRefNum ,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->dirID ,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->pName,fsCurPerm,&ref)); void *data=NewPtr(size); HandleError(SetFPos(ref,fsFromStart,offset)); long readSize=size; HandleError(FSRead(ref,&readSize,data)); HandleError(FSClose(ref)); return data; } else FailWithErrorString("Cannot get partial data from packaged file."); } //write a file's data void FileStoreData(tFileRef fileRef) { if(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset==kFileNotPackaged) { short ref; HandleError(HOpenDF(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->vRefNum ,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->dirID ,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->pName,fsCurPerm,&ref)); long eof=gFileTable[fileRef].size; HandleError(SetEOF(ref,eof)); HandleError(FSWrite(ref,&eof,gFileTable[fileRef].data)); HandleError(FSClose(ref)); } else FailWithErrorString("Cannot write to package file!"); } void FileAppendData(tFileRef fileRef,void *data,int size) { if(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset==kFileNotPackaged) { short ref; HandleError(HOpenDF(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->vRefNum ,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->dirID ,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->pName,fsCurPerm,&ref)); long writeSize=size; HandleError(SetFPos(ref,fsFromLEOF,0)); HandleError(FSWrite(ref,&writeSize,data)); HandleError(FSClose(ref)); } else FailWithErrorString("Cannot write to package file!"); }