📄 macclassic.c
字号:
/* * MacOS Classic support routines for PhysicsFS. * * Please see the file LICENSE in the source's root directory. * * This file written by Ryan C. Gordon. */#if HAVE_CONFIG_H# include <config.h>#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <alloca.h>/* * Most of the API calls in here are, according to ADC, available since * MacOS 8.1. I don't think I used any MacOS 9 or CarbonLib-specific * functions. There might be one or two 8.5 calls, and perhaps when the * ADC docs say "Available in MacOS 8.1" they really mean "this works * with System 6, but we don't want to hear about it at this point." * * IsAliasFile() showed up in MacOS 8.5. You can duplicate this code with * PBGetCatInfoSync(), which is an older API, if you hope the bits in the * catalog info never change (which they won't for, say, MacOS 8.1). * See Apple Technote FL-30: * http://developer.apple.com/technotes/fl/fl_30.html * * If you want to use weak pointers and Gestalt, and choose the correct * code to use during __PHYSFS_platformInit(), I'll accept a patch, but * chances are, it wasn't worth the time it took to write this, let alone * implement that. *//* * Please note that I haven't tried this code with CarbonLib or under * MacOS X at all. The code in unix.c is known to work with Darwin, * and you may or may not be better off using that, especially since * mutexes are no-ops in this file. Patches welcome. */#ifdef __PHYSFS_CARBONIZED__ /* this is currently not defined anywhere. */#include <Carbon.h>#else#include <OSUtils.h>#include <Processes.h>#include <Files.h>#include <TextUtils.h>#include <Resources.h>#include <MacMemory.h>#include <Events.h>#include <DriverGestalt.h>#include <Aliases.h>#endif#define __PHYSICSFS_INTERNAL__#include "physfs_internal.h"const char *__PHYSFS_platformDirSeparator = ":";static const char *get_macos_error_string(OSErr err){ if (err == noErr) return(NULL); switch (err) { case fnfErr: return(ERR_NO_SUCH_FILE); case notOpenErr: return(ERR_NO_SUCH_VOLUME); case dirFulErr: return(ERR_DIRECTORY_FULL); case dskFulErr: return(ERR_DISK_FULL); case nsvErr: return(ERR_NO_SUCH_VOLUME); case ioErr: return(ERR_IO_ERROR); case bdNamErr: return(ERR_BAD_FILENAME); case fnOpnErr: return(ERR_NOT_A_HANDLE); case eofErr: return(ERR_PAST_EOF); case posErr: return(ERR_SEEK_OUT_OF_RANGE); case tmfoErr: return(ERR_TOO_MANY_HANDLES); case wPrErr: return(ERR_VOL_LOCKED_HW); case fLckdErr: return(ERR_FILE_LOCKED); case vLckdErr: return(ERR_VOL_LOCKED_SW); case fBsyErr: return(ERR_FILE_OR_DIR_BUSY); case dupFNErr: return(ERR_FILE_EXISTS); case opWrErr: return(ERR_FILE_ALREADY_OPEN_W); case rfNumErr: return(ERR_INVALID_REFNUM); case gfpErr: return(ERR_GETTING_FILE_POS); case volOffLinErr: return(ERR_VOLUME_OFFLINE); case permErr: return(ERR_PERMISSION_DENIED); case volOnLinErr: return(ERR_VOL_ALREADY_ONLINE); case nsDrvErr: return(ERR_NO_SUCH_DRIVE); case noMacDskErr: return(ERR_NOT_MAC_DISK); case extFSErr: return(ERR_VOL_EXTERNAL_FS); case fsRnErr: return(ERR_PROBLEM_RENAME); case badMDBErr: return(ERR_BAD_MASTER_BLOCK); case wrPermErr: return(ERR_PERMISSION_DENIED); case memFullErr: return(ERR_OUT_OF_MEMORY); case dirNFErr: return(ERR_NO_SUCH_PATH); case tmwdoErr: return(ERR_TOO_MANY_HANDLES); case badMovErr: return(ERR_CANT_MOVE_FORBIDDEN); case wrgVolTypErr: return(ERR_WRONG_VOL_TYPE); case volGoneErr: return(ERR_SERVER_VOL_LOST); case errFSNameTooLong: return(ERR_BAD_FILENAME); case errFSNotAFolder: return(ERR_NOT_A_DIR); /*case errFSNotAFile: return(ERR_NOT_A_FILE);*/ case fidNotFound: return(ERR_FILE_ID_NOT_FOUND); case fidExists: return(ERR_FILE_ID_EXISTS); case afpAccessDenied: return(ERR_ACCESS_DENIED); case afpNoServer: return(ERR_SERVER_NO_RESPOND); case afpUserNotAuth: return(ERR_USER_AUTH_FAILED); case afpPwdExpiredErr: return(ERR_PWORD_EXPIRED); case paramErr: case errFSBadFSRef: case errFSBadBuffer: case errFSMissingName: case errFSBadPosMode: case errFSBadAllocFlags: case errFSBadItemCount: case errFSBadSearchParams: case afpDenyConflict: return(ERR_PHYSFS_BAD_OS_CALL); default: return(ERR_MACOS_GENERIC); } /* switch */ return(NULL);} /* get_macos_error_string */static OSErr oserr(OSErr retval){ char buf[sizeof (ERR_MACOS_GENERIC) + 32]; const char *errstr = get_macos_error_string(retval); if (strcmp(errstr, ERR_MACOS_GENERIC) == 0) { snprintf(buf, sizeof (buf), ERR_MACOS_GENERIC, (int) retval); errstr = buf; } /* if */ if (errstr != NULL) __PHYSFS_setError(errstr); return(retval);} /* oserr */static struct ProcessInfoRec procInfo;static FSSpec procfsspec;int __PHYSFS_platformInit(void){ OSErr err; ProcessSerialNumber psn; BAIL_IF_MACRO(oserr(GetCurrentProcess(&psn)) != noErr, NULL, 0); memset(&procInfo, '\0', sizeof (ProcessInfoRec)); memset(&procfsspec, '\0', sizeof (FSSpec)); procInfo.processInfoLength = sizeof (ProcessInfoRec); procInfo.processAppSpec = &procfsspec; err = GetProcessInformation(&psn, &procInfo); BAIL_IF_MACRO(oserr(err) != noErr, NULL, 0); return(1); /* we're golden. */} /* __PHYSFS_platformInit */int __PHYSFS_platformDeinit(void){ return(1); /* always succeed. */} /* __PHYSFS_platformDeinit *//* * CD detection code is borrowed from Apple Technical Q&A DV18. * http://developer.apple.com/qa/dv/dv18.html */char **__PHYSFS_platformDetectAvailableCDs(void){ DriverGestaltParam pb; DrvQEl *dqp; OSErr status; char **retval = (char **) malloc(sizeof (char *)); int cd_count = 1; BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL); *retval = NULL; pb.csCode = kDriverGestaltCode; pb.driverGestaltSelector = kdgDeviceType; dqp = (DrvQEl *) GetDrvQHdr()->qHead; while (dqp != NULL) { pb.ioCRefNum = dqp->dQRefNum; pb.ioVRefNum = dqp->dQDrive; status = PBStatusSync((ParmBlkPtr) &pb); if ((status == noErr) && (pb.driverGestaltResponse == kdgCDType)) { Str63 volName; HParamBlockRec hpbr; memset(&hpbr, '\0', sizeof (HParamBlockRec)); hpbr.volumeParam.ioNamePtr = volName; hpbr.volumeParam.ioVRefNum = dqp->dQDrive; hpbr.volumeParam.ioVolIndex = 0; if (PBHGetVInfoSync(&hpbr) == noErr) { char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1)); if (tmp) { char *str = (char *) malloc(volName[0] + 1); retval = tmp; if (str != NULL) { memcpy(str, &volName[1], volName[0]); str[volName[0]] = '\0'; retval[cd_count-1] = str; cd_count++; } /* if */ } /* if */ } /* if */ } /* if */ dqp = (DrvQEl *) dqp->qLink; } /* while */ retval[cd_count - 1] = NULL; return(retval);} /* __PHYSFS_platformDetectAvailableCDs */static char *convFSSpecToPath(FSSpec *spec, int includeFile){ char *ptr; char *retval = NULL; UInt32 retLength = 0; CInfoPBRec infoPB; Str255 str255; str255[0] = spec->name[0]; memcpy(&str255[1], &spec->name[1], str255[0]); memset(&infoPB, '\0', sizeof (CInfoPBRec)); infoPB.dirInfo.ioNamePtr = str255; /* put name in here. */ infoPB.dirInfo.ioVRefNum = spec->vRefNum; /* ID of bin's volume. */ infoPB.dirInfo.ioDrParID = spec->parID; /* ID of bin's dir. */ infoPB.dirInfo.ioFDirIndex = (includeFile) ? 0 : -1; /* walk the tree back to the root dir (volume), building path string... */ do { /* check parent dir of what we last looked at... */ infoPB.dirInfo.ioDrDirID = infoPB.dirInfo.ioDrParID; if (oserr(PBGetCatInfoSync(&infoPB)) != noErr) { if (retval != NULL) free(retval); return(NULL); } /* if */ infoPB.dirInfo.ioFDirIndex = -1; /* look at parent dir next time. */ /* allocate more space for the retval... */ retLength += str255[0] + 1; /* + 1 for a ':' or null char... */ ptr = (char *) malloc(retLength); if (ptr == NULL) { if (retval != NULL) free(retval); BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL); } /* if */ /* prepend new dir to retval and cleanup... */ memcpy(ptr, &str255[1], str255[0]); ptr[str255[0]] = '\0'; /* null terminate it. */ if (retval != NULL) { strcat(ptr, ":"); strcat(ptr, retval); free(retval); } /* if */ retval = ptr; } while (infoPB.dirInfo.ioDrDirID != fsRtDirID); return(retval);} /* convFSSpecToPath */char *__PHYSFS_platformCalcBaseDir(const char *argv0){ FSSpec spec; /* Get the name of the binary's parent directory. */ FSMakeFSSpec(procfsspec.vRefNum, procfsspec.parID, procfsspec.name, &spec); return(convFSSpecToPath(&spec, 0));} /* __PHYSFS_platformCalcBaseDir */char *__PHYSFS_platformGetUserName(void){ char *retval = NULL; StringHandle strHandle; short origResourceFile = CurResFile(); /* use the System resource file. */ UseResFile(0); /* apparently, -16096 specifies the username. */ strHandle = GetString(-16096); UseResFile(origResourceFile); BAIL_IF_MACRO(strHandle == NULL, NULL, NULL); HLock((Handle) strHandle); retval = (char *) malloc((*strHandle)[0] + 1); if (retval == NULL) { HUnlock((Handle) strHandle); BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL); } /* if */ memcpy(retval, &(*strHandle)[1], (*strHandle)[0]); retval[(*strHandle)[0]] = '\0'; /* null-terminate it. */ HUnlock((Handle) strHandle); return(retval);} /* __PHYSFS_platformGetUserName */char *__PHYSFS_platformGetUserDir(void){#if 0 return(NULL); /* bah...use default behaviour, I guess. */#else /* (Hmm. Default behaviour is broken in the base library. :) ) */ return(__PHYSFS_platformCalcBaseDir(NULL));#endif} /* __PHYSFS_platformGetUserDir */PHYSFS_uint64 __PHYSFS_platformGetThreadID(void){ return(1); /* single threaded. */} /* __PHYSFS_platformGetThreadID */int __PHYSFS_platformStricmp(const char *x, const char *y){ extern int _stricmp(const char *, const char *); return(_stricmp(x, y)); /* (*shrug*) */} /* __PHYSFS_platformStricmp */static OSErr fnameToFSSpecNoAlias(const char *fname, FSSpec *spec){ OSErr err; Str255 str255; int needColon = (strchr(fname, ':') == NULL); int len = strlen(fname) + ((needColon) ? 1 : 0); if (len > 255) return(bdNamErr); /* !!! FIXME: What happens with relative pathnames? */ str255[0] = len; memcpy(&str255[1], fname, len); /* probably just a volume name, which seems to need a ':' at the end. */ if (needColon) str255[len] = ':'; err = oserr(FSMakeFSSpec(0, 0, str255, spec)); return(err);} /* fnameToFSSpecNoAlias */static OSErr fnameToFSSpec(const char *fname, FSSpec *spec){ Boolean alias = 0; Boolean folder = 0; OSErr err = fnameToFSSpecNoAlias(fname, spec); if (err == dirNFErr) /* might be an alias in the middle of the path. */ { /* * Has to be at least two ':' chars, or we wouldn't get a * dir-not-found condition. (no ':' means it was just a volume, * just one ':' means we would have gotten a fnfErr, if anything. */ char *ptr; char *start; char *path = alloca(strlen(fname) + 1); strcpy(path, fname); ptr = strchr(path, ':'); BAIL_IF_MACRO(!ptr, ERR_NO_SUCH_FILE, err); /* just in case */ ptr = strchr(ptr + 1, ':'); BAIL_IF_MACRO(!ptr, ERR_NO_SUCH_FILE, err); /* just in case */ *ptr = '\0'; err = fnameToFSSpecNoAlias(path, spec); /* get first dir. */ BAIL_IF_MACRO(oserr(err) != noErr, NULL, err); start = ptr; ptr = strchr(start + 1, ':'); /* Now check each element of the path for aliases... */ do { CInfoPBRec infoPB; memset(&infoPB, '\0', sizeof (CInfoPBRec)); infoPB.dirInfo.ioNamePtr = spec->name; infoPB.dirInfo.ioVRefNum = spec->vRefNum; infoPB.dirInfo.ioDrDirID = spec->parID; infoPB.dirInfo.ioFDirIndex = 0; err = PBGetCatInfoSync(&infoPB); if (err != noErr) /* not an alias, really just a bogus path. */ return(fnameToFSSpecNoAlias(fname, spec)); /* reset */ if ((infoPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0) spec->parID = infoPB.dirInfo.ioDrDirID; if (ptr != NULL) /* terminate string after next element. */ *ptr = '\0'; *start = strlen(start + 1); /* make it a pstring. */ err = FSMakeFSSpec(spec->vRefNum, spec->parID, (const unsigned char *) start, spec); if (err != noErr) /* not an alias, really a bogus path. */ return(fnameToFSSpecNoAlias(fname, spec)); /* reset */ err = ResolveAliasFileWithMountFlags(spec, 1, &folder, &alias, 0); if (err != noErr) /* not an alias, really a bogus path. */ return(fnameToFSSpecNoAlias(fname, spec)); /* reset */ start = ptr; /* move to the next element. */ if (ptr != NULL) ptr = strchr(start + 1, ':'); } while (start != NULL); } /* if */ else /* there's something there; make sure final file is not an alias. */ { BAIL_IF_MACRO(oserr(err) != noErr, NULL, err); err = ResolveAliasFileWithMountFlags(spec, 1, &folder, &alias, 0); BAIL_IF_MACRO(oserr(err) != noErr, NULL, err); } /* else */ return(noErr); /* w00t. */} /* fnameToFSSpec */int __PHYSFS_platformExists(const char *fname){ FSSpec spec; return(fnameToFSSpec(fname, &spec) == noErr);} /* __PHYSFS_platformExists */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -