/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "hsFiles.h" #include "hsUtils.h" #include "hsMemory.h" #if HS_BUILD_FOR_MAC #include #include #include /////////////////////////////////////////////////////////////////////////// hsMacFile::hsMacFile() : fFlags(kRefNum_Dirty) { fSpec.name[0] = 0; } hsMacFile::hsMacFile(const char pathAndName[]) : hsFile(pathAndName), fFlags(kRefNum_Dirty) { this->SetSpecFromName(); } hsMacFile::hsMacFile(const FSSpec* spec) : fFlags(kRefNum_Dirty) { this->SetSpec(spec); } hsMacFile::~hsMacFile() { this->Close(); } void hsMacFile::SetSpec(const FSSpec* spec) { if (spec) fSpec = *spec; else fSpec.name[0] = 0; fFlags |= kPathName_Dirty; } void hsMacFile::SetSpecFromName() { Str255 pstr; if (fPathAndName == nil) fSpec.name[0] = 0; else { hsC2PString(fPathAndName, pstr); ::FSMakeFSSpec(0, 0, pstr, &fSpec); } } void hsMacFile::SetNameFromSpec() { CInfoPBRec pb; Str255 dirNameP; char dirName[256], temp[256]; int err; hsP2CString(fSpec.name, temp); pb.dirInfo.ioNamePtr = dirNameP; pb.dirInfo.ioVRefNum = fSpec.vRefNum; pb.dirInfo.ioDrParID = fSpec.parID; pb.dirInfo.ioFDirIndex = -1; do { pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; err = PBGetCatInfoSync(&pb); hsThrowIfOSErr(err); hsP2CString(dirNameP, dirName); strcat(dirName,":"); strcat(dirName, temp); strcpy(temp, dirName); } while( pb.dirInfo.ioDrDirID != fsRtDirID); hsAssert(fPathAndName == nil, "pathname should be nil"); fPathAndName = hsStrcpy(temp); } hsBool hsMacFile::Create(OSType creator, OSType fileType, ScriptCode scriptCode) { this->Close(); OSErr err; (void)::FSpDelete(&fSpec); err = ::FSpCreate(&fSpec, creator, fileType, scriptCode); hsIfDebugMessage(err != 0, "FSpCreate failed", err); return err == 0; } #define kFileNotFound_Err -43 hsBool hsMacFile::OpenDataFork(SInt8 perm, Int16* refnum) { this->Close(); OSErr err; err = ::FSpOpenDF(&fSpec, perm, &fRefNum); if (err == kFileNotFound_Err && (perm & fsWrPerm) && (perm & fsRdPerm) == 0) { if (this->Create('HdSp', '????')) err = ::FSpOpenDF(&fSpec, perm, &fRefNum); } if (err == 0) { fFlags &= ~kRefNum_Dirty; if (refnum) *refnum = fRefNum; return true; } return false; } const char* hsMacFile::GetPathAndName() { if (fFlags & kPathName_Dirty) { this->SetNameFromSpec(); fFlags &= ~kPathName_Dirty; } return fPathAndName; } void hsMacFile::SetPathAndName(const char pathAndName[]) { this->hsFile::SetPathAndName(pathAndName); this->SetSpecFromName(); } hsStream* hsMacFile::OpenStream(const char mode[], hsBool throwIfFailure) { hsThrowIfNilParam(mode); short refnum; SInt8 perm = 0; if (::strchr(mode, 'r')) perm |= fsRdPerm; if (::strchr(mode, 'w')) perm |= fsWrPerm; if (this->OpenDataFork(perm, &refnum)) { hsFileStream* stream = TRACKED_NEW hsFileStream; stream->SetFileRef(refnum); return stream; } hsThrowIfTrue(throwIfFailure); return nil; } void hsMacFile::Close() { if (fFlags & kRefNum_Dirty) { OSErr err = ::FSClose(fRefNum); hsIfDebugMessage(err != 0, "FSClose failed", err); fFlags &= ~kRefNum_Dirty; } this->hsFile::Close(); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// struct hsFolderIterator_Data { FSSpec fSpec; OSType fFileType; OSType fCreator; char fCName[_MAX_PATH]; Int16 fCurrIndex; hsBool fValid; }; hsFolderIterator::hsFolderIterator(const char path[]) { fData = TRACKED_NEW hsFolderIterator_Data; fData->fCurrIndex = 0; fData->fValid = false; #if HS_BUILD_FOR_WIN32 this->SetPath(path); #else this->SetMacFolder(path); #endif } hsFolderIterator::hsFolderIterator(const struct FSSpec* spec) // Alt Constructor - pass in FSSpec from OpenDlg() { fData = TRACKED_NEW hsFolderIterator_Data; fData->fCurrIndex = 0; fData->fValid = false; SetMacFolder(spec->vRefNum, spec->parID); } hsFolderIterator::~hsFolderIterator() { delete fData; } void hsFolderIterator::SetPath(const char path[]) { fPath[0] = 0; fData->fValid = false; fData->fCurrIndex = 0; if (path) { ::strcpy(fPath, path); } } /////////////////////////////////////////////////////////////////////////// void hsFolderIterator::SetMacFolder(OSType folderType) { fData->fCurrIndex = 0; fData->fValid = ::FindFolder(kOnSystemDisk, folderType, false, &fData->fSpec.vRefNum, &fData->fSpec.parID) == 0; this->Reset(); } void hsFolderIterator::SetMacFolder(Int16 vRefNum, Int32 dirID) { fData->fSpec.vRefNum = vRefNum; fData->fSpec.parID = dirID; fData->fCurrIndex = 0; fData->fValid = true; this->Reset(); } void hsFolderIterator::SetMacFolder(const char path[]) { char tmp[255]; FSSpec fileSpec; OSErr err; hsCPathToMacPath(&tmp[1], (char*)path); tmp[0] = hsStrlen(&tmp[1]); SetPath((char*)&tmp[1]); err = FSMakeFSSpec(0, 0, (const unsigned char*)tmp, &fileSpec); if(err == fnfErr) { HSDebugProc("XCmd directory does not exist."); return; } hsAssert(err == noErr, "Error making file spec."); // by now we should have the file spec for the given // directory, however, the DirID is the PARENT directory, // not the child directory. The following steps should // give us the items we want. CInfoPBRec pb; pb.hFileInfo.ioVRefNum = fileSpec.vRefNum; pb.hFileInfo.ioNamePtr = (StringPtr)fileSpec.name; // The name of the child directory. pb.hFileInfo.ioDirID = fileSpec.parID; // The ID of the parent directory. pb.hFileInfo.ioFDirIndex = 0; pb.hFileInfo.ioCompletion = 0; err = ::PBGetCatInfoSync(&pb); hsAssert(err == noErr, "PBGetCatInfoSync() failure."); fData->fSpec.vRefNum = fileSpec.vRefNum; // Volume reference fData->fSpec.parID = pb.dirInfo.ioDrDirID; // child directory ID (Finally!) fData->fCurrIndex = 0; fData->fValid = true; this->Reset(); } /////////////////////////////////////////////////////////////////////////// void hsFolderIterator::Reset() { if (fData->fValid) fData->fCurrIndex = 1; #ifdef HS_DEBUGGING else hsAssert(fData->fCurrIndex == 0, "bad currindex"); #endif } hsBool hsFolderIterator::NextFile() { if (fData->fCurrIndex == 0) return false; CInfoPBRec pb; do { pb.hFileInfo.ioVRefNum = fData->fSpec.vRefNum; pb.hFileInfo.ioNamePtr = (StringPtr)fData->fSpec.name; pb.hFileInfo.ioDirID = fData->fSpec.parID; pb.hFileInfo.ioFDirIndex = fData->fCurrIndex++; OSErr err = ::PBGetCatInfoSync(&pb); if (err) { fData->fCurrIndex = 0; return false; } } while (pb.hFileInfo.ioFlAttrib & ioDirMask); fData->fFileType = pb.hFileInfo.ioFlFndrInfo.fdType; fData->fCreator = pb.hFileInfo.ioFlFndrInfo.fdCreator; return true; } const char* hsFolderIterator::GetFileName() const { if (fData->fCurrIndex == 0) throw "end of folder"; // Copy our filename (in pascal format) into a cstring and then return HSMemory::BlockMove(&fData->fSpec.name[1], fData->fCName, fData->fSpec.name[0]); fData->fCName[fData->fSpec.name[0]] = 0; return fData->fCName; } //////////////////////////////////////////////////////////////////////////// hsBool hsFolderIterator::NextMacFile(OSType targetFileType, OSType targetCreator) { for (;;) { if (this->NextFile() == false) return false; if ((targetFileType == 0 || targetFileType == this->GetMacFileType()) && (targetCreator == 0 || targetCreator == this->GetMacCreator())) return true; } } const FSSpec* hsFolderIterator::GetMacSpec() const { if (fData->fCurrIndex == 0) throw "end of folder"; return &fData->fSpec; } OSType hsFolderIterator::GetMacFileType() const { if (fData->fCurrIndex == 0) throw "end of folder"; return fData->fFileType; } OSType hsFolderIterator::GetMacCreator() const { if (fData->fCurrIndex == 0) throw "end of folder"; return fData->fCreator; } hsBool hsFolderIterator::IsDirectory( void ) const { hsAssert( false, "hsFolderIterator::IsDirectory() not defined on this platform!!!" ); return false; } #endif // HS_BUILD_FOR_MAC