📄 pgpmacfile.c
字号:
rts
#endif
}
#else
static ushort CalcCRC16Contin(ushort crc, const void *data, long len)
{
const char *dp=(const char *)data;
short i;
while(len--)
{
crc ^= (ushort)(*dp++) << 8;
for (i = 0; i < 8; ++i)
{
if (crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
}
return(crc);
}
static uchar CalcChecksum8Contin(uchar start, const void *data, long len)
{
const char *dp=(char *)data;
while(len--)
start+=*dp++;
return start;
}
static ulong CalcCRC32(const void *data, register long len)
{
const ulong *dp=(const ulong *)data;
ulong crc=0, x;
long len2;
ulong highSet;
len2=len;
len>>=2;
while(--len>=0)
{
highSet=(crc & 0x80000000);
crc<<=1;
if(highSet)
crc|=1;
crc+=*dp++;
}
x=3;
len2 &=x;
len2<<=x;
x=0;
x=~x;
x>>=len2;
x=~x;
x &= *dp;
highSet=(crc & 0x80000000);
crc<<=1;
if(highSet)
crc|=1;
crc+=x;
return crc;
}
#endif
static uchar CalcChecksum8(const void *data, long len)
{
return CalcChecksum8Contin(0, data, len);
}
static ushort CalcCRC16(const void *data, long len)
{
return CalcCRC16Contin(0, data, len);
}
/*
* This routine is called each time before writing to an actual fork. If
* the kPGPCheckMacBin flag is set, it determines whether or not it's a
* valid MacBinary header. If so, it creates the file and opens both the
* data and resource forks. Otherwise it creates and opens the data fork,
* and writes false header information to the data fork, using whatever
* hints it can find to create the file with the correct type and creator.
*/
static PGPError
PrepareToWrite(
PGPFile * file,
PGPBoolean autoMapMacTypes )
{
MacFile * mf = (MacFile *)file->priv;
FSSpec spec;
PGPError err = kPGPError_NoErr;
OSErr macResult;
long length;
pgpAssert( (mf->flags & kPGPMacWrite) != 0 );
if (!(mf->flags & kPGPMacWrite))
return kPGPError_NoErr;
if (mf->flags & kPGPCheckMacBin)
{
mf->flags &= ~(kPGPMacBinMode | kPGPCheckMacBin);
if (mf->totalSize >= 126 && mf->macBinHeader.oldVersion == 0 &&
mf->macBinHeader.minimumVersion <= 129 &&
(mf->macBinHeader.info1.fdFlags & 0xFF) == 0 &&
mf->macBinHeader.zero1 == 0 &&
mf->macBinHeader.name[0] < 64)
{
ushort crc;
pgpAssert(sizeof(crc) == 2);
pgpCopyMemory(&mf->macBinHeader.crc1, &crc, sizeof(crc));
if (crc == CalcCRC16((uchar *)&mf->macBinHeader + 1, 124)
|| ((mf->flags & kPGPNoMacBinCRCOkay) && crc == 0))
{
mf->flags |= kPGPMacBinMode;
file->dataType = kPGPFileDataType_Binary;
}
}
}
if (mf->dataRef != 0)
return kPGPError_NoErr;
if ((err = PFLGetFSSpecFromFileSpec(mf->fileRef, &spec)) != kPGPError_NoErr)
goto error;
if (mf->flags & kPGPMacBinMode)
{
/* XXX Reconsider using a different file type for this */
macResult = FSpCreate( &spec,
pgpGetMacFileCreatorFromPGPFileType( kPGPFileTypeDecryptedBin ),
pgpGetMacFileTypeFromPGPFileType( kPGPFileTypeDecryptedBin ),
smSystemScript);
if ( IsPGPError( macResult ) )
goto macError;
if ((macResult = FSpOpenDF(&spec, fsWrPerm, &mf->dataRef)) != noErr)
goto macError;
if ((macResult = FSpOpenRF(&spec, fsWrPerm, &mf->resRef)) != noErr)
goto macError;
mf->dataOffset = 128;
mf->resOffset = mf->dataOffset +
(mf->macBinHeader.dLength + 127) & ~127L;
mf->totalSize = mf->resOffset +
(mf->macBinHeader.rLength + 127) & ~127L;
}
else
{
OSType creator;
OSType type;
if ( autoMapMacTypes )
{
err = pgpMapFileNameToMacCreatorType( spec.name,
&creator, &type );
if ( IsPGPError( err ) )
{
err = pgpMapFileDataToMacCreatorType(
((uchar *)&mf->macBinHeader) + 1,
&creator, &type );
}
}
if ( IsPGPError( err ) || ! autoMapMacTypes )
{
/* if no mapping, use default types */
creator = pgpGetMacFileCreatorFromPGPFileType( mf->fileType );
type = pgpGetMacFileTypeFromPGPFileType( mf->fileType );
err = noErr;
}
macResult = FSpCreate( &spec, creator,
type, smSystemScript);
if ( IsPGPError( macResult ) )
goto macError;
if ((macResult = FSpOpenDF(&spec, fsWrPerm, &mf->dataRef)) != noErr)
goto macError;
mf->dataOffset = mf->resOffset = 0;
length = mf->totalSize;
if ((macResult = FSWrite(mf->dataRef, &length,
(Ptr)&mf->macBinHeader + 1)) != noErr)
goto macError;
}
return kPGPError_NoErr;
macError:
err = pgpErrorFromMacError(macResult, kPGPError_FileOpFailed);
error:
macSetError(file, err);
return err;
}
/*
* This routine is called after closing a MacBinary file for writing. It
* sets the finder information including type and creator.
*/
static PGPError
SetFileInfo(
PGPFile * file)
{
const MacFile * mf = (MacFile *)file->priv;
FSSpec spec;
CInfoPBRec cpb;
FInfo fInfo;
if (!(mf->flags & kPGPMacWrite) || !(mf->flags & kPGPMacBinMode))
return kPGPError_NoErr;
if (PFLGetFSSpecFromFileSpec(mf->fileRef, &spec) != kPGPError_NoErr)
goto error;
cpbCreationDate( &cpb ) = mf->macBinHeader.creationDate;
cpbModificationDate( &cpb ) = mf->macBinHeader.modificationDate;
fInfo = mf->macBinHeader.info1;
fInfo.fdFlags &= 0xFF00;
fInfo.fdFlags |= mf->macBinHeader.info2;
fInfo.fdFlags &= ~kFinderFlagsIgnore;
fInfo.fdLocation.h = 0;
fInfo.fdLocation.v = 0;
fInfo.fdFldr = 0;
cpbFInfo( &cpb ) = fInfo;
if ( FSpSetCatInfo( &spec, &cpb ) != noErr)
goto error;
return kPGPError_NoErr;
error:
/* XXX Improve error reporting */
macSetError(file, kPGPError_FileOpFailed);
return kPGPError_FileOpFailed;
}
/*
* It should be noted that writing to MacBinary files won't work if seeking
* is used in certain ways. The MacBinary header only interpreted the first
* time data is written past the first 128 bytes, and then the fork lengths
* and offsets are fixed and immutable. This could be fixed at some point,
* but there's no need for it now.
*
* The filename used to create the file is always the <fileRef> passed in,
* not the name in the MacBinary header.
*/
PGPFile *
pgpFileRefMacWriteOpen(
PGPContextRef cdkContext,
PFLConstFileSpecRef fileRef,
PGPFileType fileType,
PGPFileOpenFlags flags,
PGPError * errorCode)
{
PGPFile * file = NULL;
MacFile * mf = NULL;
FSSpec spec;
PGPError err = kPGPError_NoErr;
PGPMemoryMgrRef memoryMgr = pgpGetFileRefMemoryMgr( fileRef );
if ((file = (PGPFile *)PGPNewData( memoryMgr,
sizeof(*file), kPGPMemoryMgrFlags_Clear)) == NULL)
{
err = kPGPError_OutOfMemory;
goto error;
}
file->context = cdkContext;
file->dataType = kPGPFileDataType_Unknown;
if ((mf = (MacFile *)PGPNewData( memoryMgr,
sizeof(*mf), kPGPMemoryMgrFlags_Clear)) == NULL)
{
PGPFreeData( file );
err = kPGPError_OutOfMemory;
goto error;
}
err = PFLCopyFileSpec(fileRef, &mf->fileRef );
if ((err = PFLGetFSSpecFromFileSpec(mf->fileRef, &spec)) != kPGPError_NoErr)
goto error;
mf->fileType = fileType;
/* Try to delete the file first, in case it already exists */
/* XXX Maybe we should check the error, and/or truncate the file instead */
FSpDelete( &spec );
pgpAssert(sizeof(mf->macBinHeader) >= 129);
pgpAssert((flags & kPGPFileOpenLocalEncodeHashOnly) == 0);
mf->flags = kPGPMacWrite;
if (flags & (kPGPFileOpenMaybeLocalEncode | kPGPFileOpenForceLocalEncode))
{
mf->flags |= kPGPCheckMacBin;
if (flags & kPGPFileOpenNoMacBinCRCOkay)
mf->flags |= kPGPNoMacBinCRCOkay;
mf->dataOffset = mf->resOffset = 128;
}
else
mf->dataOffset = mf->resOffset = 0;
mf->dataRef = mf->resRef = 0;
mf->totalSize = 0;
mf->filePos = 0;
file->priv = mf;
file->read = macFileRead;
file->write = macFileWrite;
file->flush = macFileFlush;
file->close = macFileClose;
file->tell = macFileTell;
file->seek = macFileSeek;
file->eof = macFileEof;
file->sizeAdvise = macFileSizeAdvise;
file->error = macFileError;
file->clearError = macFileClearError;
file->write2read = macFileWrite2Read;
file->cfb = macFileCfb;
if ( !( mf->flags & kPGPCheckMacBin) )
{
if ((err = PrepareToWrite(file, FALSE )) != kPGPError_NoErr)
goto error;
}
return file;
error:
if (mf != NULL)
{
if (mf->fileRef != NULL)
PFLFreeFileSpec(mf->fileRef);
pgpContextMemFree( cdkContext, mf);
}
if (file != NULL)
pgpContextMemFree( cdkContext, file);
if (errorCode != NULL)
{
pgpAssertAddrValid(errorCode, PGPError);
*errorCode = err;
}
return NULL;
}
PGPFile *
pgpFileRefMacReadOpen(
PGPContextRef cdkContext,
PFLConstFileSpecRef fileRef,
PGPFileOpenFlags flags,
PGPError * errorCode)
{
PGPFile * file = NULL;
MacFile * mf = NULL;
FSSpec spec;
CInfoPBRec cpb;
ushort crc;
OSErr macResult;
PGPError result = kPGPError_NoErr;
pgpAssert( pgpContextIsValid( cdkContext ) );
if ((file = (PGPFile *)pgpContextMemAlloc( cdkContext,
sizeof(*file), kPGPMemoryMgrFlags_Clear)) == NULL)
{
result = kPGPError_OutOfMemory;
goto error;
}
file->context = cdkContext;
file->dataType = kPGPFileDataType_Unknown;
if ((mf = (MacFile *)pgpContextMemAlloc( cdkContext,
sizeof(*mf), kPGPMemoryMgrFlags_Clear)) == NULL)
{
pgpContextMemFree( cdkContext, file );
result = kPGPError_OutOfMemory;
goto error;
}
result = PFLCopyFileSpec(fileRef, &mf->fileRef);
if ( result != noErr )
goto error;
result = PFLGetFSSpecFromFileSpec(mf->fileRef, &spec);
if ( IsPGPError( result ) )
goto error;
mf->fileType = kPGPFileTypeNone;
macResult = FSpGetCatInfo( &spec, &cpb );
if ( macResult != noErr )
goto macError;
pgpAssert(sizeof(mf->macBinHeader) >= 129);
pgpClearMemory(&mf->macBinHeader, sizeof(mf->macBinHeader));
CopyPString(spec.name, mf->macBinHeader.name);
mf->macBinHeader.info2 = cpbFInfo( &cpb ).fdFlags & 0x00FF;
cpbFInfo( &cpb ).fdFlags &= 0xFF00;
cpbFInfo( &cpb ).fdLocation.h = 0;
cpbFInfo( &cpb ).fdLocation.v = 0;
cpbFInfo( &cpb ).fdFldr = 0;
mf->macBinHeader.info1 = cpbFInfo( &cpb );
mf->macBinHeader.dLength = cpbDataForkSize( &cpb );
mf->macBinHeader.rLength = cpbResForkSize( &cpb );
mf->macBinHeader.creationDate = cpbCreationDate( &cpb );
mf->macBinHeader.modificationDate = cpbModificationDate( &cpb );
mf->macBinHeader.newVersion = 129;
mf->macBinHeader.minimumVersion = 129;
crc = CalcCRC16((const uchar *)&mf->macBinHeader + 1, 124);
pgpAssert(sizeof(crc) == 2);
pgpCopyMemory(&crc, &mf->macBinHeader.crc1, sizeof(crc));
mf->flags = kPGPMacRead;
if ( flags & kPGPFileOpenForceLocalEncode)
{
mf->flags |= kPGPMacBinMode;
file->dataType = kPGPFileDataType_Binary;
}
else if (flags & kPGPFileOpenMaybeLocalEncode)
{
if ( pgpOKToEncodeFSSpecWithoutMacBinary( &spec ) )
{
mf->flags &= ~ kPGPMacBinMode;
}
else
{
mf->flags |= kPGPMacBinMode;
file->dataType = kPGPFileDataType_Binary;
}
}
if ((macResult = FSpOpenDF(&spec, fsRdPerm, &mf->dataRef)) != noErr)
goto macError;
if (mf->flags & kPGPMacBinMode)
{
if ((macResult = FSpOpenRF(&spec, fsRdPerm, &mf->resRef)) != noErr)
goto macError;
mf->dataOffset = 128;
mf->resOffset =
mf->dataOffset + (cpbDataForkSize( &cpb ) + 127) & ~127L;
mf->totalSize = mf->resOffset + (cpbResForkSize( &cpb ) + 127) & ~127L;
if (flags & kPGPFileOpenLocalEncodeHashOnly)
{
mf->flags |= kPGPMacBinHashOnly;
/* Clear the finder flags */
mf->macBinHeader.info1.fdFlags = 0;
mf->macBinHeader.info2 = 0;
/* Clear the creation and modification dates */
mf->macBinHeader.creationDate = 0;
mf->macBinHeader.modificationDate = 0;
/* Clear the filename */
pgpClearMemory(mf->macBinHeader.name,
sizeof(mf->macBinHeader.name));
/*
* Clear the CRC so that if this output gets used to
* recreate a file (which it shouldn't), it won't work
* properly and someone will notice the problem.
*/
pgpClearMemory(&mf->macBinHeader.crc1, sizeof(crc));
}
}
else
{
mf->resRef = 0;
mf->dataOffset = 0;
mf->totalSize = mf->resOffset = cpbDataForkSize( &cpb );
}
mf->filePos = 0;
file->priv = mf;
file->read = macFileRead;
file->write = macFileWrite;
file->flush = macFileFlush;
file->close = macFileClose;
file->tell = macFileTell;
file->seek = macFileSeek;
file->eof = macFileEof;
file->sizeAdvise = macFileSizeAdvise;
file->error = macFileError;
file->clearError = macFileClearError;
file->write2read = macFileWrite2Read;
file->cfb = macFileCfb;
return file;
macError:
result = pgpErrorFromMacError(macResult, kPGPError_CantOpenFile);
error:
if (mf != NULL)
{
if (mf->fileRef != NULL)
PFLFreeFileSpec(mf->fileRef);
pgpContextMemFree( cdkContext, mf);
}
if (file != NULL)
pgpContextMemFree( cdkContext, file);
if (errorCode != NULL)
{
pgpAssertAddrValid(errorCode, PGPError);
*errorCode = result;
}
return NULL;
}
PGPError
pgpMacCalcFileSize(
PFLConstFileSpecRef fileRef,
PGPFileOpenFlags flags,
size_t * fileSize)
{
FSSpec spec;
CInfoPBRec cpb;
PGPBoolean macBinMode;
PGPError result = kPGPError_NoErr;
*fileSize = 0; /* In case there's an error */
if ((result = PFLGetFSSpecFromFileSpec(fileRef, &spec)) != kPGPError_NoErr)
return result;
if ( (result = FSpGetCatInfo( &spec, &cpb )) != noErr)
return pgpErrorFromMacError( result, kPGPError_CantOpenFile);
macBinMode = FALSE;
if ( flags & kPGPFileOpenForceLocalEncode )
{
macBinMode = TRUE;
}
else if (flags & kPGPFileOpenMaybeLocalEncode)
{
macBinMode = ! pgpOKToEncodeFSSpecWithoutMacBinary( &spec );
}
if (macBinMode)
{
*fileSize = 128 + /* MacBinary header */
((cpbDataForkSize( &cpb ) + 127) & ~127L) + /* Data fork */
((cpbResForkSize( &cpb ) + 127) & ~127L); /* Res fork */
}
else
{
*fileSize = cpbDataForkSize( &cpb );
}
return kPGPError_NoErr;
}
static MacFileTypeEntry const *
sFindMacFileTypeEntry( PGPFileType type )
{
PGPUInt16 index;
MacFileTypeEntry const * entry = NULL;
entry = &sMacFileTypeTable[ 0 ];
for( index = 0; index < kNumMacFileTypeEntries; ++index, ++entry )
{
if ( entry->pgpFileType == type )
{
return( entry );
}
}
pgpDebugMsg( "can't find entry for PGPFileType" );
return( NULL );
}
OSType
pgpGetMacFileTypeFromPGPFileType( PGPFileType pgpType )
{
MacFileTypeEntry const * entry = NULL;
entry = sFindMacFileTypeEntry( pgpType );
if ( IsntNull( entry ) )
return( entry->type );
return( 0 );
}
OSType
pgpGetMacFileCreatorFromPGPFileType( PGPFileType pgpType )
{
MacFileTypeEntry const * entry = NULL;
entry = sFindMacFileTypeEntry( pgpType );
if ( IsntNull( entry ) )
return( entry->creator );
return( 0 );
}
#endif /* ] PGP_MACINTOSH */
/*
* Local Variables:
* tab-width: 4
* End:
* vi: ts=4 sw=4
* vim: si
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -