reman3/Rayman_X/cpa/tempgrp/SNA/snafile.c

614 lines
19 KiB
C

/*=========================================================================
* SnaFile.c : Manage files with checksums and basic encryption.
*
* The checksum is a simple xor check.
* To use files w/ checksums you must open, close, read and write to a file
* using SNA_fn_bFOpen, SNA_fn_bFClose, etc.
*
* The functions automatically compute the checksum and/or crypt the datas upon reading or writing.
*
* How to create a file :
* Open it with SNA_fn_bFOpen (specify if you want to use checksum and/or encryption)
* Write data with SNA_fn_ulFWrite (you may call for it several times)
* When ALL datas are written, call SNA_fn_bWriteChecksum,
* then SNA_fn_bFClose
*
*
* How to read a file :
* Open it with SNA_fn_bFOpen
* Read data with SNA_fn_ulFRead (you may call for it several times)
* When ALL datas are read, call SNA_fn_bReadChecksum,
* then SNA_fn_bFClose
* Now, you can check if checksum is good with SNA_fn_bTestChecksum.
*
* You can put several checksums in one file.
* Simply call SNA_fn_bWriteChecksum when you want to add a checksum
* for datas allready written.
* Checksums only control datas written BETWEEN two consecutive SNA_fn_bWriteChecksum.
* Be sure to read checksums at the same place you wrote them.
*
* Do NOT use fseek when writing or reading, it would make the checksum useless.
* You can use other file functions like ftell like this: ftell( stSNAFile->p_xFile );
*
* Version 1.0
* Creation date 25/09/98
* Revision date
*
* (c) Ubi R&D 1998
*=========================================================================
*/
#define min(a, b) (((a) < (b)) ? (a) : (b))
#include <stdio.h>
#include <memory.h>
#include <string.h>
//#include "acp_opfi.h"
#include "snafile.h"
#include "TMP.h"
#include "mmg.h"
#include "snammg.h"
#include "snarlt.h"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* SNA_fn_vSetXorCode
* Sets the xor key for encryption of a file.
* To call after SNA_fn_bFOpen(..).
*/
void SNA_fn_vSetCryptKey( unsigned char _ulCryptKey, struct SNA_tdstFile_ *_p_stFile )
{
_p_stFile->ulCryptKey = _ulCryptKey;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* SNA_fn_vResetChecksum
* Sets the checksum of a file to 0.
* To use after reading and testing it's value, before further reading.
*/
void SNA_fn_vResetChecksum( struct SNA_tdstFile_ *_p_stFile )
{
_p_stFile->ulChecksum = 0;
_p_stFile->ucBytesInChecksumBuffer = 0;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* SNA_fn_bTestChecksum
* Tests if checksum is ok (==0).
* Tu use JUST AFTER SNA_bReadChecksum
*/
ACP_tdxBool SNA_fn_bTestChecksum( struct SNA_tdstFile_ *_p_stFile )
{
return (_p_stFile->ulChecksum == 0);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* SNA_fn_bWriteChecksum
* Write the computed checksum in the file.
* The written checksum checks datas between the current position and
* the beginning of the file or the position of the last call to SNA_fn_bWriteChecksum
*/
ACP_tdxBool SNA_fn_bWriteChecksum( struct SNA_tdstFile_ *_p_stFile )
{
if( SNA_fn_bFileUseChecksum( _p_stFile ) )
{
unsigned long ulTempChecksum = _p_stFile->ulChecksum;
DWORD dwlNumberOfBytesWriten;
if( _p_stFile->ucBytesInChecksumBuffer )
{
memset( &_p_stFile->a4_cChecksumBuffer[_p_stFile->ucBytesInChecksumBuffer], 4-_p_stFile->ucBytesInChecksumBuffer, 0 );
ulTempChecksum ^= *(unsigned long *)_p_stFile->a4_cChecksumBuffer;
_p_stFile->ucBytesInChecksumBuffer = 0;
}
_p_stFile->ulChecksum = 0;
SNA_M_WRITEFILE(_p_stFile->hFile , &ulTempChecksum , sizeof(ulTempChecksum) , &dwlNumberOfBytesWriten , NULL);
return (dwlNumberOfBytesWriten != 0);
}
return TRUE;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* Read file checksum (if file uses checksums)
* Return TRUE if checksum was read ok or FALSE if there was a read error.
* To test the checksum value, use SNA_fn_bTestChecksum
*/
ACP_tdxBool SNA_fn_bReadChecksum( struct SNA_tdstFile_ *_p_stFile )
{
if( SNA_fn_bFileUseChecksum( _p_stFile ) )
{
DWORD dwNbRead;
unsigned long ulTempChecksum = 0;
if( _p_stFile->ucBytesInChecksumBuffer )
{
memset( &_p_stFile->a4_cChecksumBuffer[_p_stFile->ucBytesInChecksumBuffer], 4-_p_stFile->ucBytesInChecksumBuffer, 0 );
_p_stFile->ulChecksum ^= *(unsigned long *)_p_stFile->a4_cChecksumBuffer;
_p_stFile->ucBytesInChecksumBuffer = 0;
}
if (!SNA_M_READFILE(_p_stFile->hFile , &ulTempChecksum , sizeof(ulTempChecksum) , &dwNbRead , NULL))
{
_p_stFile->ulChecksum = -1;
_p_stFile -> bReadSuccess = FALSE;
return FALSE;
}
_p_stFile -> bReadSuccess = TRUE;
_p_stFile->ulChecksum ^= ulTempChecksum;
}
return TRUE;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* Opens a file.
* ucOptions are a bitwise combo of SNA_C_ucUseChecksum and/or SNA_C_ucUseEncryption and/or SNA_C_ucUseMemBuffer
*/
void SNA_fn_vInitFile(unsigned char ucOptions, struct SNA_tdstFile_ *_p_stFile )
{
_p_stFile->ulChecksum = 0;
_p_stFile->ucBytesInChecksumBuffer = 0;
_p_stFile->ucOptions = ucOptions;
_p_stFile->p_fn_bWriteWithoutOptions = SNA_fn_bWriteToFile;
_p_stFile->p_fn_bReadWithoutOptions = SNA_fn_bReadFromFile;
if( SNA_fn_bFileUseEncryption( _p_stFile ) )
{
_p_stFile->ulCryptKey = 0x6AB5CC79; // Set default encryption key.
_p_stFile->p_fn_bDefaultWrite = SNA_fn_bCryptAndWriteToFile;
_p_stFile->p_fn_bDefaultRead = SNA_fn_bReadAndDecryptFromFile;
}
else
{
_p_stFile->ulCryptKey = 0;
_p_stFile->p_fn_bDefaultWrite = SNA_fn_bWriteToFile;
_p_stFile->p_fn_bDefaultRead = SNA_fn_bReadFromFile;
}
}
ACP_tdxBool SNA_fn_bFOpen(
char *_p_szfilename,
unsigned char ucMode,
unsigned char ucOptions,
struct SNA_tdstFile_ *_p_stFile )
{
DWORD dwCreate,dwAccess;
/*
_p_stFile->ulChecksum = 0;
_p_stFile->ucBytesInChecksumBuffer = 0;
_p_stFile->ucOptions = ucOptions;
_p_stFile->p_fn_bWriteWithoutOptions = SNA_fn_bWriteToFile;
_p_stFile->p_fn_bReadWithoutOptions = SNA_fn_bReadFromFile;
if( SNA_fn_bFileUseEncryption( _p_stFile ) )
{
_p_stFile->ulCryptKey = 0x6AB5CC79; // Set default encryption key.
_p_stFile->p_fn_bDefaultWrite = SNA_fn_bCryptAndWriteToFile;
_p_stFile->p_fn_bDefaultRead = SNA_fn_bReadAndDecryptFromFile;
}
else
{
_p_stFile->ulCryptKey = 0;
_p_stFile->p_fn_bDefaultWrite = SNA_fn_bWriteToFile;
_p_stFile->p_fn_bDefaultRead = SNA_fn_bReadFromFile;
}
*/
SNA_fn_vInitFile (ucOptions , _p_stFile);
switch(ucMode)
{
case SNA_C_ucWrite: dwCreate = CREATE_ALWAYS; dwAccess = GENERIC_WRITE;
{
DWORD dwAttrib = GetFileAttributes(_p_szfilename);
if(dwAttrib & FILE_ATTRIBUTE_READONLY)
SetFileAttributes(_p_szfilename , dwAttrib & ~FILE_ATTRIBUTE_READONLY);
}
break;
case SNA_C_ucRead: dwCreate = OPEN_EXISTING; dwAccess = GENERIC_READ; break;
default:
_asm {int 3h};
break;
}
_p_stFile -> hFile = SNA_M_CREATEFILE(_p_szfilename , dwAccess , 0 , NULL , dwCreate , FILE_ATTRIBUTE_NORMAL , NULL);
_p_stFile -> bReadSuccess = (_p_stFile -> hFile != INVALID_HANDLE_VALUE);
return (_p_stFile -> bReadSuccess);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* Closes a file
* Be sure to call SNA_fn_bTestChecksum before Close to check the value of the file checksum.
*/
ACP_tdxBool SNA_fn_bFClose( struct SNA_tdstFile_ *_p_stFile )
{
int iRes;
// _p_stFile->ulChecksum = 0;
_p_stFile->ucBytesInChecksumBuffer = 0;
iRes = (int) SNA_M_CLOSEHANDLE(_p_stFile->hFile);
_p_stFile->hFile = INVALID_HANDLE_VALUE;
return (iRes == 0);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* SNA_fn_ulFWrite
* Write datas into a file with or without encryption and checksum.
* (it checks the option field in SNA_tdstFile)
* Returns the number of items written.
*/
size_t SNA_fn_ulFWrite( void *_p_vBuffer, size_t _ulSize, size_t _ulCount, struct SNA_tdstFile_ *_p_stFile )
{
unsigned long ulTotalSize = _ulSize*_ulCount;
// If nothing to write, then nothing to do...
if( ! ulTotalSize ) return 0;
// Check if this file uses checksums.
if( SNA_fn_bFileUseChecksum( _p_stFile ) )
{
/* It uses checksums. */
unsigned char ucRest;
char *p_cBuffer = _p_vBuffer;
// If there was some bytes remaining in the checksum buffer, take them into account.
if( _p_stFile->ucBytesInChecksumBuffer )
{
// First, fill the buffer.
unsigned char ucBytesToCopy = (unsigned char)min( ulTotalSize, (unsigned long)(4-_p_stFile->ucBytesInChecksumBuffer) );
memcpy( &_p_stFile->a4_cChecksumBuffer[_p_stFile->ucBytesInChecksumBuffer], p_cBuffer, ulTotalSize );
// Update buffer info
_p_stFile->ucBytesInChecksumBuffer += ucBytesToCopy;
p_cBuffer += ucBytesToCopy;
ulTotalSize -= ucBytesToCopy;
// If buffer is full, compute checksum.
if( _p_stFile->ucBytesInChecksumBuffer == 4 )
{
_p_stFile->ulChecksum ^= *(unsigned long *)_p_stFile->a4_cChecksumBuffer;
_p_stFile->ucBytesInChecksumBuffer = 0;
}
}
// Compute number of long integers in the datas.
ucRest = (unsigned char)(ulTotalSize & 0x03); // =Total Size % 4
ulTotalSize >>= 2;
// For each long integer, update the checksum.
while( ulTotalSize )
{
_p_stFile->ulChecksum ^= *(unsigned long *)p_cBuffer;
p_cBuffer += 4;
ulTotalSize--;
}
// Trailing bytes (less than 4 bytes) are put in the checksum buffer.
if( ucRest )
{
memcpy( &_p_stFile->a4_cChecksumBuffer[_p_stFile->ucBytesInChecksumBuffer], p_cBuffer, ucRest );
_p_stFile->ucBytesInChecksumBuffer += ucRest;
}
} // end of checksum calculation
// Then, write the data to the file.
if( ! _p_stFile->p_fn_bDefaultWrite( _p_vBuffer, ulTotalSize, _p_stFile ) )
return 0;
return _ulCount;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* SNA_fn_ulFRead
* Read datas from a file with or without encryption and checksum.
* (it checks the option field in SNA_tdstFile)
* Returns the number of items read.
*/
size_t SNA_fn_ulFRead( void *_p_vBuffer, size_t _ulSize, size_t _ulCount, struct SNA_tdstFile_ *_p_stFile )
{
unsigned long ulTotalSize = _ulSize*_ulCount;
// If nothing to read, then nothing to do...
if( ! ulTotalSize ) return 0;
// First, read the datas.
if( ! _p_stFile->p_fn_bDefaultRead( _p_vBuffer, ulTotalSize, _p_stFile ) )
return 0;
// Check if this file uses checksums.
if( SNA_fn_bFileUseChecksum( _p_stFile ) )
{
unsigned long ulTotalSize = _ulSize*_ulCount;
unsigned char ucRest;
char *p_cBuffer = _p_vBuffer;
if( _p_stFile->ucBytesInChecksumBuffer )
{
unsigned char ucBytesToCopy = (unsigned char)min( ulTotalSize, (unsigned long)(4-_p_stFile->ucBytesInChecksumBuffer) );
memcpy( &_p_stFile->a4_cChecksumBuffer[_p_stFile->ucBytesInChecksumBuffer], p_cBuffer, ucBytesToCopy );
_p_stFile->ucBytesInChecksumBuffer += ucBytesToCopy;
p_cBuffer += ucBytesToCopy;
ulTotalSize -= ucBytesToCopy;
if( _p_stFile->ucBytesInChecksumBuffer == 4 )
{
_p_stFile->ulChecksum ^= *(unsigned long *)_p_stFile->a4_cChecksumBuffer;
_p_stFile->ucBytesInChecksumBuffer = 0;
}
}
ucRest = (unsigned char)(ulTotalSize & 0x03); // =Total Size % 4
ulTotalSize >>= 2;
while( ulTotalSize )
{
_p_stFile->ulChecksum ^= *(unsigned long *)p_cBuffer;
p_cBuffer += 4;
ulTotalSize--;
}
if( ucRest )
{
memcpy( &_p_stFile->a4_cChecksumBuffer[_p_stFile->ucBytesInChecksumBuffer], p_cBuffer, ucRest );
_p_stFile->ucBytesInChecksumBuffer += ucRest;
}
} // End of checksum calculation
return _ulCount;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// For writing datas without encryption nor checksum calculation,
// even if the file has been opened with such options
size_t SNA_fn_ulFWriteWithoutOptions( void *_p_vBuffer, size_t _ulSize, size_t _ulCount, struct SNA_tdstFile_ *_p_stFile )
{
unsigned long ulTotalSize = _ulSize*_ulCount;
// If nothing to write, then nothing to do...
if( ! ulTotalSize ) return 0;
// write the data to the file without encryption nor checksum calculation
if( ! _p_stFile->p_fn_bWriteWithoutOptions( _p_vBuffer, ulTotalSize, _p_stFile ) )
return 0;
return _ulCount;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// For reading datas without encryption nor checksum calculation,
// even if the file has been opened with such options
// Use this function ONLY if you have written the datas you want to read
// with SNA_fn_ulFWriteWithoutOptions
size_t SNA_fn_ulFReadWithoutOptions( void *_p_vBuffer, size_t _ulSize, size_t _ulCount, struct SNA_tdstFile_ *_p_stFile )
{
unsigned long ulTotalSize = _ulSize*_ulCount;
// If nothing to read, then nothing to do...
if( ! ulTotalSize ) return 0;
// read the datas without encryption nor checksum calculation.
if( ! _p_stFile->p_fn_bReadWithoutOptions( _p_vBuffer, ulTotalSize, _p_stFile ) )
return 0;
return _ulCount;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ACP_tdxBool SNA_fn_bFileUseChecksum( struct SNA_tdstFile_ *_p_stFile )
{
return (_p_stFile->ucOptions & SNA_C_ucUseChecksum) != 0;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ACP_tdxBool SNA_fn_bFileUseEncryption( struct SNA_tdstFile_ *_p_stFile )
{
return (_p_stFile->ucOptions & SNA_C_ucUseEncryption) != 0;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
///////
// Handle seek for sna file.
// WARNING : you'd better not use seek with file with checksum and encryption.
// Encryption is handled by seek only if the origin is the current position.
// Checksum calculation is NOT handled by seek.
// This function does not check the validity of the offset.
// A bad offset (seek goes out of file) can cause problems in key calculation for files with encryption...
int SNA_fn_bFseek( struct SNA_tdstFile_ *_p_stFile, long _lOffset, int _lOrigin )
{
// fflush( _p_stFile->p_xFile );
DWORD dwMoveMethod;
if( _lOrigin == SEEK_CUR && SNA_fn_bFileUseEncryption( _p_stFile ) )
{
unsigned char *p_a_ucCryptKeys = (unsigned char *)&_p_stFile->ulCryptKey;
unsigned long ulOffset = abs( _lOffset );
ACP_tdxBool ucForward = (_lOffset>0);
if( _lOffset>0 )
while( ulOffset-- )
{
p_a_ucCryptKeys[0] += p_a_ucCryptKeys[2];
p_a_ucCryptKeys[1] += p_a_ucCryptKeys[3];
}
else
while( ulOffset-- )
{
p_a_ucCryptKeys[0] -= p_a_ucCryptKeys[2];
p_a_ucCryptKeys[1] -= p_a_ucCryptKeys[3];
}
}
if (_lOrigin == SEEK_SET) dwMoveMethod = FILE_BEGIN;
else if (_lOrigin == SEEK_END) dwMoveMethod = FILE_END;
else dwMoveMethod = FILE_CURRENT;
return SNA_M_SETFILEPOINTER(_p_stFile->hFile , _lOffset , NULL , dwMoveMethod);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
int SNA_fn_iFFlush( struct SNA_tdstFile_ *_p_stFile )
{
return (int) SNA_M_FLUSHFILEBUFFERS (_p_stFile->hFile);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Crypt the input data into the file.
// Return FALSE if an IO error occured
// To perform this, the datas to be written are copied into a buffer with encryption.
// Then the buffer is written to the file.
// Datas are cut into 2048 bytes blocs.
ACP_tdxBool SNA_fn_bCryptAndWriteToFile( const void *_p_vData, unsigned long _ulSize, struct SNA_tdstFile_ *_p_stFile )
{
unsigned char a_ucBuffer[2048];
unsigned long ulBytesInBuffer;
const unsigned char *p_ucInput, *p_ucEndInput, *p_ucEndStep;
unsigned char *p_ucOutput;
unsigned char *p_a_ucCryptKeys = (unsigned char *)&_p_stFile->ulCryptKey;
unsigned long ulBytesWritten;
// Compute the begining and the end of the input buffer (=datas to be written).
p_ucInput = _p_vData;
p_ucEndInput = (char *)_p_vData + _ulSize;
// For each 2048 bytes block.
do
{
// Compute amount of data to copy to the buffer (max 2048)
ulBytesInBuffer = p_ucEndInput - p_ucInput;
if( ulBytesInBuffer > 2048 ) ulBytesInBuffer = 2048;
// Compute the pointer to the end of this bloc.
p_ucEndStep = p_ucInput + ulBytesInBuffer;
// Destination = buffer.
p_ucOutput = a_ucBuffer;
// Perform the copy with encryption.
while( p_ucInput < p_ucEndStep )
{
/*
*p_ucOutput++ = (*p_ucInput++ ^ p_a_ucCryptKeys[1]) + p_a_ucCryptKeys[0];
p_a_ucCryptKeys[0] += p_a_ucCryptKeys[2];
p_a_ucCryptKeys[1] += p_a_ucCryptKeys[3];
*/
*p_ucOutput++ = (*p_ucInput++ ^ p_a_ucCryptKeys[1]);
*((DWORD*)p_a_ucCryptKeys) = SNA_fn_dwGetCryptKey(*((DWORD*)p_a_ucCryptKeys));
}
// Writes the buffer to disk.
SNA_M_WRITEFILE(_p_stFile->hFile , a_ucBuffer , ulBytesInBuffer , &ulBytesWritten, NULL);
// If not all datas were written (because of an error), we return FALSE.
if( ulBytesWritten != ulBytesInBuffer )
{
return FALSE;
}
// If not end of input, go for the next bloc.
} while( p_ucInput < p_ucEndInput );
// all the datas were written ok, return TRUE.
return TRUE;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Write the input data into file without encryption.
// Return FALSE if an IO error occured
ACP_tdxBool SNA_fn_bWriteToFile( const void *_p_vData, unsigned long _ulSize, struct SNA_tdstFile_ *_p_stFile )
{
DWORD dwBytesWritten;
SNA_M_WRITEFILE(_p_stFile->hFile , _p_vData , _ulSize , &dwBytesWritten, NULL);
return (dwBytesWritten == _ulSize);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Read the data from the IO buffer and decrypt it.
// Buffer is filled if needed
// Return FALSE if an IO error occured
ACP_tdxBool SNA_fn_bReadAndDecryptFromFile( void *_p_vData, unsigned long _ulSize, struct SNA_tdstFile_ *_p_stFile )
{
unsigned char *p_ucBuffer = _p_vData;
unsigned char *p_ucEndBuffer = p_ucBuffer + _ulSize;
unsigned char *p_a_ucCryptKeys = (unsigned char *)&_p_stFile->ulCryptKey;
// First, read the datas.
DWORD dwBytesRead;
_p_stFile -> bReadSuccess = SNA_M_READFILE(_p_stFile->hFile , p_ucBuffer , _ulSize , &dwBytesRead , NULL);
if( dwBytesRead != _ulSize )
return FALSE;
// Then, decrypt the datas.
for( ; p_ucBuffer<p_ucEndBuffer; p_ucBuffer++ )
{
/*
*p_ucBuffer = (*p_ucBuffer - p_a_ucCryptKeys[0]) ^ p_a_ucCryptKeys[1];
p_a_ucCryptKeys[0] += p_a_ucCryptKeys[2];
p_a_ucCryptKeys[1] += p_a_ucCryptKeys[3];
*/
*p_ucBuffer = (*p_ucBuffer ^ p_a_ucCryptKeys[1]);
*((DWORD*)p_a_ucCryptKeys) = SNA_fn_dwGetCryptKey(*((DWORD*)p_a_ucCryptKeys));
}
return TRUE;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Read the input data from file without encryption.
// Return FALSE if an IO error occured
ACP_tdxBool SNA_fn_bReadFromFile( void *_p_vData, unsigned long _ulSize, struct SNA_tdstFile_ *_p_stFile )
{
DWORD dwBytesRead;
_p_stFile -> bReadSuccess = SNA_M_READFILE(_p_stFile->hFile , _p_vData , _ulSize , &dwBytesRead , NULL);
return (dwBytesRead == _ulSize);
}