📄 cmacfile.cp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
// include platform specific headers here
#include <stdio.h>
#include <fcntl.h>
#include <Folders.h>
#include <Script.h>
#include "CMacFile.h"
#include "hxtick.h"
#include "FullPathName.h"
#include "hxcom.h"
#include "hxbuffer.h"
#include "hxmm.h"
#include "hxfiles.h" /* for HX_FILE_WRITE */
#ifndef _CARBON
#include "FSpCompat.h"
#include "MoreFilesExtras.h"
#else
#include "MoreFilesX.h"
#endif
OSType CMacFile::sCreator = 'PNst';
OSType CMacFile::sFileType = 'PNRA';
BOOL gReadDone = FALSE;
ULONG32 gReadCount = 0;
// async callback proc
pascal void ReadCallback(ParamBlockRec* pb);
// async callback UPP
#ifdef _CARBON
static IOCompletionUPP gReadCallbackUPP=NewIOCompletionUPP(ReadCallback);
#else
static IOCompletionUPP gReadCallbackUPP=NewIOCompletionProc(ReadCallback);
#endif
CHXDataFile*
CHXDataFile::Construct (UINT32 ulFlags)
{
return (CHXDataFile *) new CMacFile;
}
// CHXFile should set the file reference to a value indicating the file is not open
CMacFile::CMacFile (void)
{
mRefNum = 0;
mLastError = noErr;
mAppendMode = FALSE;
mBufferFile = NULL;
mBufferedRead = FALSE;
mWriteFile = NULL;
mBufferedWrite = FALSE;
m_pseudoFileHandle = NULL; // if non-null, a memory manager handle containing the "file data"
m_pseudoFileOffset = 0; // current "read" position in the pseudo file
m_pseudoFileSize = 0; // total pseudo file size
}
// ~CHXFile should close the file if it is open
CMacFile::~CMacFile(void)
{
/* if(mBufferFile)
{
delete mBufferFile;
mBufferFile = NULL;
}
if(mWriteFile)
{
delete mWriteFile;
mWriteFile = NULL;
} */
Close(); // close file if necessary
}
// Create a file with the specified mode
// Close the previous file if it was open
HX_RESULT CMacFile::Create(const char *filename, UINT16 mode,BOOL textflag)
{
Close(); // close previous file if necessary
FSSpec theSpec;
OSErr theErr=noErr;
Close(); // close previous file if necessary
theErr = FSSpecFromPathName(filename, &theSpec);
if(!theErr)
{
Boolean targetIsFolder,wasAliased;
theErr = ::ResolveAliasFile(&theSpec,true,&targetIsFolder,&wasAliased);
}
if(theErr==fnfErr)
theErr = FSCreateDataFile(&theSpec,textflag ? 'ttxt' : sCreator ,textflag ? 'TEXT' : sFileType);
if(!theErr)
theErr = FSOpenFile(&theSpec, fsRdWrPerm, &mRefNum);
if(!theErr)
theErr = ::SetEOF(mRefNum, 0L);
if(!theErr)
mFile = theSpec;
mLastError = theErr;
return(theErr ? -1 : 0);
}
// Open a file with the specified permissions
// Close the previous file if it was open
//
// If the file isn't found, look for a 'RLFL' resource *in the current
// resource chain* with the same name as the file.
HX_RESULT CMacFile::Open(const char *filename, UINT16 mode,BOOL textflag)
{
OSErr theErr = noErr;
short perm = fsCurPerm;
UCHAR length = ::strlen(filename);
FSSpec theSpec;
if(!theErr)
{
Close(); // close previous file if necessary
theErr = FSSpecFromPathName(filename,&theSpec);
if (theErr) //try adding ':' (partial path)
{
UCHAR* partial = new UCHAR[length + 2];
partial[0] = length+1;
partial[1] = ':';
::BlockMoveData(filename,&partial[2],length);
theErr = FSMakeFSSpec(0,0,partial,&theSpec);
if (theErr == dirNFErr)
theErr = fnfErr;
delete [] partial;
}
if(!theErr)
{
Boolean targetIsFolder,wasAliased;
theErr = ::ResolveAliasFile(&theSpec,true,&targetIsFolder,&wasAliased);
}
}
if(!theErr)
{
// figure out mac file permission
perm = fsRdWrPerm;
if (mode & O_WRONLY)
perm = fsWrPerm;
else if (mode & O_RDONLY)
perm = fsRdPerm;
// Store the permissions for this file for later.
m_mode=mode;
theErr = FSOpenFile(&theSpec, perm, &mRefNum);
}
if(theErr != noErr)
{
if(theErr == fnfErr)
{
theErr = FSSpecFromPathName(filename,&theSpec);
if ((mode & O_CREAT) || (mode & O_WRONLY)) //always create if Write mode
theErr = FSCreateDataFile(&theSpec,textflag ? 'ttxt' : sCreator ,textflag ? 'TEXT' : sFileType);
if(!theErr)
theErr = FSOpenFile(&theSpec, perm, &mRefNum);
}
}
if ((theErr) && (mode & O_RDONLY))
{
Handle resHandle;
SInt32 resSize;
// We couldn't open the file, and the request was read-only
//
// See if there's a pseudo-file resource we can use
//
// We need a handle to the resource so we can read from it, but
// we don't want the whole resource loaded into memory, so we
// set ResLoad to false.
SetResLoad(false);
resHandle = GetNamedResource(kRealFileResource, theSpec.name); // 'RLFL'
SetResLoad(true);
if (resHandle)
{
// we have a handle to the resource; determine
// its size and reset our "file pointer"
resSize = GetResourceSizeOnDisk(resHandle);
if (resSize > 0)
{
m_pseudoFileHandle = resHandle;
m_pseudoFileSize = resSize;
m_pseudoFileOffset = 0;
theErr = noErr;
mRefNum = -1; // signals that we're using a pseudo-file and no actual file is open
}
}
}
if (!m_pseudoFileHandle)
{
if(!theErr && (mode & O_CREAT))
theErr = ::SetEOF(mRefNum, 0L);
if(!theErr)
{
mAppendMode = (mode & O_APPEND);
mFile = theSpec;
if(mode & O_TRUNC) theErr = ::SetEOF(mRefNum, 0L);
}
if(theErr && mRefNum != 0) Close();
}
mLastError = theErr;
return(theErr ? HXR_DOC_MISSING : 0);
}
// Close the previous file if it was open
HX_RESULT CMacFile::Close(void)
{
OSErr theErr = noErr;
if (m_pseudoFileHandle)
{
// "close" our pseudo file
//
// We don't need or want to dispose or release our pseudo-
// file handle since it's not using up memory anyway, and
// releasing it would hurt anyone else who happens to be
// reading from it. The handle will be released
// automatically when its owning resource file closes.
m_pseudoFileHandle = 0;
m_pseudoFileOffset = 0;
m_pseudoFileSize = 0;
theErr = noErr;
mRefNum = 0;
}
else if (mRefNum)
{
if(mBufferFile)
{
delete mBufferFile;
mBufferFile = NULL;
}
if(mWriteFile)
{
delete mWriteFile;
mWriteFile = NULL;
}
// close a real file
theErr = ::FSClose(mRefNum);
mRefNum = 0;
if(!theErr) theErr =::FlushVol(nil, mFile.vRefNum);
}
mLastError = theErr;
return(theErr ? -1 : 0);
}
HX_RESULT CMacFile::Delete (const char *filename)
{
OSErr theErr = noErr;
FSSpec theSpec;
HX_ASSERT (!m_pseudoFileHandle);
theErr = FSSpecFromPathName(filename,&theSpec);
if (noErr == theErr)
{
theErr = ::FSpDelete(&theSpec);
}
mLastError = theErr;
return(theErr ? -1 : 0);
}
/* Returns the size of the file in bytes. */
ULONG32 CMacFile::GetSize(void)
{
ULONG32 size=0;
if (m_pseudoFileHandle)
{
size = m_pseudoFileSize;
}
else if (mRefNum)
{
::GetEOF(mRefNum,(long*)&size);
}
return size;
}
// Rewinds the file position to the start of the file
HX_RESULT CMacFile::Rewind(void)
{
OSErr theErr;
if (m_pseudoFileHandle)
{
m_pseudoFileOffset = 0;
theErr = noErr;
}
else
{
theErr = ::SetFPos(mRefNum,fsFromStart,0L);
}
mLastError = theErr;
return(theErr ? HXR_INVALID_FILE : 0);
}
// Seek moves the current file position to the offset from the fromWhere specifier
HX_RESULT CMacFile::Seek(ULONG32 offset, UINT16 fromWhere)
{
OSErr theErr = noErr;
if (m_pseudoFileHandle)
{
switch(fromWhere)
{
case SEEK_SET:
m_pseudoFileOffset = offset;
break;
case SEEK_CUR:
m_pseudoFileOffset += offset;
break;
case SEEK_END:
m_pseudoFileOffset = (m_pseudoFileSize - 1) - offset;
break;
}
// don't go beyond the end (we won't return eofErr either to match
// the real seek below)
if (m_pseudoFileOffset >= m_pseudoFileSize)
{
m_pseudoFileOffset = m_pseudoFileSize - 1;
}
theErr = HXR_OK;
}
else if (mBufferedWrite)
{
long pos = 0;
switch(fromWhere)
{
case SEEK_SET:
pos = offset;
break;
case SEEK_CUR:
pos = mWriteFile->GetCurPos() + offset;
break;
case SEEK_END:
pos = (mWriteFile->GetBufSize() - 1) - offset;
break;
}
mWriteFile->Seek(pos);
}
else
{
switch(fromWhere)
{
case SEEK_SET:
fromWhere = fsFromStart;
break;
case SEEK_CUR:
fromWhere = fsFromMark;
break;
case SEEK_END:
fromWhere = fsFromLEOF;
break;
}
theErr = ::SetFPos(mRefNum,fromWhere,offset);
// returning eofErr was causing problems for ChunkyRes during http play
if (theErr == eofErr)
{
theErr = ::SetEOF(mRefNum,offset);
theErr = ::SetFPos(mRefNum,fromWhere,offset);
theErr = HXR_OK;
}
long pos;
::GetFPos(mRefNum,(long *)&pos);
if(!theErr && mBufferedRead)
{
long count;
::GetEOF(mRefNum, &count);
mBufferFile->PreLoad(pos,count - offset);
}
/* if(!theErr && mBufferedWrite)
{
mWriteFile->Seek(pos);
} */
}
mLastError = theErr;
return(theErr ? HXR_INVALID_FILE : 0);
}
// Tell
ULONG32 CMacFile::Tell(void)
{
ULONG32 pos;
if (m_pseudoFileHandle)
{
pos = m_pseudoFileOffset;
mLastError = noErr;
}
else
{
mLastError = ::GetFPos(mRefNum,(long *)&pos);
}
return(pos);
}
// callback could be at interrupt time
pascal void ReadCallback(ParamBlockRec* pb)
{
OSErr theErr = (*pb).ioParam.ioResult;
gReadCount = pb->ioParam.ioActCount;
gReadDone = TRUE;
}
/* Read reads up to count bytes of data into buf.
returns the number of bytes read, EOF, or -1 if the read failed */
ULONG32 CMacFile::Read (char *buf, ULONG32 count)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -