/* * Copyright (c) 2013, Kelvin W Sherlock * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include "rm.h" #include "toolbox.h" #include "mm.h" #include "os_internal.h" #include #include #include #include #include #include #include "stackframe.h" #include "fs_spec.h" using ToolBox::Log; using namespace OS::Internal; using namespace ToolBox; using MacOS::tool_return; using MacOS::macos_error_from_errno; using MacOS::macos_error; namespace { bool ResLoad = true; // https://developer.apple.com/library/mac/documentation/Carbon/Reference/CoreEndianReference/ OSStatus FlipperNoFlipping(OSType dataDomain, OSType dataType, SInt16 id, void *dataPtr, ByteCount dataSize, Boolean currentlyNative, void *refCon) { return 0; } void BypassResourceFlipper(OSType dataType) { static std::unordered_set Types; if (Types.find(dataType) != Types.end()) return; CoreEndianFlipProc proc; void *refCon; if (::CoreEndianGetFlipper(kCoreEndianResourceManagerDomain, dataType, &proc, &refCon) == 0) { ::CoreEndianInstallFlipper(kCoreEndianResourceManagerDomain, dataType, FlipperNoFlipping, nullptr); //fprintf(stderr, "Endian Flipper was installed for resource '%s'\n", TypeToString(dataType).c_str()); } Types.insert(dataType); } #if 0 struct ResEntry { ResEntry(uint32_t type = 0, uint32_t id = 0) : resType(type), resID(id) {} uint32_t resType; uint32_t resID; uint32_t handle; }; std::list ResourceMapList; #endif // sigh... really need to create a resmap for every open // resource file and update that with the pointer. std::map rhandle_map; inline uint16_t SetResError(uint16_t error) { memoryWriteWord(error, MacOS::ResErr); return error; } bool LoadResType(uint32_t type) { // this filtering was originally to // block cursors ('acur'). Can probably // change it to a blacklist rather than // a whitelist at some point. return true; switch (type) { case 0x76657273: // 'vers'; case 0x48455841: // 'HEXA' case 0x53545220: // 'STR ' case 0x53545223: // 'STR#' (reziigs) case 0x59414343: // 'YACC' (pascaliigs) case 0x72547970: // 'rTyp' (rezIIgs) case 0x756e6974: // 'unit' (Pascal) case 0x434f4445: // 'CODE' (Link) case 0x5041434b: // 'PACK' (PascalIIgs) case 0x4b4f4445: // 'KODE' (Link 32-bit Startup) case 0x45525253: // 'ERRS' (PPCLink) case 0x63667267: // 'cfrg' (PPCLink) case 0x44415441: // 'DATA' (MetroWerks tools) case 0x54455854: // 'TEXT' (MetroWerks tools) case 0x6f626a64: // 'objd' (MetroWerks tools) return true; default: return false; } } } namespace RM { namespace Native { // not to be confused with MacOS LoadResource(theHandle) template uint16_t LoadResource(uint32_t type, uint32_t &theHandle, FX fx) { uint32_t ptr; uint16_t error; Handle nativeHandle; uint32_t size; theHandle = 0; if (!LoadResType(type)) return SetResError(resNotFound); BypassResourceFlipper(type); nativeHandle = fx(); if (!nativeHandle) return SetResError(resNotFound); // in OS X 10.8, ::SetResLoad(false) seems to be permanent. // therefore, explicitly load it if needed. (PascalIIgs) if (ResLoad) ::LoadResource(nativeHandle); size = ::GetHandleSize(nativeHandle); error = MM::Native::NewHandle(size, false, theHandle, ptr); // TODO -- need to lock if native handle locked. if (!theHandle) { ::ReleaseResource(nativeHandle); return SetResError(error); } MM::Native::HSetRBit(theHandle); if (size) std::memcpy(memoryPointer(ptr), *(void **)nativeHandle, size); //::ReleaseResource(nativeHandle); rhandle_map.insert({theHandle, nativeHandle}); return SetResError(0); } // used by GetString (utility.h) // used by Loader. uint16_t GetResource(uint32_t type, uint16_t id, uint32_t &theHandle) { return LoadResource(type, theHandle, [type, id](){ return ::GetResource(type, id); }); } uint16_t SetResLoad(bool load) { ResLoad = load; ::SetResLoad(load); memoryWriteByte(load ? 0xff : 0x00, MacOS::ResLoad); // word or byte? return SetResError(0); } } uint16_t CloseResFile(uint16_t trap) { // PROCEDURE CloseResFile (refNum: Integer); uint16_t refNum; StackFrame<2>(refNum); Log("%04x CloseResFile(%04x)\n", trap, refNum); // If the value of the refNum parameter is 0, it represents the System file and is ignored. if (refNum != 0) { ::CloseResFile(refNum); return SetResError(::ResError()); } return SetResError(0); //return SetResError(resFNotFound); } uint16_t Get1NamedResource(uint16_t trap) { // Get1NamedResource (theType: ResType; name: Str255) : Handle; /* * ----------- * +8 outHandle * ------------ * +4 theType * ------------ * +0 name * ------------ * */ // nb - return address is not on the stack. uint32_t sp; uint32_t theType; uint32_t name; sp = StackFrame<8>(theType, name); std::string sname = ToolBox::ReadPString(name); Log("%04x Get1NamedResource(%08x ('%s'), %s)\n", trap, theType, TypeToString(theType).c_str(), sname.c_str()); uint32_t resourceHandle; uint32_t d0; d0 = Native::LoadResource(theType, resourceHandle, [theType, name](){ return ::Get1NamedResource(theType, memoryPointer(name)); } ); ToolReturn<4>(sp, resourceHandle); return SetResError(d0); } uint16_t GetNamedResource(uint16_t trap) { // FUNCTION GetNamedResource (theType: ResType; name: Str255): Handle; uint32_t sp; uint32_t theType; uint32_t name; sp = StackFrame<8>(theType, name); std::string sname = ToolBox::ReadPString(name); Log("%04x GetNamedResource(%08x ('%s'), %s)\n", trap, theType, TypeToString(theType).c_str(), sname.c_str()); uint32_t resourceHandle; uint32_t d0; d0 = Native::LoadResource(theType, resourceHandle, [theType, name](){ return ::GetNamedResource(theType, memoryPointer(name)); } ); ToolReturn<4>(sp, resourceHandle); return SetResError(d0); } uint16_t GetResource(uint16_t trap) { // GetResource (theType: ResType; theID: Integer): Handle; /* * ----------- * +6 outHandle * ------------ * +2 theType * ------------ * +0 theID * ------------ * */ // nb - return address is not on the stack. uint32_t sp; uint32_t theType; uint16_t theID; sp = StackFrame<6>(theType, theID); Log("%04x GetResource(%08x ('%s'), %04x)\n", trap, theType, TypeToString(theType).c_str(), theID); uint32_t resourceHandle; uint32_t d0; d0 = Native::LoadResource(theType, resourceHandle, [theType, theID](){ return ::GetResource(theType, theID); } ); ToolReturn<4>(sp, resourceHandle); return d0; } uint16_t Get1Resource(uint16_t trap) { // Get1Resource (theType: ResType; theID: Integer): Handle; /* * ----------- * +6 outHandle * ------------ * +2 theType * ------------ * +0 theID * ------------ * */ // nb - return address is not on the stack. uint32_t sp; uint32_t theType; uint16_t theID; sp = StackFrame<6>(theType, theID); Log("%04x Get1Resource(%08x ('%s'), %04x)\n", trap, theType, TypeToString(theType).c_str(), theID); uint32_t resourceHandle; uint32_t d0; d0 = Native::LoadResource(theType, resourceHandle, [theType, theID](){ return ::Get1Resource(theType, theID); } ); ToolReturn<4>(sp, resourceHandle); return d0; } uint16_t ReleaseResource(uint16_t trap) { // ReleaseResource (theResource: Handle); /* * ------------ * +0 theResource * ------------ * */ uint32_t sp; uint32_t theResource; sp = StackFrame<4>(theResource); Log("%04x ReleaseResource(%08x)\n", trap, theResource); return SetResError(0); } uint16_t ResError(uint16_t trap) { uint32_t sp; Log("%04x ResError()\n", trap); sp = cpuGetAReg(7); ToolReturn<2>(sp, memoryReadWord(MacOS::ResErr)); return 0; } // SetResLoad (load: BOOLEAN); uint16_t SetResLoad(uint16_t trap) { uint16_t load; StackFrame<2>(load); Log("%04x SetResLoad(%04x)\n", trap, load); ResLoad = load; ::SetResLoad(load); memoryWriteByte(load ? 0xff : 0x00, MacOS::ResLoad); // word or byte? return SetResError(0); } uint16_t CurResFile(uint16_t trap) { Log("%04x CurResFile()\n", trap); ResFileRefNum refNum = ::CurResFile(); ToolReturn<2>(-1, refNum); return SetResError(::ResError()); } uint16_t UseResFile(uint16_t trap) { uint16_t resFile; StackFrame<2>(resFile); Log("%04x UseResFile(%04x)\n", trap, resFile); ::UseResFile(resFile); return SetResError(::ResError()); } tool_return CreateResFile(const std::string &path, uint32_t creator = 0, uint32_t fileType = 0) { if (path.empty()) return MacOS::paramErr; FSRef ref; OSErr error; int fd; // FSPathMakeRef only works with existing files. // FSCreateResourceFork only works with existing files. fd = ::open(path.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666); if (fd < 0) { if (errno != EEXIST) return macos_error_from_errno(); } else { if (creator || fileType) OS::Internal::SetFinderInfo(path, fileType, creator); close(fd); } error = ::FSPathMakeRef((const UInt8 *)path.c_str(), &ref, NULL); if (error != noErr) return macos_error(error); HFSUniStr255 fork = {0,{0}}; ::FSGetResourceForkName(&fork); error = ::FSCreateResourceFork(&ref, fork.length, fork.unicode, 0); // CreateResFile returns an error if the fork exists, HCreateResFile // and FSpCreateResFile do not. if (error == errFSForkExists) error = MacOS::dupFNErr; return macos_error(error); } uint16_t CreateResFile(uint16_t trap) { // PROCEDURE CreateResFile (fileName: Str255); /* * CreateResFile creates a resource file containing no resource * data. If there's no file at all with the given name, it also * creates an empty data fork for the file. If there's already a * resource file with the given name (that is, a resource fork * that isn't empty), CreateResFile will do nothing and the * ResError function will return an appropriate Operating System * result code. */ uint32_t fileName; StackFrame<4>(fileName); std::string sname = ToolBox::ReadPString(fileName, true); Log("%04x CreateResFile(%s)\n", trap, sname.c_str()); if (!sname.length()) return SetResError(MacOS::paramErr); auto rv = CreateResFile(sname); return SetResError(rv.error()); } uint16_t HCreateResFile(uint16_t trap) { // PROCEDURE HCreateResFile (vRefNum: Integer; dirID: LongInt; // fileName: Str255); uint16_t vRefNum; uint32_t dirID; uint32_t fileName; StackFrame<10>(vRefNum, dirID, fileName); std::string sname = ToolBox::ReadPString(fileName, true); Log("%04x HCreateResFile(%04x, %08x, %s)\n", trap, vRefNum, dirID, sname.c_str()); sname = OS::FSSpecManager::ExpandPath(sname, dirID); if (sname.empty()) { return SetResError(MacOS::dirNFErr); } auto rv = CreateResFile(sname); return SetResError(rv.error() == MacOS::dupFNErr ? 0 : rv.error()); } uint16_t FSpCreateResFile(void) { // PROCEDURE FSpCreateResFile (spec: FSSpec; creator, fileType: OSType; scriptTag: ScriptCode); // creates the file, if necessary. uint32_t sp; uint32_t spec; uint32_t creator; uint32_t fileType; uint16_t scriptTag; sp = StackFrame<14>(spec, creator, fileType, scriptTag); int parentID = memoryReadLong(spec + 2); std::string sname = ToolBox::ReadPString(spec + 6, false); Log(" FSpCreateResFile(%s, %08x ('%s'), %08x ('%s'), %02x)\n", sname.c_str(), creator, ToolBox::TypeToString(creator).c_str(), fileType, ToolBox::TypeToString(fileType).c_str(), scriptTag); sname = OS::FSSpecManager::ExpandPath(sname, parentID); if (sname.empty()) { return SetResError(MacOS::dirNFErr); } auto rv = CreateResFile(sname, creator, fileType); return SetResError(rv.error() == MacOS::dupFNErr ? 0 : rv.error()); } tool_return OpenResCommon(const std::string &path, uint16_t permission = 0) { OSErr error; FSRef ref; ResFileRefNum refNum; error = ::FSPathMakeRef( (const UInt8 *)path.c_str(), &ref, NULL); if (error != noErr) return (MacOS::macos_error)error; HFSUniStr255 fork = {0,{0}}; ::FSGetResourceForkName(&fork); refNum = -1; error = ::FSOpenResourceFile(&ref, fork.length, fork.unicode, permission, &refNum); if (error != noErr) return (MacOS::macos_error)error; return refNum; } uint16_t OpenResFile(uint16_t trap) { // OpenResFile (fileName: Str255) : INTEGER; uint32_t sp; uint32_t fileName; sp = StackFrame<4>(fileName); std::string sname = ToolBox::ReadPString(fileName, true); Log("%04x OpenResFile(%s)\n", trap, sname.c_str()); auto rv = OpenResCommon(sname); ToolReturn<2>(sp, rv.value_or(-1)); return SetResError(rv.error()); } uint16_t HOpenResFile(uint16_t trap) { // FUNCTION HOpenResFile (vRefNum: Integer; dirID: LongInt; // fileName: Str255; permission: SignedByte): Integer; uint32_t sp; uint16_t vRefNum; uint32_t dirID; uint32_t fileName; uint8_t permission; sp = StackFrame<12>(vRefNum, dirID, fileName, permission); std::string sname = ToolBox::ReadPString(fileName, true); Log("%04x HOpenResFile(%04x, %08x, %s, %04x)\n", trap, vRefNum, dirID, sname.c_str(), permission); if (vRefNum) { fprintf(stderr, "HOpenResFile: vRefNum not supported yet.\n"); exit(1); } sname = OS::FSSpecManager::ExpandPath(sname, dirID); if (sname.empty()) { ToolReturn<2>(sp, (uint16_t)-1); return SetResError(MacOS::dirNFErr); } auto rv = OpenResCommon(sname, permission); ToolReturn<2>(sp, rv.value_or(-1)); return SetResError(rv.error()); } uint16_t FSpOpenResFile(void) { // FUNCTION FSpOpenResFile (spec: FSSpec; permission: SignedByte): Integer; uint32_t sp; uint32_t spec; uint8_t permission; sp = StackFrame<6>(spec, permission); int parentID = memoryReadLong(spec + 2); std::string sname = ToolBox::ReadPString(spec + 6, false); Log(" FSpOpenResFile(%s, %04x)\n", sname.c_str(), permission); sname = OS::FSSpecManager::ExpandPath(sname, parentID); if (sname.empty()) { ToolReturn<2>(sp, (uint16_t)-1); return SetResError(MacOS::dirNFErr); } auto rv = OpenResCommon(sname, permission); ToolReturn<2>(sp, rv.value_or(-1)); return SetResError(rv.error()); } uint16_t OpenRFPerm(uint16_t trap) { // FUNCTION OpenRFPerm (fileName: Str255; vRefNum: Integer; // permission: SignedByte): Integer; ResFileRefNum refNum; FSRef ref; uint32_t sp; uint32_t fileName; uint16_t vRefNum; uint16_t permission; OSErr error; sp = StackFrame<8>(fileName, vRefNum, permission); std::string sname = ToolBox::ReadPString(fileName, true); Log("%04x OpenRFPerm(%s, %04x, %04x)\n", trap, sname.c_str(), vRefNum, permission); error = ::FSPathMakeRef( (const UInt8 *)sname.c_str(), &ref, NULL); if (error != noErr) { ToolReturn<2>(sp, (uint16_t)-1); return SetResError(error); } HFSUniStr255 fork = {0,{0}}; ::FSGetResourceForkName(&fork); refNum = -1; error = ::FSOpenResourceFile(&ref, fork.length, fork.unicode, permission, &refNum); ToolReturn<2>(sp, (uint16_t)refNum); return SetResError(error); } uint16_t Count1Resources(uint16_t trap) { // FUNCTION Count1Resources (theType: ResType): Integer; uint32_t sp; uint32_t theType; uint16_t count; sp = StackFrame<4>(theType); Log("%04x Count1Resources(%08x ('%s'))\n", trap, theType, TypeToString(theType).c_str()); count = ::Count1Resources(theType); ToolReturn<2>(sp, count); return SetResError(0); } uint16_t UpdateResFile(uint16_t trap) { // PROCEDURE UpdateResFile (refNum: Integer); uint16_t refNum; StackFrame<2>(refNum); Log("%04x UpdateResFile(%04x)\n", trap, refNum); ::UpdateResFile(refNum); return SetResError(::ResError()); } uint16_t ChangedResource(uint16_t trap) { // PROCEDURE ChangedResource (theResource: Handle); uint32_t theResource; StackFrame<4>(theResource); Log("%04x ChangedResource(%08x)\n", trap, theResource); // set the resChanged attribute so when UpdateResFile() is called // (or the app exits) // also needs to update the carbon handle/data with the mpw handle // since the data has changed.... auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) { return SetResError(MacOS::resNotFound); } Handle nativeHandle = iter->second; // check if handle size changed, resync data auto info = MM::GetHandleInfo(theResource); if (!info.error()) return SetResError(info.error()); uint32_t nativeSize = ::GetHandleSize(nativeHandle); if (nativeSize != info->size) { // resize... // chould get state / unlock / set state ... but that does nothing in OS X. ::SetHandleSize(nativeHandle, info->size); OSErr err = MemError(); if (err) return SetResError(err); } std::memcpy(*nativeHandle, memoryPointer(info->address), info->size); ::ChangedResource(nativeHandle); return SetResError(::ResError()); } uint16_t GetResFileAttrs(uint16_t trap) { // FUNCTION GetResFileAttrs (refNum: Integer): Integer; uint32_t sp; uint16_t attrs; uint16_t refNum; sp = StackFrame<2>(refNum); Log("%04x GetResFileAttrs(%04x)\n", trap, refNum); attrs = ::GetResFileAttrs(refNum); ToolReturn<2>(sp, attrs); return SetResError(::ResError()); } uint16_t SetResFileAttrs(uint16_t trap) { // PROCEDURE SetResFileAttrs (refNum: Integer; attrs: Integer); uint32_t sp; uint16_t attrs; uint16_t refNum; sp = StackFrame<4>(refNum, attrs); Log("%04x GetResFileAttrs(%04x, %04x)\n", trap, refNum, attrs); ::SetResFileAttrs(refNum, attrs); return SetResError(::ResError()); } // TODO -- update rhandle_map when loading resources // TODO -- update rhandle_map when disposing resources. uint16_t AddResource(uint16_t trap) { // PROCEDURE AddResource (theData: Handle; theType: ResType; // theID: Integer; name: Str255); uint32_t theData; uint32_t theType; uint16_t theID; uint32_t namePtr; StackFrame<14>(theData, theType, theID, namePtr); std::string sname = ToolBox::ReadPString(namePtr, false); Log("%04x AddResource(%08x, %08x ('%s'), %04x, %s)\n", trap, theData, theType, TypeToString(theType).c_str(), theID, sname.c_str() ); BypassResourceFlipper(theType); Handle nativeHandle = NULL; auto info = MM::GetHandleInfo(theData); if (info.error()) return SetResError(MacOS::addResFailed); nativeHandle = ::NewHandle(info->size); if (!nativeHandle) return SetResError(MacOS::addResFailed); std::memcpy(*(uint8_t **)nativeHandle, memoryPointer(info->address), info->size); rhandle_map.insert({theData, nativeHandle}); // AddResource assumes ownership of the handle. ::AddResource(nativeHandle, theType, theID, memoryPointer(namePtr)); return SetResError(::ResError()); } uint16_t SetResAttrs(uint16_t trap) { // PROCEDURE SetResAttrs (theResource: Handle; attrs: Integer); uint32_t theResource; uint16_t attrs; StackFrame<6>(theResource, attrs); Log("%04x SetResAttrs(%08x, %04x)\n", trap, theResource, attrs); // find the native handle.. auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) return SetResError(MacOS::resNotFound); Handle nativeHandle = iter->second; ::SetResAttrs(nativeHandle, attrs); return SetResError(::ResError()); } uint16_t GetResAttrs(uint16_t trap) { // FUNCTION GetResAttrs (theResource: Handle): Integer; uint32_t sp; uint32_t theResource; uint16_t attrs; sp = StackFrame<4>(theResource); Log("%04x GetResAttrs(%08x)\n", trap, theResource); auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) { ToolReturn<2>(sp, 0); return SetResError(MacOS::resNotFound); } Handle nativeHandle = iter->second; attrs = ::GetResAttrs(nativeHandle); ToolReturn<2>(sp, attrs); return SetResError(::ResError()); } uint16_t WriteResource(uint16_t trap) { // PROCEDURE WriteResource (theResource: Handle); uint32_t theResource; StackFrame<4>(theResource); Log("%04x WriteResource(%08x)\n", trap, theResource); auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) return SetResError(MacOS::resNotFound); Handle nativeHandle = iter->second; // todo -- need to verify handle size, re-copy handle memory? ::WriteResource(nativeHandle); return SetResError(::ResError()); } uint16_t DetachResource(uint16_t trap) { // PROCEDURE DetachResource (theResource: Handle); uint32_t theResource; StackFrame<4>(theResource); Log("%04x DetachResource(%08x)\n", trap, theResource); auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) return SetResError(MacOS::resNotFound); Handle nativeHandle = iter->second; rhandle_map.erase(iter); ::ReleaseResource(nativeHandle); return SetResError(::ResError()); } uint16_t Get1IndResource(uint16_t trap) { // FUNCTION Get1IndResource (theType: ResType; index: Integer): Handle; uint32_t sp; uint32_t theType; uint16_t index; sp = StackFrame<6>(theType, index); Log("%04x Get1IndResource(%08x ('%s'), %04x)\n", trap, theType, TypeToString(theType).c_str(), index); uint32_t resourceHandle = 0; uint16_t d0; d0 = Native::LoadResource(theType, resourceHandle, [theType, index](){ return ::Get1IndResource(theType, index); } ); ToolReturn<4>(sp, resourceHandle); return SetResError(d0); } uint16_t RemoveResource(uint16_t trap) { // PROCEDURE RemoveResource (theResource: Handle); uint32_t theResource; StackFrame<4>(theResource); Log("%04x RemoveResource(%08x)\n", trap, theResource); auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) return SetResError(MacOS::resNotFound); Handle nativeHandle = iter->second; rhandle_map.erase(iter); ::RemoveResource(nativeHandle); ::DisposeHandle(nativeHandle); return SetResError(::ResError()); } uint16_t GetResourceSizeOnDisk(uint16_t trap) { // FUNCTION GetResourceSizeOnDisk (theResource: Handle): LongInt; uint32_t sp; uint32_t theResource; sp = StackFrame<4>(theResource); Log("%04x GetResourceSizeOnDisk(%08x)\n", trap, theResource); auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) { ToolReturn<4>(sp, (uint32_t)0); return SetResError(MacOS::resNotFound); } Handle nativeHandle = iter->second; uint32_t size = ::GetResourceSizeOnDisk(nativeHandle); ToolReturn<4>(sp, size); return SetResError(::ResError()); } uint16_t GetResInfo(uint16_t trap) { // PROCEDURE GetResInfo (theResource: Handle; // VAR theID: INTEGER; VAR theType: ResType; VAR name: Str255); uint32_t theResource; uint32_t theID; uint32_t theType; uint32_t name; StackFrame<16>(theResource, theID, theType, name); Log("%04x GetResInfo(%08x)\n", trap, theResource); auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) { return SetResError(MacOS::resNotFound); } Handle nativeHandle = iter->second; ResID nativeID = 0; ResType nativeType = 0; Str255 nativeName = {0}; ::GetResInfo(nativeHandle, &nativeID, &nativeType, nativeName); if (theID) memoryWriteWord(nativeID, theID); if (theType) memoryWriteLong(nativeType, theType); if (name) { std::string sname(nativeName + 1, nativeName + 1 + nativeName[0]); ToolBox::WritePString(name, sname); } return SetResError(::ResError()); } uint16_t LoadResource(uint16_t trap) { // PROCEDURE LoadResource (theResource: Handle); // this loads the resource from disk, if not already // loaded. (if purgeable or SetResLoad(false)) // this needs cooperation with MM to check if // handle was purged. OSErr err; uint32_t theResource; StackFrame<4>(theResource); Log("%04x LoadResource(%08x)\n", trap, theResource); auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) { return SetResError(MacOS::resNotFound); } // if it has a size, it's loaded... auto info = MM::GetHandleInfo(theResource); if (info.error()) return SetResError(resNotFound); if (info->size) return SetResError(0); // otherwise, load it Handle nativeHandle; uint32_t size; nativeHandle = iter->second; ::LoadResource(nativeHandle); err = ::ResError(); if (err) return SetResError(err); size = ::GetHandleSize(nativeHandle); err = MM::Native::ReallocHandle(theResource, size); if (err) return SetResError(err); // todo -- need to lock if resource locked. if (size) { info = MM::GetHandleInfo(theResource); std::memcpy(memoryPointer(info->address), *(void **)nativeHandle, size); } return SetResError(0); } uint16_t HomeResFile(uint16_t trap) { // PPCAsm // FUNCTION HomeResFile (theResource: Handle): Integer; uint32_t sp; uint32_t theResource; uint16_t resFile; sp = StackFrame<4>(theResource); Log("%04x HomeResFile(%08x)\n", trap, theResource); auto iter = rhandle_map.find(theResource); if (iter == rhandle_map.end()) { ToolReturn<2>(sp, -1); return SetResError(MacOS::resNotFound); } resFile = ::HomeResFile(iter->second); ToolReturn<2>(sp, resFile); return SetResError(::ResError()); } uint16_t Count1Types(uint16_t trap) { // FUNCTION Count1Types: Integer; uint16_t count; Log("%04x Count1Types\n", trap); count = ::Count1Types(); ToolReturn<2>(-1, count); return SetResError(::ResError()); } uint16_t Get1IndType(uint16_t trap) { // PROCEDURE Get1IndType (VAR theType: ResType; index: Integer); uint32_t theType; uint16_t index; StackFrame<6>(theType, index); Log("%04x Get1IndType(%08x, %04x)\n", trap, theType, index); ResType nativeType = 0; ::Get1IndType(&nativeType, index); memoryWriteLong(nativeType, theType); return SetResError(::ResError()); } }