//------------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1993, 1996 by Borland International, All Rights Reserved
// Copyright (c) 1996-1998 Bidus Yura, All rights Reserved
//
/// \file
/// TFile class implementation.
/// Fully rewritten by Yura Bidus
//------------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/file.h>
#include <owl/wsyscls.h>
#if defined(OWL5_COMPAT) // See TFile::GetStatus.
#include <owl/filename.h>
#endif
#if defined(__BORLANDC__)
# pragma option -w-ccc // Disable warning; "Condition is always true/false".
# pragma option -w-inl // Disable warning in standard library; "Functions containing 'statement' are not expanded inline".
#endif
using namespace std;
namespace owl {
OWL_DIAGINFO;
/// \cond
// ////////////////////////////
// Internal support structure
#include <pshpack1.h>
struct __i_uint32_32{
uint32 Lo;
uint32 Hi;
};
struct __i_int32_32{
uint32 Lo;
int32 Hi;
};
#include <poppack.h>
/// \endcond
DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlFileSystem, 1, 0);
//
/// Constructs an exception handling class with identity IDS_BADFILEFORMAT.
//
TXBadFormat::TXBadFormat()
:
TXOwl(IDS_BADFILEFORMAT)
{
}
//
/// Construct a TXBadFormat exception from scratch, and throws it.
//
void
TXBadFormat::Raise()
{
TXBadFormat().Throw();
}
TXBadFormat*
TXBadFormat::Clone()
{
return new TXBadFormat(*this);
}
//
//
void
TXBadFormat::Throw()
{
throw *this;
}
//------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
//
// class TDiskFileHandle
// ~~~~~ ~~~~~~~~~~~~~~~
//
//
// helper functions
static void sys2Mode(uint32& access, uint32& sharedMode, uint32& howOpen, uint32 openMode)
{
if(openMode & TFile::ReadOnly)
access |= GENERIC_READ;
if(openMode & TFile::WriteOnly)
access |= GENERIC_WRITE;
if(openMode & TFile::PermExclusive)
sharedMode |= 0; // exclisive - default
if(openMode & TFile::PermRead)
sharedMode |= FILE_SHARE_READ; //
if(openMode & TFile::PermWrite)
sharedMode |= FILE_SHARE_WRITE; //
// if(openMode & TFile::PermNone) // not implemented in WIN32
// ShareMode |= 0; //
if(openMode & TFile::CreateNew)
howOpen |= CREATE_NEW ; // open
if(openMode & TFile::CreateAlways)
howOpen |= CREATE_ALWAYS; // open
if(openMode & TFile::OpenExisting)
howOpen |= OPEN_EXISTING; // open
if(openMode & TFile::TruncateExist)
howOpen |= TRUNCATE_EXISTING; // open
}
//
// class TDiskFileHandle
// ~~~~ ~~~~~~~~~~~~~~~
//
TDiskFileHandle::TDiskFileHandle(const tstring& fileName, uint32 mode)
{
OpenMode = mode;
FileName = fileName;
uint32 Access = 0;
uint32 ShareMode = 0;
uint32 HowOpen = 0;
sys2Mode(Access, ShareMode, HowOpen, OpenMode);
uint32 flags = FILE_FLAG_RANDOM_ACCESS;
Handle = ::CreateFile(FileName.c_str(),Access,ShareMode,NULL,HowOpen,flags,0);
}
//
TDiskFileHandle::TDiskFileHandle(HANDLE handle, const tstring& fileName, uint mode)
:
Handle(handle), OpenMode(mode), FileName(fileName)
{
}
//
TDiskFileHandle*
TDiskFileHandle::Clone() const
{
HANDLE hHandle = 0;
if(::DuplicateHandle(::GetCurrentProcess(), Handle,
::GetCurrentProcess(), &hHandle,
0, false, DUPLICATE_SAME_ACCESS) && hHandle)
return new TDiskFileHandle(hHandle, FileName.c_str(), OpenMode);
return 0;
}
//
uint32 TDiskFileHandle::LastError()
{
return ::GetLastError();
}
//
bool TDiskFileHandle::Close()
{
if(!::CloseHandle(Handle))
return false;
return true;
}
//
uint32 TDiskFileHandle::Read(void * buffer, uint32 numBytes)
{
DWORD u32Ret;
if(::ReadFile(Handle, buffer, numBytes, &u32Ret, NULL))
return u32Ret;
return TFILE_ERROR;
}
//
bool TDiskFileHandle::Write(const void * buffer, uint32 numBytes)
{
DWORD u32ret;
if(::WriteFile(Handle, buffer, numBytes, &u32ret, NULL))
return true;
return false;
}
//
bool TDiskFileHandle::Length(uint64 newLen)
{
if(Seek(int64(newLen),TFile::beg) == TFILE64_ERROR)
return false;
if(::SetEndOfFile(Handle))
return true;
return false;
}
//
uint64 TDiskFileHandle::Position64() const
{
uint32 ret = ::SetFilePointer(Handle,0,0,(uint32)TFile::cur);
return uint64(ret);
}
//
uint64 TDiskFileHandle::Length64() const
{
__i_uint32_32 ul;
ul.Lo = ::GetFileSize(Handle, (DWORD *)&ul.Hi);
return *(uint64*)&ul;
}
//
bool TDiskFileHandle::Length(uint32 newLen)
{
if(Seek((long)newLen, TFile::beg) == TFILE_ERROR)
return false;
if(::SetEndOfFile(Handle))
return true;
return false;
}
//
uint32 TDiskFileHandle::Position() const
{
uint32 ret = ::SetFilePointer(Handle,0,0,(uint32)TFile::cur);
if( ret != 0xFFFFFFFF)
return ret;
return TFILE_ERROR;
}
//
uint32 TDiskFileHandle::Length() const
{
uint32 ret = ::GetFileSize(Handle, NULL);
if( ret != 0xFFFFFFFF)
return ret;
return TFILE_ERROR;
}
uint64 TDiskFileHandle::Seek(int64 offset, TFile::TSeekDir origin)
{
__i_int32_32 ul = *(__i_int32_32*)&offset;
ul.Lo = ::SetFilePointer(Handle,ul.Lo,(LONG*)&ul.Hi,(uint32)origin);
return uint64(*(int64*)&ul);
}
//
uint32 TDiskFileHandle::Seek(long offset, TFile::TSeekDir origin)
{
uint32 ret = ::SetFilePointer(Handle,offset,0,(uint32)origin);
if( ret != 0xFFFFFFFF)
return ret;
return TFILE_ERROR;
}
//
bool TDiskFileHandle::Flush()
{
if(::FlushFileBuffers(Handle))
return true;
return false;
}
//
bool TDiskFileHandle::LockRange(uint32 position, uint32 count)
{
return ::LockFile(Handle,position,0, count,0);
}
//
bool TDiskFileHandle::UnlockRange(uint32 position, uint32 count)
{
if(::UnlockFile(Handle,position, 0, count, 0))
return true;
return false;
}
bool TDiskFileHandle::LockRange(uint64 position, uint64 count)
{
__i_uint32_32 up = *(__i_uint32_32*)&position;
__i_uint32_32 uc = *(__i_uint32_32*)&count;
return ::LockFile(Handle, up.Lo,up.Hi,uc.Lo,uc.Hi);
}
//
bool TDiskFileHandle::UnlockRange(uint64 position, uint64 count)
{
__i_uint32_32 up = *(__i_uint32_32*)&position;
__i_uint32_32 uc = *(__i_uint32_32*)&count;
return ::UnlockFile(Handle, up.Lo,up.Hi, uc.Lo,uc.Hi);
}
///////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------
//------------------------------------------------------------------------------
uint __sys2Atr(uint32 attrib)
{
uint attr = 0;
if(attrib & FILE_ATTRIBUTE_ARCHIVE)
attr |= TFile::Archive;
if(attrib & FILE_ATTRIBUTE_DIRECTORY)
attr |= TFile::Directory;
if(attrib & FILE_ATTRIBUTE_HIDDEN)
attr |= TFile::Hidden;
if(attrib & FILE_ATTRIBUTE_NORMAL)
attr |= TFile::Normal;
if(attrib & FILE_ATTRIBUTE_READONLY)
attr |= TFile::RdOnly;
if(attrib & FILE_ATTRIBUTE_SYSTEM)
attr |= TFile::System;
if(attrib & FILE_ATTRIBUTE_TEMPORARY)
attr |= TFile::Temporary;
return attr;
}
uint __attr2Sys( uint attrib)
{
uint attr = 0;
if(attrib & TFile::Archive)
attr |= FILE_ATTRIBUTE_ARCHIVE;
if(attrib & TFile::Directory)
attr |= FILE_ATTRIBUTE_DIRECTORY;
if(attrib & TFile::Hidden)
attr |= FILE_ATTRIBUTE_HIDDEN;
if(attrib & TFile::Normal)
attr |= FILE_ATTRIBUTE_NORMAL;
if(attrib & TFile::RdOnly)
attr |= FILE_ATTRIBUTE_READONLY;
if(attrib & TFile::System)
attr |= FILE_ATTRIBUTE_SYSTEM;
if(attrib & TFile::Temporary)
attr |= FILE_ATTRIBUTE_TEMPORARY;
return attr;
}
TTime __MakeTTime(uint16 fdate, uint16 ftime);
void __MakeDosTime(const TTime& time, uint16& fdate, uint16& ftime);
uint __sys2Atr(uint32 attrib);
uint __attr2Sys(uint newattr);
//
bool TDiskFileHandle::GetStatus(TFileStatus & status) const
{
if (::_tfullpath(status.fullName, FileName.c_str(), COUNTOF(status.fullName)) == 0){
status.fullName[0] = 0;
return false;
}
uint32 attrib = ::GetFileAttributes(FileName.c_str());
if(attrib == TFILE_ERROR)
return false;
status.attribute = __sys2Atr(attrib);
TFileTime ftCreate, ftAccess, ftWrite;
if(::GetFileTime(Handle, &ftCreate, &ftAccess, &ftWrite) == FALSE)
return false;
//uint16 ftime,fdate;
//FileTimeToDosDateTime(&ftCreate, &fdate, &ftime);
//status.createTime = __MakeTTime(fdate, ftime);
status.createTime = TTime(ftCreate);
//FileTimeToDosDateTime(&ftWrite, &fdate, &ftime);
//status.modifyTime = __MakeTTime(fdate, ftime);
status.modifyTime = TTime(ftWrite);
//FileTimeToDosDateTime(&ftAccess, &fdate, &ftime);
//status.accessTime = __MakeTTime(fdate, ftime);
status.accessTime = TTime(ftAccess);
status.size = Length();
return true;
}
//////////////////////////////////////////////////////////////////////
// class TFile
// ~~~~~ ~~~~~
//
//
//
/// If ShouldClose is true the file is closed. If the Handle is not FileNull Handle
/// is deleted. Buffer is deleted.
//
TFile::~TFile()
{
if(ShouldClose)
Close();
if(Handle != FileNull)
delete Handle;
delete[] Buffer;
}
// if TFileHandle not support Clone() will throw TXNotSupportedCall()
TFile::TFile(const TFile & file)
{
if(ShouldClose)
Close();
if(Handle != FileNull)
delete Handle;
Handle = file.GetHandle()->Clone();
ShouldClose = true;
CHECK(Handle);
if(!Handle)
TXNotSupportedCall::Raise();
}
/// Opens file name with the given mode. Returns true if successful, false
/// otherwise. Calling Open when the file is already open will fail.
bool TFile::Open(const tstring& fileName, const uint32 openMode)
{
if(IsOpen())
return false;
Handle = new TDiskFileHandle(fileName, openMode);
if(!Handle->IsOpen()){
delete Handle;
Handle = FileNull;
}
ShouldClose = true;
return IsOpen();
}
//------------------------------------------------------------------------------
/// Closes the file. Returns true if successful, false otherwise.
bool TFile::Close()
{
if(IsOpen() && ShouldClose){
if(!Handle->Close())
return false;
}
if(Handle != FileNull)
delete Handle;
Handle = FileNull;
ShouldClose = false;
return true;
}
/// Performs any pending I/O functions. Returns true if successful; false otherwise.
bool TFile::Flush()
{
PRECONDITION(Handle);
return Handle->Flush();
}
/// Locks count bytes, beginning at position of the file. Returns true if
/// successful; false otherwise.
bool TFile::LockRange(uint32 position, uint32 count)
{
PRECONDITION(Handle);
return Handle->LockRange(position, count);
}
/// Unlocks the range at the given Position. Returns true if successful; false
/// otherwise.
bool TFile::UnlockRange(uint32 position, uint32 count)
{
PRECONDITION(Handle);
return Handle->UnlockRange(position, count);
}
inline int binCVTCharMBF (uint8* src, uint8* dst, int /*type*/, int size, int count)
{
memcpy(dst, src, count*size);
return count*size;
}
//------------------------------------------------------------------------------
static int binCVTShortMBF(uint8* _src, uint8* _dst, int /*type*/, int size, int count)
{
int retval = count*size;
uint16* src = (uint16*)_src;
uint16* dst = (uint16*)_dst;
while(count--)
*dst++ = SwapUint16(*src++);
return retval;
}
//------------------------------------------------------------------------------
static int binCVTLongMBF(uint8* _src, uint8* _dst, int /*type*/, int size, int count)
{
int retval = count*size;
uint32* src = (uint32*)_src;
uint32* dst = (uint32*)_dst;
while(count--)
*dst++ = SwapUint32(*src++);
return retval;
}
//------------------------------------------------------------------------------
static int binCVTFloatMBF (uint8* _src, uint8* _dst, int /*type*/, int size, int count)
{
int retval = count*size;
uint32* src = (uint32*)_src;
uint32* dst = (uint32*)_dst;
while(count--)
*dst++ = SwapUint32(*src++);
return retval;
}
//------------------------------------------------------------------------------
static int binCVTDoubleMBF (uint8*, uint8*, int, int, int)
{
return 0;
}
//------------------------------------------------------------------------------
static int binCVTInt64MBF (uint8* _src, uint8* _dst, int /*type*/, int size, int count) //???????????????????
{
int retval = count*size;
__i_uint32_32* src = (__i_uint32_32*)_src;
__i_uint32_32* dst = (__i_uint32_32*)_dst;
while(count--){
dst->Lo = SwapUint32(src->Hi);
dst->Hi = SwapUint32(src->Lo);
dst++;
src++;
}
return retval;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
inline int binCVTCharLBF (uint8* src, uint8* dst, int /*type*/, int size, int count){
memcpy(dst, src, count*size);
return count*size;
}
//------------------------------------------------------------------------------
static int binCVTShortLBF (uint8* _src, uint8* _dst, int /*type*/, int size, int count)
{
int retval = count*size;
uint16* src = (uint16*)_src;
uint16* dst = (uint16*)_dst;
while(count--)
*dst++ = SwapUint16(*src++);
return retval;
}
//------------------------------------------------------------------------------
static int binCVTLongLBF (uint8* _src, uint8* _dst, int /*type*/, int size, int count)
{
int retval = count*size;
uint32* src = (uint32*)_src;
uint32* dst = (uint32*)_dst;
while(count--)
*dst++ = SwapUint32(*src++);
return retval;
}
//------------------------------------------------------------------------------
static int binCVTFloatLBF (uint8* _src, uint8* _dst, int /*type*/, int size, int count)
{
int retval = count*size;
uint32* src = (uint32*)_src;
uint32* dst = (uint32*)_dst;
while(count--)
*dst++ = SwapUint32(*src++);
return retval;
}
//------------------------------------------------------------------------------
static int binCVTDoubleLBF (uint8*, uint8*, int, int, int)
{
return 0;
}
//------------------------------------------------------------------------------
static int binCVTInt64LBF (uint8* _src, uint8* _dst, int /*type*/, int size, int count)
{
int retval = count*size;
__i_uint32_32* src = (__i_uint32_32*)_src;
__i_uint32_32* dst = (__i_uint32_32*)_dst;
while(count--){
dst->Lo = SwapUint32(src->Hi);
dst->Hi = SwapUint32(src->Lo);
dst++;
src++;
}
return retval;
}
//------------------------------------------------------------------------------
typedef int (*cvtDispatchFunc)(uint8*, uint8*, int, int, int); /* Dispatch table entry */
static cvtDispatchFunc dispatchMBF[] = { /* MBF -> LBF */
0, /* varEnd */
binCVTLongMBF, /* varPOINTER */
binCVTCharMBF, /* varCHAR */
binCVTCharMBF, /* varUCHAR */
binCVTShortMBF, /* varSHORT */
binCVTLongMBF, /* varLONG */
binCVTCharMBF, /* varINT8 */
binCVTShortMBF, /* varINT16 */
binCVTLongMBF, /* varINT32 */
binCVTShortMBF, /* varUSHORT */
binCVTLongMBF, /* varULONG */
binCVTCharMBF, /* varUINT8 */
binCVTShortMBF, /* varUINT16 */
binCVTLongMBF, /* varUINT32 */
binCVTFloatMBF, /* varFLOAT */
binCVTDoubleMBF, /* varDOUBLE */
binCVTInt64MBF, /* varINT64 */
binCVTInt64MBF, /* varUINT64r */
};
static cvtDispatchFunc dispatchLBF[] = { /* LBF -> MBF */
0, /* varEnd */
binCVTLongLBF, /* varPOINTER */
binCVTCharLBF, /* varCHAR */
binCVTCharLBF, /* varUCHAR */
binCVTShortMBF, /* varSHORT */
binCVTLongLBF, /* varLONG */
binCVTCharLBF, /* varINT8 */
binCVTShortMBF, /* varINT16 */
binCVTLongLBF, /* varINT32 */
binCVTShortLBF, /* varUSHORT */
binCVTLongLBF, /* varULONG */
binCVTCharLBF, /* varUINT8 */
binCVTShortLBF, /* varUINT16 */
binCVTLongLBF, /* varUINT32 */
binCVTFloatLBF, /* varFLOAT */
binCVTDoubleLBF, /* varDOUBLE */
binCVTInt64LBF, /* varINT64 */
binCVTInt64LBF, /* varUINT64r */
};
//------------------------------------------------------------------------------
#define BINCHECKRTYPE(type) \
if ( (type) <= 0 || (type) > varLastMember) \
return 0;
#define BINCHECKWTYPE(type) \
if ((type) <= 0 || (type) > varLastMember) \
return 0;
#define BINCHECKNBYTES(nBytes) \
if((nBytes) <= 0 ) \
return 0;
//------------------------------------------------------------------------------
/// Returns the number of bytes in a binary data structure.
uint TFile::StructSize(TBinField * fields)
{
uint count = 0;
for(TBinField *bfp = fields; bfp->Count; bfp++)
count += bfp->Count*bfp->Bytes;
return count;
}
//------------------------------------------------------------------------------
/// Read binary structure from file.
/// Returns # of bytes read
uint TFile::ReadStruct(void* buffer, TBinField* fields, TByteOrderType type)
{
TBinField *bfp; /* Field pointer */
uint count; /* Number of bytes read */
int n; /* Read status & # bytes read */
uint8* curBuffer;
cvtDispatchFunc* binReadDisp;
cvtDispatchFunc dispatch;
// int (*dispatch)(uint8*, uint8*, int, int, int ); /* Dispatch table entry */
/* Check all values in the fields array before doing anything. */
for(bfp = fields; bfp->Count; bfp++ ) {
BINCHECKRTYPE(bfp->Type);
BINCHECKNBYTES(bfp->Bytes)
}
// count size of structure
count = StructSize(fields);
// if no conversion
if(EndianType() == type)
return (uint)Read(buffer, count);
// if Litle endian machine -> read as Big endian -> last choise
// else as Little endian
binReadDisp = dispatchMBF;
if(EndianType() == boBig_Endian)
binReadDisp = dispatchLBF;
if(Buffer && BufSize < count){
delete[] Buffer;
Buffer = 0;
}
if(!Buffer){
BufSize = count*5;
Buffer = new uint8[BufSize];
}
if(!Read(Buffer, count))
return 0;
count = 0;
curBuffer = Buffer;
for(bfp = fields; bfp->Count; bfp++ ){
dispatch = binReadDisp[bfp->Type];
if ((n = (*dispatch)(curBuffer,(uint8*)buffer, bfp->Type, bfp->Bytes, bfp->Count)) == -1)
return 0; /* Error occured */
count += n;
buffer = (uint8*)buffer + bfp->Bytes * bfp->Count;
curBuffer += n;
}
return count;
}
//------------------------------------------------------------------------------
/// Writes structures to binary file based on fields description.
/// Returns # of bytes written
uint TFile::WriteStruct(void* buffer, TBinField* fields, TByteOrderType type)
{
TBinField *bfp; /* Field pointer */
uint count; /* Number of bytes read */
int n; /* Read status & # bytes read */
uint8* curBuffer;
cvtDispatchFunc* binReadDisp;
cvtDispatchFunc dispatch;
/* Check all values in the fields array before doing anything. */
for(bfp = fields; bfp->Count; bfp++ ) {
BINCHECKRTYPE(bfp->Type);
BINCHECKNBYTES(bfp->Bytes)
}
// count size of structure
count = StructSize(fields);
// if no conversion
if(EndianType() == type)
return Write(buffer, count);
// if Litle endian machine -> read as Big endian -> last choise
// else as Little endian
binReadDisp = dispatchMBF;
if(EndianType() == boBig_Endian)
binReadDisp = dispatchLBF;
if(Buffer && BufSize < count){
delete[] Buffer;
Buffer = 0;
}
if(!Buffer){
BufSize = count*5;
Buffer = new uint8[BufSize];
}
count = 0;
curBuffer = Buffer;
for(bfp = fields; bfp->Count; bfp++ ){
dispatch = binReadDisp[bfp->Type];
if ((n = (*dispatch)((uint8*)buffer, curBuffer, bfp->Type, bfp->Bytes, bfp->Count)) == -1)
return 0; /* Error occured */
count += n;
buffer = (uint8*)buffer + bfp->Bytes * bfp->Count;
curBuffer += n;
}
return Write(Buffer, count);
}
//------------------------------------------------------------------------------
/// Read binary structure from buffer.
/// Returns # of bytes read
uint TFile::ReadStruct(uint8* ReadBuf, void* buffer, TBinField* fields, TByteOrderType type)
{
TBinField *bfp; /* Field pointer */
int count; /* Number of bytes read */
int n; /* Read status & # bytes read */
uint8* curBuffer;
cvtDispatchFunc* binReadDisp;
cvtDispatchFunc dispatch;
// int (*dispatch)(uint8*, uint8*, int, int, int ); /* Dispatch table entry */
/* Check all values in the fields array before doing anything. */
for(bfp = fields; bfp->Count; bfp++ ) {
BINCHECKRTYPE(bfp->Type);
BINCHECKNBYTES(bfp->Bytes)
}
// count size of structure
count = StructSize(fields);
// if no conversion
if(EndianType() == type){
memcpy(buffer, ReadBuf, count);
return count;
}
// if Litle endian machine -> read as Big endian -> last choise
// else as Little endian
binReadDisp = dispatchMBF;
if(EndianType() == boBig_Endian)
binReadDisp = dispatchLBF;
count = 0;
curBuffer = ReadBuf;
for(bfp = fields; bfp->Count; bfp++ ){
dispatch = binReadDisp[bfp->Type];
if ((n = (*dispatch)(curBuffer,(uint8*)buffer, bfp->Type, bfp->Bytes, bfp->Count)) == -1)
return 0; /* Error occured */
count += n;
buffer = (uint8*)buffer + bfp->Bytes * bfp->Count;
curBuffer += n;
}
return count;
}
//------------------------------------------------------------------------------
/// Writes structures to buffer based on fields description.
/// Returns # of bytes written
uint TFile::WriteStruct(uint8* OutBuf, void* buffer, TBinField* fields, TByteOrderType type)
{
TBinField *bfp; /* Field pointer */
int count; /* Number of bytes read */
int n; /* Read status & # bytes read */
uint8* curBuffer;
cvtDispatchFunc* binReadDisp;
cvtDispatchFunc dispatch;
/* Check all values in the fields array before doing anything. */
for(bfp = fields; bfp->Count; bfp++ ) {
BINCHECKRTYPE(bfp->Type);
BINCHECKNBYTES(bfp->Bytes)
}
// count size of structure
count = StructSize(fields);
// if no conversion
if(EndianType() == type){
memcpy(OutBuf, buffer, count);
return count;
}
// if Litle endian machine -> read as Big endian -> last choise
// else as Little endian
binReadDisp = dispatchMBF;
if(EndianType() == boBig_Endian)
binReadDisp = dispatchLBF;
count = 0;
curBuffer = OutBuf;
for(bfp = fields; bfp->Count; bfp++ ){
dispatch = binReadDisp[bfp->Type];
if ((n = (*dispatch)((uint8*)buffer, curBuffer, bfp->Type, bfp->Bytes, bfp->Count)) == -1)
return 0; /* Error occured */
count += n;
buffer = (uint8*)buffer + bfp->Bytes * bfp->Count;
curBuffer += n;
}
return count;
}
static TBinField CharField[] = {
{varCHAR, 1, 1},
{varEnd, 0, 0},
};
static TBinField ShortField[] = {
{varSHORT, 2, 1},
{varEnd, 0, 0},
};
static TBinField LongField[] = {
{varLONG, 4, 1},
{varEnd, 0, 0},
};
static TBinField FloatField[] = {
{varFLOAT, 4, 1},
{varEnd, 0, 0},
};
static TBinField DoubleField[] = {
{varDOUBLE, 8, 1},
{varEnd, 0, 0},
};
static TBinField Long64Field[] = {
{varDOUBLE, 8, 1},
{varEnd, 0, 0},
};
static TBinField PointField[] = {
{varLONG, 4, 2},
{varEnd, 0, 0},
};
static TBinField RectField[] = {
{varLONG, 4, 2},
{varEnd, 0, 0},
};
static TBinField* FieldTypes[] = {
CharField,
ShortField,
LongField,
FloatField,
DoubleField,
Long64Field,
PointField,
RectField,
};
//------------------------------------------------------------------------------
/// Read binary predefined structure from file.
/// Returns # of bytes read
uint TFile::ReadStruct(void* buffer, TBinType btype, TByteOrderType type)
{
return ReadStruct(buffer, FieldTypes[btype], type);
}
//------------------------------------------------------------------------------
/// Writes predefined structures to binary file.
uint TFile::WriteStruct(void* buffer, TBinType btype, TByteOrderType type)
{
return WriteStruct(buffer, FieldTypes[btype], type);
}
#if defined(OWL5_COMPAT) // must be moved to TFileName
//
/// Fills status with the status for name. Returns nonzero if successful, 0 otherwise.
/// \note This is only available when OWL has been compiled with
/// OWL5_COMPAT defined. The TFileName class should be used instead.
bool TFile::GetStatus(LPCTSTR name, TFileStatus & status)
{
return TFileName(name).GetStatus(status);
}
//
/// Sets file name's status to status.
/// \note This is only available when OWL has been compiled with OWL5_COMPAT
/// defined. The TFileName class should be used instead.
bool TFile::SetStatus(LPCTSTR name, const TFileStatus & status)
{
return TFileName(name).SetStatus(status);
}
#endif //
//
TFile& operator >> ( TFile& file, tstring& s)
{
int size = (int)file.readUint32();
s = _T("");
s.resize(size+1);
if(file.Read((void*)s.c_str(), size) == TFILE_ERROR)
size = -1;
s[size+1] = _T('\0');
return file;
}
uint8
TFile::readUint8()
{
char c;
Read(&c, 1);
return c;
}
uint16
TFile::readUint16()
{
uint16 i;
ReadStruct(&i, TypeShort, boLittle_Endian);
return i;
}
uint32
TFile::readUint32(){
uint32 i;
ReadStruct(&i, TypeLong, boLittle_Endian);
return i;
}
uint64
TFile::readUint64(){
uint64 i;
ReadStruct(&i, TypeLong64, boLittle_Endian);
return i;
}
float
TFile::readFloat()
{
float i;
ReadStruct(&i, TypeFloat, boLittle_Endian);
return i;
}
double
TFile::readDouble()
{
double i;
ReadStruct(&i, TypeDouble, boLittle_Endian);
return i;
}
void TFile::writeUint8( const uint8 c)
{
Write(&c, 1);
}
void TFile::writeUint16( const uint16 i)
{
WriteStruct((void*)&i, TypeShort, boLittle_Endian);
}
void
TFile::writeUint32( const uint32 i)
{
WriteStruct((void*)&i, TypeLong, boLittle_Endian);
}
void
TFile::writeUint64( const uint64 i)
{
WriteStruct((void*)&i, TypeLong64, boLittle_Endian);
}
void
TFile::writeFloat( const float f)
{
WriteStruct((void*)&f, TypeFloat, boLittle_Endian);
}
void
TFile::writeDouble( const double d)
{
WriteStruct((void*)&d, TypeDouble, boLittle_Endian);
}
//------------------------------------------------------------------------------
//
// TBufferedFile
// ~~~~~~~~~~~~~
//
/// The buffer is flushed. If ShouldDelete is true the buffer is deleted.
//
TBufferedFile::~TBufferedFile()
{
FlushBuffer();
if(ShouldDelete)
delete[] FileBuffer;
FileBuffer = 0;
}
//------------------------------------------------------------------------------
/// Allocates a buffer of size bytes.
void TBufferedFile::InitBuffer(uint size)
{
BufferEmpty = true;
EndPos = FileBufSize = size;
CurByte = FileBuffer = new uint8[size];
ShouldDelete = true;
CurPos = StartPos = 0;
}
//------------------------------------------------------------------------------
/// Flushes the buffer by writing any unwritten data to the file. This function is
/// called by Flush() before the operating system is called to flush its buffers.
bool TBufferedFile::FlushBuffer()
{
// if open mode -> write flush buffer
if(GetHandle() && (GetHandle()->GetOpenMode() & WriteOnly)){
if(CurPos != StartPos){
if(!TFile::Write(FileBuffer, CurPos-StartPos)){
WARNX(OwlFileSystem,1, 0,"TBufferedFile::FlushBuffer() error Seek(), line: " << __LINE__);
return false;
}
StartPos = CurPos;
CurByte = FileBuffer;
EndPos = StartPos + FileBufSize;
BufferEmpty = true;
}
}
return true;
}
/// Flushes the current buffer and then deletes it if ShouldDelete is true. If
/// buffer is not NULL it is assigned to FileBuffer; otherwise FileBuffer is
/// allocated size bytes. ShouldDelete is then set.
//
void TBufferedFile::SetBuffer(uint8* buffer, uint size, bool shouldDelete)
{
FlushBuffer();
if(ShouldDelete)
delete[] FileBuffer;
ShouldDelete = shouldDelete;
if(buffer)
FileBuffer = CurByte = buffer;
else{
FileBuffer = CurByte = new uint8[size];
ShouldDelete = true;
}
FileBufSize = size;
// StartPos = CurPos; set in FlushBuffer
EndPos = StartPos + FileBufSize;
}
//
/// Repositions the file pointer to offset bytes from the specified
/// origin. If the position moved to is outside of the buffer, the buffer is
/// flushed. Returns the position moved to or TFILE64_ERROR on error. To get
/// extended error information, call LastError.
//
uint64 TBufferedFile::Seek(int64 offset, TSeekDir origin)
{
PRECONDITION(GetHandle());
// calculate absolute position ->
int64 position = CurPos;
if(origin == cur)
position += offset;
else if(origin == end)
position = int64(Length64()) + offset;
else
position = offset;
uint64 oldpos = CurPos;
if(position >= int64(StartPos) && position < int64(EndPos)){
CurPos = (uint32)position;
CurByte = &FileBuffer[CurPos-StartPos];
}
else{
if(!FlushBuffer()){
WARNX(OwlFileSystem,1, 0,"TBufferedFile::Seek() error FlushBuffer(), line: " << __LINE__);
return TFILE64_ERROR;
}
uint64 newpos = TFile::Seek(offset, origin);
if(newpos != TFILE64_ERROR){
StartPos = CurPos = (uint32)position;
CurByte = FileBuffer;
EndPos = StartPos + FileBufSize;
BufferEmpty = true;
}
else{
WARNX(OwlFileSystem,1, 0,"TBufferedFile::Seek() error Seek(), line: " << __LINE__);
return TFILE64_ERROR;
}
}
return oldpos;
}
//
/// Repositions the file pointer to offset bytes from the specified origin. If the
/// position moved to is outside of the buffer, the buffer is flushed. Returns the
/// position moved to or TFILE_ERROR on error. To get extended error information,
/// call LastError.
//
uint32 TBufferedFile::Seek(long offset, TSeekDir origin)
{
PRECONDITION(GetHandle());
// calculate absolute position ->
uint32 position = CurPos;
if(origin == cur)
position += offset;
else if(origin == end)
position = Length() + offset;
else
position = offset;
uint32 oldpos = CurPos;
if(position >= StartPos && position < EndPos){
CurPos = position;
CurByte = &FileBuffer[CurPos-StartPos];
}
else{
if(!FlushBuffer()){
WARNX(OwlFileSystem,1, 0,"TBufferedFile::Seek() error FlushBuffer(), line: " << __LINE__);
return TFILE_ERROR;
}
uint32 newpos = TFile::Seek(offset, origin);
if(newpos != TFILE_ERROR){
StartPos = CurPos = position;
CurByte = FileBuffer;
EndPos = StartPos + FileBufSize;
BufferEmpty = true;
}
else{
WARNX(OwlFileSystem,1, 0,"TBufferedFile::Seek() error Seek(), line: " << __LINE__);
return TFILE_ERROR;
}
}
return oldpos;
}
//
/// Reads numBytes from the file into buffer. The number of bytes read is returned.
//
uint32 TBufferedFile::Read(void * buffer, uint32 numBytes)
{
PRECONDITION(GetHandle());
uint32 retval = numBytes;
uint8* data = (uint8*)buffer;
// fill buffer if empty and buffer exist
if(BufferEmpty && FileBufSize){
StartPos = CurPos = Position();
uint32 ret = TFile::Read(FileBuffer, FileBufSize);
if(ret == TFILE_ERROR){
WARNX(OwlFileSystem,ret==TFILE_ERROR, 0,"TBufferedFile::Write() error Read(), line: " << __LINE__);
return ret;
}
CurByte = FileBuffer;
EndPos = StartPos + ret;
BufferEmpty = false;
}
while(numBytes > 0){
uint dataSize = EndPos-CurPos;
if(numBytes > dataSize){
if(dataSize > 0){
memmove(data, CurByte, dataSize);
numBytes -= dataSize;
data += dataSize;
}
uint32 ret;
if(numBytes > FileBufSize){
ret = TFile::Read(data, numBytes);
if(ret == TFILE_ERROR){
WARNX(OwlFileSystem,ret==TFILE_ERROR, 0,"TBufferedFile::Write() error Read(), line: " << __LINE__);
return ret;
}
BufferEmpty = true;
numBytes = 0;
}
else{
ret = TFile::Read(FileBuffer, FileBufSize);
if(ret == TFILE_ERROR || ret == 0){
if((buffer == data) && (ret == TFILE_ERROR)){
WARNX(OwlFileSystem,ret==TFILE_ERROR, 0,"TBufferedFile::Write() error Read(), line: " << __LINE__);
StartPos = CurPos;
return ret;
}
else{
StartPos = EndPos = CurPos;
// Note: The number of read bytes should not exceed numBytes (uint32) so we can cast unchecked.
// TODO: Widen the parameter and return type to avoid this narrowing cast.
size_t n = data - static_cast<uint8*>(buffer);
return static_cast<uint32>(n);
}
}
}
StartPos = CurPos;
EndPos = StartPos + ret;
CurByte = FileBuffer;
}
else{
memmove(data, CurByte, numBytes);
data += numBytes;
CurPos += numBytes;
CurByte += numBytes;
numBytes = 0;
}
}
return retval;
}
/// Writes numBytes of buffer to the file. If numBytes is greater than the size of
/// the buffer the buffer is flushed and the data is written directly to the file;
/// if the amount of data in the buffer plus numBytes is greater than the capacity
/// of the buffer the buffer is filled and written to the file and the remaining
/// data is placed in the buffer; otherwise the data is appended to the buffer.
/// Returns true if the operation is successful; false otherwise.
//
bool TBufferedFile::Write(const void* buffer, uint32 numBytes)
{
PRECONDITION(GetHandle());
// if data size greater then buffer -> write directly
if(numBytes > FileBufSize){
if(!FlushBuffer()){
WARNX(OwlFileSystem,1, 0,"TBufferedFile::Write() error FlushBuffer(), line: " << __LINE__);
return false;
}
if(!TFile::Write(buffer, numBytes))
return false;
StartPos = CurPos = Position();
CurByte = FileBuffer;
EndPos = StartPos + FileBufSize;
return true;
}
// else use buffer for output
uint8* data = (uint8*)buffer;
while(numBytes > 0L){
uint freeSize = EndPos - CurPos;
if( numBytes > freeSize ){
memmove(CurByte, data, freeSize);
numBytes -= freeSize;
data += freeSize;
CurPos += freeSize;
if(!TFile::Write(FileBuffer, FileBufSize)){
WARNX(OwlFileSystem,1, 0,"TBufferedFile::Write() error Write(), line: " << __LINE__);
return false;
}
StartPos = CurPos;
EndPos = StartPos + FileBufSize;
CurByte = FileBuffer;
}
else{
memmove(CurByte, data, numBytes);
data += numBytes;
CurByte += numBytes;
CurPos += numBytes;
numBytes = 0;
}
}
return true;
}
//------------------------------------------------------------------------------
//
// TTextFile
// ~~~~~~~~~
//
/// Reads up to size characters and places them in buffer. Normal termination is
/// when a \\r\\n character sequence is encountered. The string in buffer is NULL
/// terminated. NULL is returned on failure; a pointer to buffer is returned on
/// success.
//
LPTSTR
TTextFile::GetString(LPTSTR buffer, uint32 size)
{
PRECONDITION(GetHandle());
LPTSTR str = buffer;
LPTSTR Buff = (LPTSTR)CurByte;
uint length = 0;
if(BufferEmpty){
StartPos = CurPos = Position();
uint32 retval = TFile::Read(FileBuffer, FileBufSize);
if(retval == TFILE_ERROR || retval == 0){
WARNX(OwlFileSystem,retval==TFILE_ERROR,0,_T("TTextFile::GetString() error Read(), line: ") << __LINE__);
return 0;
}
CurByte = FileBuffer;
EndPos = StartPos + retval;
BufferEmpty = false;
}
while(*Buff && *Buff != _T('\r') && *Buff != _T('\n') && length < size){
// if end -> fill buffer
if(CurPos >= EndPos){
CurByte = (uint8*)Buff;
uint32 retval = TFile::Read(FileBuffer, FileBufSize);
if((retval == TFILE_ERROR || retval == 0) && length==0){
WARNX(OwlFileSystem,retval==TFILE_ERROR,0,_T("TTextFile::GetString() error Read(), line: ") <<__LINE__);
return 0;
}
StartPos = CurPos;
EndPos = StartPos + retval;
CurByte = FileBuffer;
Buff = (LPTSTR)CurByte;
if(!retval)
break;
}
#if 0 // check UNICODE support
*str = *Buff;
LPTSTR p = CharNext(str);
length += p - str;
str = p;
p = CharNext(Buff);
uint delta = p - Buff;
CurPos += delta;
Buff += delta;
#else
*str++ = *Buff++;
length++;
CurPos++;
#endif
}
if(*Buff == _T('\r')){
Buff++;
CurPos++;
}
if(*Buff == _T('\n')){
Buff++;
CurPos++;
}
CurByte = (uint8*)Buff;
// End string with 0
*str = _T('\0');
return (*CurByte || length) ? buffer : 0;
}
namespace
{
//
// For use with CopyText
//
struct TTextFileGetString
{
TTextFile& f;
TTextFileGetString(TTextFile& f_) : f(f_) {}
int operator()(LPTSTR buf, int bufSize)
{
LPTSTR r = f.GetString(buf, static_cast<uint32>(bufSize));
return r ? bufSize - 1 : 0;
}
};
} // namespace
//
/// String-aware overload
//
tstring TTextFile::GetString(int size)
{
return CopyText(size, TTextFileGetString(*this));
}
//
/// Writes the NULL terminated character string in buffer to the file and adds a
/// terminating \\r\\n character sequence. The NULL character is not written. On
/// success true is returned; false otherwise.
//
bool
TTextFile::WriteString(LPCTSTR buffer)
{
PRECONDITION(GetHandle());
size_t len = ::_tcslen(buffer) * sizeof(tchar);
// TODO: Widen the parameter type for Write to avoid this check and the narrowing cast.
//
if (!IsRepresentable<uint32>(len))
return false;
bool status = TBufferedFile::Write(buffer, static_cast<uint32>(len));
if(status)
status = TBufferedFile::Write(_T("\r\n"), 2);
return status;
}
uint8
TTextFile::readUint8()
{
uint8 c;
Read(&c, 1);
return c;
}
uint16
TTextFile::readUint16()
{
return (uint16)readUint32();
}
uint32
TTextFile::readUint32()
{
TXNotSupportedCall::Raise();
return 0; //?????????????????????????
}
uint64
TTextFile::readUint64()
{
TXNotSupportedCall::Raise();
return 0; //?????????????????????????
}
float
TTextFile::readFloat()
{
return (float)readDouble();
}
double
TTextFile::readDouble()
{
TXNotSupportedCall::Raise();
return 0; //?????????????????????????
}
void
TTextFile::writeUint8( const uint8 u)
{
Write(&u, 1);
}
void
TTextFile::writeUint16( const uint16 u)
{
writeUint32(u);
}
void
TTextFile::writeUint32( const uint32 u)
{
tchar buf[20];
#if defined __GNUC__
_tprintf(buf, _T("%d"), u);
#else
_ltot(u, buf, 10);
#endif
Write(buf, static_cast<uint32>(::_tcslen(buf))); // TODO: Widen the paramteter type to avoid this narrowing cast.
return;
}
void
TTextFile::writeUint64( const uint64)
{
TXNotSupportedCall::Raise();
return; //?????????????????????????????
}
void
TTextFile::writeFloat( const float f)
{
writeDouble(f);
}
void
TTextFile::writeDouble( const double)
{
TXNotSupportedCall::Raise();
return;//????????????????????????????????????????????
}
//
/// Constructor for iterating through file. The bufsize paramater is used for
/// setting the buffer size.
//
TFileLineIterator::TFileLineIterator(TTextFile& file, uint bufsize)
:
File(&file),
LineBuffer(0),
BuffSize(bufsize),
LineNumber(0),
Done(false)
{
LineBuffer = new tchar[BuffSize];
Done = !NextLine();
}
//------------------------------------------------------------------------------
/// Deletes the buffer.
TFileLineIterator::~TFileLineIterator()
{
delete[] LineBuffer;
}
//------------------------------------------------------------------------------
// all work do here -> must fill LineBuffer
//
/// Loads the next line in the file. Returns true if successful; false otherwise.
//
bool TFileLineIterator::NextLine()
{
if(!File || !File->IsOpen())
return false;
return ToBool(File->GetString(LineBuffer, BuffSize) != 0);
}
//------------------------------------------------------------------------------
/// \cond
#include <pshpack1.h>
struct __TChunk {
uint32 CkId; // 'RIFF' or 'LIST'
uint32 Size; // data size
uint32 Type; // type for main chunk 'WAVE'
};
#include <poppack.h>
/// \endcond
//------------------------------------------------------------------------------
static TBinField ChunkField[] = {
{varLONG, 4, 1}, /* FOURCC CkId; // 'RIFF' or 'LIST' */
{varLONG, 4, 1}, /* data size */
{varEnd, 0, 0},
};
//------------------------------------------------------------------------------
static TBinField ListField[] = {
{varLONG, 4, 1}, /* FOURCC CkId; // 'RIFF' or 'LIST' */
{varLONG, 4, 1}, /* data size */
{varLONG, 4, 1}, /* type for main chunk 'WAVE' */
{varEnd, 0, 0},
};
//------------------------------------------------------------------------------
// without first member
static TBinField ChunkField1[] = {
{varLONG, 4, 1}, /* data size */
{varEnd, 0, 0},
};
//------------------------------------------------------------------------------
static TBinField ListField1[] = {
{varLONG, 4, 1}, /* data size */
{varLONG, 4, 1}, /* type for main chunk 'WAVE' */
{varEnd, 0, 0},
};
//------------------------------------------------------------------------------
/// Writes a data structure of the specified type to the associated file.
bool TRiffFile::CreateChunk(TCkInfo& info, const TCreateFlags type)
{
CHECK(IsOpen());
__TChunk chunk;
chunk.CkId = 0;
TBinField* fields = ListField;
info.Flags = TCkInfo::ckDirty;
chunk.CkId = info.CkId; // type of Atom
if(type == cfCreateList){
chunk.CkId = FOURCC_LIST;
info.Flags |= TCkInfo::ckList;
}
else if(type == cfCreateRiff){
chunk.CkId = FOURCC_RIFF;
info.Flags |= TCkInfo::ckRiff;
}
chunk.Type = info.Type; // type of Atom
chunk.Size = 0; // data size not include size of atom
if(type == cfCreateChunk)
fields = ChunkField;
if(!WriteStruct(&chunk, fields, boLittle_Endian)){
WARNX(OwlFileSystem,1, 0,"TRiffFile::CreateChunk() error WriteStruct(), line: " << __LINE__);
return false;
}
info.Offset = Position();
if(type == cfCreateList || type == cfCreateRiff)
info.Offset -= 4;
return true;
}
//------------------------------------------------------------------------------
bool TRiffFile::Ascent(TCkInfo& info)
{
CHECK(IsOpen());
if(info.Flags & TCkInfo::ckDirty){
info.Size = Position() - info.Offset;
long offset = info.Offset - sizeof(__TChunk) + 4;
if(Seek(offset, beg) == TFILE_ERROR){
WARNX(OwlFileSystem,1, 0,"TRiffFile::Ascent() error Seek(), line: " << __LINE__);
return false;
}
__TChunk chunk;
chunk.CkId = info.CkId;
chunk.Type = info.Type;
chunk.Size = info.Size; // data size not include size of atom
if(info.Flags & TCkInfo::ckList)
chunk.CkId = FOURCC_LIST;
else if(info.Flags & TCkInfo::ckRiff)
chunk.CkId = FOURCC_RIFF;
TBinField* fields = ChunkField;
if(info.Flags & TCkInfo::ckList || info.Flags & TCkInfo::ckRiff)
fields = ListField;
if(!WriteStruct(&chunk, fields, boLittle_Endian)){
WARNX(OwlFileSystem,1, 0,"TRiffFile::Ascent() error WriteStruct(), line: " << __LINE__);
return false;
}
info.Flags = 0;
}
// seek to beginning the next atom if any
long size = info.Offset + info.Size;
if(Seek(size, beg) == TFILE_ERROR){
WARNX(OwlFileSystem,1, 0,"TRiffFile::Ascent() error Seek(), line: " << __LINE__);
return false;
}
return true;
}
/* -------------------------------------------------------------------------- */
bool TRiffFile::Descent(TCkInfo& info, TCkInfo* parent, const TFindFlags flags)
{
CHECK(IsOpen());
__TChunk chunk;
if(flags & ffReset){
if(parent){
long offset = parent->Offset;
if(parent->Flags & TCkInfo::ckList || parent->Flags & TCkInfo::ckRiff)
offset += 4;
if(Seek(offset, beg) == TFILE_ERROR){
WARNX(OwlFileSystem,1, 0,"TRiffFile::Descent() error Seek(), line: " << __LINE__);
return false;
}
}
else // else if parent = 0
if(SeekToBegin() == TFILE_ERROR){
WARNX(OwlFileSystem,1, 0,"TRiffFile::Descent() error SeekToBegin(), line: " << __LINE__);
return false;
}
}
bool bRiff;
bool done = false;
bool retval = false;
uint32 riff, size;
TBinField* fields;
TBinField longField[] = { {varLONG, 4, 1}, {varEnd, 0, 0},};
do{
if(!ReadStruct(&riff, longField, boLittle_Endian)){
WARNX(OwlFileSystem,1, 0,"TRiffFile::Descent() error ReadStruct(), line: " << __LINE__);
return false;
}
fields = ChunkField1;
chunk.CkId = riff;
info.Flags = 0;
bRiff = false;
if(riff == FOURCC_RIFF){
info.Flags |= TCkInfo::ckRiff;
bRiff = true;
fields = ListField1;
}
else if(riff == FOURCC_LIST){
info.Flags |= TCkInfo::ckList;
bRiff = true;
fields = ListField1;
}
if(!ReadStruct(&chunk.Size, fields, boLittle_Endian)){
WARNX(OwlFileSystem,1, 0,"TRiffFile::Descent() error ReadStruct(), line: " << __LINE__);
return false;
}
info.Offset = Position();
if(bRiff)
info.Offset -= 4;
info.Size = chunk.Size;
// if any atom
if(flags & ffFindAny){
info.CkId = chunk.CkId;
info.Type = bRiff ? chunk.Type : 0;
retval = true;
break;
}
//if set flag FindChunk search it
else if(flags & ffFindChunk && chunk.CkId == info.CkId){
info.Type = 0;
retval = true;
break;
}
else if(flags & ffFindList && chunk.Type == info.Type){
info.Type = chunk.Type;
info.CkId = FOURCC_LIST;
retval = true;
break;
}
else if(flags & ffFindRiff && chunk.CkId == FOURCC_RIFF){
info.Type = chunk.Type;
info.CkId = FOURCC_RIFF;
retval = true;
break;
}
size = chunk.Size;
// if list chunk exclude size one field
if(bRiff)
size -= 4;
if(Seek((long)size, cur) == TFILE_ERROR){
done = true;
retval = true;
}
}
while(!done);
return retval;
}
/// \cond
#if !defined(qtstruct_h)
#include <pshpack1.h>
struct __MacAtom {
uint32 Size;
uint32 Type;
};
static TBinField MacAtomFields[] = {
{varLONG, 4, 1}, /* uint32 Size; */
{varCHAR, 1, 4}, /* uint32 Type; not swappable */
{varEnd, 0, 0},
};
#include <poppack.h>
#endif
/// \endcond
/* -------------------------------------------------------------------------- */
bool TQtFile::Descent(TQtInfo& info, TQtInfo* parent, const TFindFlags flags)
{
CHECK(IsOpen());
__MacAtom atom;
uint32 position = 0;
uint32 max_size;
if(flags & ffReset){
if(parent){
if(Seek((long)parent->Offset, beg) == TFILE_ERROR){
WARNX(OwlFileSystem,1, 0,"TQtFile::Descent() error seek line: " << __LINE__);
return false;
}
max_size = parent->Size + parent->Offset;
position = parent->Offset;
}
else{ // else if parent = 0
max_size = Length();
if(SeekToBegin() == TFILE_ERROR){
WARNX(OwlFileSystem,1, 0,"TQtFile::Descent() error seek to begin line: " << __LINE__);
return false;
}
}
}
else{
position = Position();
if(parent)
max_size = parent->Size + parent->Offset - position;
else // else if parent = 0
max_size = Length();
}
bool done = false;
bool status = false;
do{
if(ReadStruct(&atom, MacAtomFields, boBig_Endian)){
if(atom.Type == info.Type){
info.Size = atom.Size;
info.Offset = Position();
info.Flags = 0;
status = true;
done = true;
}
//if set flag FindChunk search it
if(atom.Type != info.Type && flags & ffFindChunk){
if (atom.Size==0 ||
Seek(long(atom.Size-sizeof(atom)),cur)==TFILE_ERROR)
done = true;
position += atom.Size;
}
else
done = true;
}
else
done = true;
}
while(!done && position < max_size);
return status;
}
//------------------------------------------------------------------------------
bool TQtFile::Ascent(TQtInfo& info)
{
CHECK(IsOpen());
if(info.Flags & TQtInfo::qtDirty){
info.Size = Position() - info.Offset + sizeof(__MacAtom);
long offset = info.Offset - sizeof(__MacAtom);
if(Seek(offset, beg)==TFILE_ERROR){
WARNX(OwlFileSystem,1, 0,"TQtFile::Ascent() error seek, line: " << __LINE__);
return false;
}
__MacAtom atom;
atom.Type = info.Type; // type of Atom
atom.Size = info.Size; // data size include size of atom
if(!WriteStruct(&atom, MacAtomFields, boBig_Endian)){
WARNX(OwlFileSystem,1, 0,"TQtFile::Ascent() error write to file, line: " << __LINE__);
return false;
}
info.Flags = 0;
}
// seek to beginning the next atom if any
return ToBool(Seek(long(info.Size+info.Offset-sizeof(__MacAtom)), beg) != TFILE_ERROR);
}
// -----------------------------------------------------------------------------
/// Writes a data structure of the specified type to the associated file.
bool TQtFile::CreateChunk(TQtInfo& info)
{
CHECK(IsOpen());
__MacAtom atom;
info.Flags = TQtInfo::qtDirty;
atom.Type = info.Type; // type of Atom
atom.Size = 0; // data size not include size of atom
if(!WriteStruct(&atom, MacAtomFields, boBig_Endian)){
WARNX(OwlFileSystem,1, 0,"TQtFile::CreateChunk() error write to file, line: " << __LINE__);
return false;
}
info.Offset = Position();
return ToBool(info.Offset != TFILE_ERROR);
}
// -----------------------------------------------------------------------------
static void sys2StrmMode(int& uMode, uint32 openMode)
{
if(!(openMode & TFile::Text))
uMode |= ios::binary;
if(openMode & TFile::ReadWrite){
uMode |= ios::in|ios::out;
if((openMode&TFile::TruncateExist)==0 &&
(openMode&TFile::CreateNew)==0)
uMode |= ios::app;
}
else if(openMode & TFile::ReadOnly)
uMode |= ios::in;
else if(openMode & TFile::WriteOnly)
uMode |= ios::out;
if(openMode & TFile::CreateNew ||
openMode & TFile::CreateAlways ||
openMode & TFile::TruncateExist)
uMode |= ios::trunc; // create
}
// -----------------------------------------------------------------------------
// class TStreamHandle
// ~~~~~ ~~~~~~~~~~~~~
//
//
TStreamHandle::TStreamHandle(TStreamFile* parent, const tstring& fileName, uint32 mode)
:
Parent(parent),
FileName(fileName),
OpenMode(mode)
{
// fstream
int uMode = 0;
sys2StrmMode(uMode, mode);
_USES_CONVERSION;
Parent->open(_W2A(fileName.c_str()), (ios::openmode)uMode);
}
//
uint32 TStreamHandle::LastError()
{
return Parent->bad();
}
//
bool TStreamHandle::IsOpen()
{
return Parent->rdbuf()->is_open();
}
//
TStreamHandle*
TStreamHandle::Clone() const
{
TXNotSupportedCall::Raise();
return 0;//????????????????????????????????
}
//
bool TStreamHandle::Close()
{
if(Parent->rdbuf()->close() == 0)
return false;
return true;
}
//
uint32 TStreamHandle::Read(void * buffer, uint32 numBytes)
{
Parent->read(static_cast<tchar*>(buffer), numBytes/sizeof(tchar));
streamsize n = Parent->gcount();
// Note: n cannot be greater than numBytes, so we can cast unchecked.
// TODO: Widen the parameter and return type to avoid this narrowing cast.
//
return Parent->fail() == 0 ? numBytes : static_cast<uint32>(n);
}
//
bool TStreamHandle::Write(const void * buffer, uint32 numBytes)
{
Parent->write((const tchar *)buffer, numBytes/sizeof(tchar));
return Parent->fail()==0 ? true : false;
}
//
bool TStreamHandle::Length(uint64 newLen)
{
return Length((uint32)newLen);
}
//
uint64 TStreamHandle::Position64() const
{
uint32 retval = Position();
if(retval==TFILE_ERROR)
return TFILE64_ERROR;
return uint64(retval);
}
//
uint64 TStreamHandle::Length64() const
{
return uint64(Length());
}
//
bool TStreamHandle::Length(uint32 /*newLen*/)
{
// if(chsize((uint)Handle->GetHandle(), (long)newLen) != TFILE_ERROR)
// return true;
TXNotSupportedCall::Raise();//?????????????????????????????
return false;
}
//
uint32 TStreamHandle::Position() const
{
streampos retval;
if(OpenMode & TFile::WriteOnly)
retval = Parent->tellp();
else
retval = Parent->tellg();
if(retval == streampos(-1))
return TFILE_ERROR;
return (uint32)retval;
}
//
uint32 TStreamHandle::Length() const
{
if(OpenMode & TFile::WriteOnly){
streampos retval = Parent->tellp();
if(retval == streampos(-1))
return TFILE_ERROR;
return (uint32)retval;
}
uint32 last_pos = ((TStreamHandle*)this)->Seek(0l, TFile::end);
uint32 pos = Position();
((TStreamHandle*)this)->Seek((long)last_pos, TFile::beg);
return pos;
}
//
uint64 TStreamHandle::Seek(int64 offset, TFile::TSeekDir origin)
{
return uint64(Seek((long)offset, origin));
}
//
uint32 TStreamHandle::Seek(long offset, TFile::TSeekDir origin)
{
uint32 position = Position();
if(OpenMode & TFile::WriteOnly)
Parent->seekp((streamoff)offset, (ios::seekdir)origin);
else
Parent->seekg((streamoff)offset, (ios::seekdir)origin);
return position;
}
//
bool TStreamHandle::Flush()
{
if(OpenMode & TFile::WriteOnly)
Parent->flush();
return true;
}
//
bool TStreamHandle::LockRange(uint32 /*position*/, uint32 /*count*/)
{
TXNotSupportedCall::Raise();
return false;
}
//
bool TStreamHandle::UnlockRange(uint32 /*position*/, uint32 /*count*/)
{
TXNotSupportedCall::Raise();
return false;
}
//
//
bool TStreamHandle::LockRange(uint64 position, uint64 count)
{
return LockRange((uint32)position, (uint32)count);
}
//
bool TStreamHandle::UnlockRange(uint64 position, uint64 count)
{
return UnlockRange((uint32)position, (uint32)count);
}
bool TStreamHandle::GetStatus(TFileStatus & /*status*/) const
{
TXNotSupportedCall::Raise();
return false;
}
// -----------------------------------------------------------------------------
//
// TStreamFile in work
// ~~~~~~~~~~~
//
//------------------------------------------------------------------------------
bool TStreamFile::Open(const tstring& fileName, const uint32 mode)
{
if(IsOpen())
return false;
Handle = new TStreamHandle(this, fileName, mode);
if(!Handle->IsOpen()){
delete (TStreamFile*)Handle;
Handle = FileNull;
}
return IsOpen();
}
//------------------------------------------------------------------------------
} // OWL namespace
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
↑ V595 The 'Handle' pointer was utilized before it was verified against nullptr. Check lines: 448, 451.
↑ V614 Uninitialized variable 'ShouldClose' used.
↑ V614 Potentially uninitialized pointer 'Handle' used.
↑ V614 Uninitialized variable 'chunk.Type' used.
↑ V616 The 'TFile::Normal' named constant with the value of 0 is used in the bitwise operation.
↑ V1032 The pointer '& ul' is cast to a more strictly aligned pointer type.
↑ V1032 The pointer '& ul' is cast to a more strictly aligned pointer type.
↑ V1048 The 'info.Type' variable was assigned the same value.
↑ V519 The 'chunk.CkId' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1624, 1628.
↑ V524 It is odd that the body of 'UnlockRange' function is fully equivalent to the body of 'LockRange' function.
↑ V547 Expression 'attrib & TFile::Normal' is always false.
↑ V1051 Consider checking for misprints. It's possible that the 'uMode' should be checked here.
↑ V524 It is odd that the body of 'binCVTCharLBF' function is fully equivalent to the body of 'binCVTCharMBF' function.
↑ V524 It is odd that the body of 'binCVTShortLBF' function is fully equivalent to the body of 'binCVTShortMBF' function.
↑ V524 It is odd that the body of 'binCVTInt64LBF' function is fully equivalent to the body of 'binCVTInt64MBF' function.
↑ V818 It is more efficient to use an initialization list 'FileName(fileName)' rather than an assignment operator.
↑ V815 Decreased performance. Consider replacing the expression 's = ""' with 's.clear()'.