#include <wx/filename.h>
#include <wx/buffer.h>
#include <wx/wfstream.h>
#include <wx/zstream.h>
#include <wx/mstream.h>
#include <wx/dir.h>
#include <wx/arrimpl.cpp>
#include <wx/textfile.h>
#include <stdio.h>
#include <sys/stat.h>
#include "dll/gcomp.h"
#include "storage.h"
#include "commonfunctions.h"
#include "streaminfo.h"
#include "mms.h"
#include "lexer.h"
//WX_DEFINE_LIST(wxStreamList);
WX_DEFINE_OBJARRAY(wxStgArray);
void SetIOPre(wxString MsgPrefix, wxString FileName)
{
wxString preActMsg = _U("PRE_") + MsgPrefix;
Msg(1, _U("%s: %s"), preActMsg.c_str(), FileName.c_str());
//это нам не нать, пока что
/*
DWORD dwAttrs = GetFileAttributes(FileName);
if ((dwAttrs & FILE_ATTRIBUTE_READONLY))
{
dwAttrs &= ~FILE_ATTRIBUTE_READONLY;
BOOL res = SetFileAttributes(FileName, dwAttrs);
}
*/
}
wxString GetStgErrorString(int err)
{
#warning TODO error messages
// switch( err )
// {
// case STG_E_ACCESSDENIED:
// return _U("Access denied");
// case STG_E_FILENOTFOUND:
// return _U("The element with the specified name does not exist");
// case STG_E_FILEALREADYEXISTS:
// return _U("File already exist");
// case STG_E_INVALIDPOINTER:
// return _U("The pointer specified for the element was invalid");
// case STG_E_INSUFFICIENTMEMORY:
// return _U("Insufficient memory");
// case STG_E_INVALIDNAME:
// return _U("Invalid name");
// case STG_E_TOOMANYOPENFILES:
// return _U("Too many open files");
// case -2147287008:
// return _U("Share violation");
// }
wxString res;
res.Printf(_U("Unknown error - %l"), (long)err);
return res;
}
////////////////////////////////////////////////////////////////////
void CStorage::InitZLibEngine()
{
//NOTHING TODO HERE
}
void CStorage::ReleaseZLibEngine()
{
//
}
CStorage::CStorage()
{
IsRootStorage = true;
pStream = NULL;
ExtractedFiles = new wxMapStringToPtr();
ExtractedObjects = new wxMapPtrToPtr();
}
void CStorage::SetParentStorage(CStorage& Storage)
{
IsRootStorage = false;
IStorage* pStorage = Storage.GetStorage();
Push(pStorage);
ExtractedFiles = Storage.ExtractedFiles;
ExtractedObjects = Storage.ExtractedObjects;
}
CStorage::CStorage(CStorage& Storage)
{
SetParentStorage(Storage);
}
CStorage::CStorage(CStorage& Storage, wxString SubStorage)
{
SetParentStorage(Storage);
Open(SubStorage);
}
CStorage::~CStorage()
{
Close(true);
ReleaseMaps();
}
void CStorage::ReleaseMaps()
{
if( IsRootStorage )
{
if(ExtractedFiles) delete ExtractedFiles;
if(ExtractedObjects) delete ExtractedObjects;
ExtractedFiles = NULL;
ExtractedObjects = NULL;
}
}
wxString CStorage::FullPath()
{
wxString str;
POSITION pos;
for(pos=0; pos<Storages.Count();pos++)
{
IStorage* Storage = Storages[pos];
str += _U("/")+Storage->Name();
}
return str;
}
void CStorage::Push(IStorage* pStorage)
{
Storages.push_back(pStorage);
pStream = NULL;
}
IStorage* CStorage::Pop()
{
// if( !IsRootStorage && Storages.Count() <= 1 )
if( Storages.Count() < 1 )
return NULL;
IStorage* pStorage = Storages.Last();
if( !pStorage )
return NULL;
Storages.RemoveAt(Storages.Count()-1);
return pStorage;
}
IStorage* CStorage::GetStorage()
{
IStorage* pos = Storages.Last();
return pos;
}
bool CStorage::CreateCompound(wxString& CompoundFileName)
{
if( !IsRootStorage ) //Создавать compound можно только из корневого объекта
return false;
Close(true);
// wxInputStream* pRootStorage;
// HRESULT hr;
wxFileName wCompoundName(CompoundFileName);
#warning TODO взять реализацию из wine
/*
hr = StgCreateDocfile(wCompoundName,
STGM_DIRECT | STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &pRootStorage);
delete[] wCompoundName;
if( hr != S_OK )
{
Msg(0, "ERR: can't create storage '%s' - %s",
(LPCSTR)CompoundFileName, GetStgErrorString(hr));
throw NULL;
}
Push(pRootStorage);
return true;
*/
}
bool CStorage::OpenCompound(wxString CompoundFileName)
{
if( !IsRootStorage ) //Открывать compound можно только из корневого объекта
return false;
Close(true);
IStorage * pRootStorage = new IStorage(CompoundFileName);
if( !pRootStorage->IsOpened() )
{
Msg(0, _U("ERR: Can not open storage '%s' - %s"), CompoundFileName.c_str(), wxString(wxSysErrorMsg()).c_str());
throw NULL;
}
Push(pRootStorage);
return true;
}
bool CStorage::Open(wxArrayString& StorageNames)
{
int i, max_i = StorageNames.Count() - 1;
for( i = 0; i <= max_i; i++ )
{
if( !Open(StorageNames[i]) )
return false;
}
return true;
}
bool CStorage::Open(const wxString& StorageName)
{
IStorage* Parent = GetStorage();
if( Parent == NULL ) return false;
if( StorageName.Find(_U("/")) < 0 )
{
IStorage* pStorage = OpenStorage(Parent, StorageName);
if( pStorage == NULL ) return false;
Push(pStorage);
}
else
{
wxArrayString name_parts = SplitPath(StorageName);
bool res = Open(name_parts);
return res;
}
return true;
}
bool CStorage::Create(wxArrayString& StorageNames)
{
int i, max_i = StorageNames.Count() - 1;
for( i = 0; i <= max_i; i++ )
{
if( !Create(StorageNames[i]) ) return false;
}
return true;
}
bool CStorage::Create(wxString StorageName)
{
IStorage* Parent = GetStorage();
if( Parent == NULL ) return false;
if( StorageName.Find(_U("/")) >= 0 )
{
wxArrayString name_parts = SplitPath(StorageName);
bool res = Create(name_parts);
return res;
}
if( Open(StorageName) ) return true;
IStorage* pStorage;
HRESULT hr;
#warning TODO взять из wine
/*
hr = GetStorage()->CreateStorage(wStorageName,
STGM_DIRECT | STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0,0,
&pStorage);
*/
if( hr != S_OK )
{
Msg(0, _U("ERR: Cant create storage '%s' in '%s' - %s"), StorageName.c_str(), FullPath().c_str(), GetStgErrorString(hr).c_str());
return false;
}
Push(pStorage);
return true;
}
bool CStorage::CreateStream(const wxString& StreamName)
{
CloseStream();
if( StreamName.Find(_U("/")) >= 0 )
{
wxArrayString name_parts = SplitPath(StreamName);
this->StreamName = name_parts[name_parts.Count()-1];
name_parts.RemoveAt(name_parts.Count()-1);
bool res = Create(name_parts);
if( !res ) return false;
}
else
this->StreamName = StreamName;
HRESULT hr;
#warning TODO взять из wine
/* hr = GetStorage()->CreateStream(wStreamName,
STGM_DIRECT | STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
0,0, &pStream);
*/
if( hr!=0 )
{
Msg(0, _U("ERR: Can't create stream '%s' - %s"), StreamName.c_str(), GetStgErrorString(hr).c_str());
throw NULL;
}
// StreamInfo.UpdateInfo((char*)(LPCSTR)(this->StreamName));
return true;
}
void CStorage::Close(bool CloseAll)
{
CloseStream();
IStorage* pStorage;
while( NULL != (pStorage = Pop()) )
{
//pStorage->Commit(STGC_DEFAULT);
#warning TODO взять из wine
// pStorage->Release();
if( !CloseAll ) return;
}
}
bool CStorage::Delete(wxString StorageName)
{
HRESULT hr;
#warning TODO взять из wine
// hr = GetStorage()->DestroyElement(StorageName);
if( S_OK != hr )
{
Msg(0, _U("ERR: Can't delete element '%s' - %s"), StorageName.c_str(), GetStgErrorString(hr).c_str());
throw NULL;
}
return true;
}
void CStorage::CloseStream()
{
if( pStream != NULL )
{
pStream->Release();
pStream = NULL;
}
}
bool CStorage::OpenStream(const wxString& StreamName)
{
CloseStream();
IStorage* Parent = GetStorage();
if( Parent == NULL ) return false;
if( StreamName.Find(_U("/")) == -1 )
{
pStream = ::OpenStream(Parent, StreamName);
this->StreamName = StreamName;
}
else
{
wxArrayString name_parts = SplitPath(StreamName);
wxString RealName = name_parts[name_parts.Count()-1];
name_parts.RemoveAt(name_parts.Count()-1);
if( !Open(name_parts) ) return false;
pStream = ::OpenStream(GetStorage(), RealName);
this->StreamName = RealName;
}
if( pStream == NULL ) return false;
StreamInfo.UpdateInfo(this->StreamName);
StreamInfo.ReadSize(pStream);
return true;
}
bool CStorage::StorageExist(wxString& StorageName)
{
IStorage* pStorage = ::OpenStorage(GetStorage(), StorageName);
if( pStorage != NULL )
{
pStorage->Release();
return true;
}
return false;
}
bool CStorage::StreamExist(wxString StreamName)
{
IStream* pStream = ::OpenStream(GetStorage(), StreamName);
if( pStream != NULL )
{
pStream->Release();
return true;
}
return false;
}
long CStorage::GetStreamSize(wxString& StreamName)
{
long size;
if( !OpenStream(StreamName) ) return -1L;
size = ::GetStreamSize(pStream);
CloseStream();
return size;
}
void CStorage::Rewind()
{
wxFileOffset SeekZero = 0;
pStream->Seek(SeekZero, wxFromStart, NULL);
}
void CStorage::GetCleanStream()
{
if( StreamInfo.Packed )
{
IStream * pUnpackedStream = new IStream();
wxZlibInputStream zStream(*(pStream->GetInStream()), wxZLIB_NO_HEADER);
zStream.Read(*(pUnpackedStream->GetOutStream()));
pStream->Release();
pStream = pUnpackedStream;
}
if( StreamInfo.HaveSize )
{
StreamInfo.ReadSize(pStream); //размер читаем до обработки, чтобы определить длину длины в заголовке
wxFileOffset Offset = StreamInfo.ContentOffset;
pStream->Seek(Offset, wxFromStart, NULL);
IStream* CleanStream = new IStream();
wxFileOffset BytesToCopy = 0;
BytesToCopy = StreamInfo.FullSize - StreamInfo.SizeBytes - StreamInfo.SizeOffset;
pStream->CopyTo(CleanStream, BytesToCopy, NULL, NULL);
Offset = 0;
CleanStream->Seek(Offset, wxFromStart, NULL);
pStream->Release();
pStream = CleanStream;
}
else
{
StreamInfo.ReadSize(pStream);
}
}
bool CStorage::CopyToFile(wxFile * File, wxFileOffset bytes_to_copy)
{
if( File == NULL ) return false;
wxFileOffset BytesToRead = BUFFER_SIZE, BytesRead = 0, BytesWritten = 0;
if( bytes_to_copy <= 0 ) Rewind();
do
{
wxMemoryBuffer * buff = new wxMemoryBuffer(BUFFER_SIZE);
if( bytes_to_copy > 0 && BytesToRead > bytes_to_copy )
BytesToRead = bytes_to_copy;
pStream->Read(buff, BytesToRead, &BytesRead);
if( BytesRead > 0 )
{
BytesWritten = File->Write(buff->GetData(), BytesRead);
if( BytesWritten < BytesRead ) return false;
}
if( bytes_to_copy > 0 )
{
if( bytes_to_copy <= BytesRead ) break;
bytes_to_copy -= BytesRead;
}
delete buff;
} while( BUFFER_SIZE == BytesRead );
return true;
}
bool CStorage::CopyToFile(wxString FileName, bool OnlyRestOfSream)
{
if( pStream == NULL ) return false;
wxFile File;
wxString MsgPrefix = wxEmptyString;
wxFileOffset bytes_to_copy = 0;
//Разберёмся с картинками
if( StreamInfo.Picture )
{
StreamInfo.DeterminePictureType(pStream);
FileName += StreamInfo.PictureType;
}
else if( StreamInfo.PictureGallery )
{
return ExtractPictureGallery(FileName);
}
if( OnlyRestOfSream )
{
wxFileOffset Offset = 0;
wxFileOffset Pos = 0;
pStream->Seek(Offset, wxFromCurrent, &Pos);
bytes_to_copy = StreamInfo.FullSize - Pos;
if( bytes_to_copy == 0 ) return true;
}
AddToExtractedList(FileName, NULL);
if( wxFileExists(FileName) )
{
if( bytes_to_copy == 0 )
{
if( FullCompare(FileName) == 0 ) return true;
}
else if( Compare(FileName, bytes_to_copy) == 0 )
{
return true;
}
MsgPrefix = _U("UPD");
}
else
{
MsgPrefix = _U("NEW");
}
SetIOPre(MsgPrefix, FileName);
File.Open(FileName, wxFile::write);
if( !CopyToFile(&File, bytes_to_copy) )
{
Msg(0, _U("Error writing to file '%s' - %s"), FileName.c_str(), wxSysErrorMsg());
throw NULL;
}
File.Close();
/*
wxTextFile Text(FileName);
if(Text.Open(FileName, wxCSConv(wxFONTENCODING_CP1251)))
{
Text.Write(wxTextFileType_Unix);
}
*/
Msg(1, _U("%s: %s"), MsgPrefix.c_str(), FileName.c_str());
return true;
}
bool CStorage::CopyToFile(const wxString& StreamName, const wxString& FileName)
{
if( !OpenStream(StreamName) ) return false;
GetCleanStream();
if( StreamInfo.PictureGallery )
{
return ExtractPictureGallery(FileName);
}
if( StreamInfo.HaveSize )
{
if( (StreamInfo.Size != (StreamInfo.FullSize - StreamInfo.SizeBytes - StreamInfo.SizeOffset)) )
Msg(0, _U("WARNING: Checksum %ib != real size %ib. Stream '%s/%s'. File '%s'"),
(int)StreamInfo.Size,
(int)(StreamInfo.FullSize - StreamInfo.SizeBytes - StreamInfo.SizeOffset),
FullPath().c_str(), StreamName.c_str(),
FileName.c_str()
);
}
return CopyToFile(FileName);
}
bool CStorage::Extract(const wxString& DestDir, bool WithContainerContents)
{
wxString StreamName, FileName, cc(_U("Container.Contents"));
wxMkdir(DestDir);
Entries list = GetStorage()->EnumElements();
Entries::iterator it;
for(it=list.begin();it!=list.end();++it)
{
StreamName = (*it)->Name;
FileName = DestDir + _U("/") + StreamName;
if((*it)->IsDir)
{
if( Open(StreamName) )
{
Extract(FileName, WithContainerContents);
Close();
}
}
else
{
if( !WithContainerContents && StreamName == cc ) continue;
CopyToFile(StreamName, FileName);
}
}
return true;
}
unsigned long CStorage::AppendFile(IStream* pStream, wxFile* File)
{
size_t BytesRead;
unsigned long TotalBytesRead = 0;
wxFileOffset offset, pos;
pos = ::GetStreamSize(pStream);
offset = pos;
pStream->Seek(offset, wxFromStart, &pos);
size_t BytesToRead;
do
{
wxMemoryBuffer * buff = new wxMemoryBuffer(BUFFER_SIZE);
BytesToRead = buff->GetBufSize();
BytesRead = File->Read(buff->GetWriteBuf(BytesToRead), BytesToRead);
pStream->Write(buff, BytesRead, NULL);
TotalBytesRead += BytesRead;
} while( BytesRead == BytesToRead );
return TotalBytesRead;
}
unsigned long CStorage::AppendFile(IStream* pStream, wxString& FileName)
{
wxFile File(FileName, wxFile::read);
if( !File.IsOpened() ) return 0;
unsigned long bytes_appended = AppendFile(pStream, &File);
File.Close();
return bytes_appended;
}
bool CStorage::FromFile(wxFile* File, wxString FileName)
{
IStream* pStreamText;
if( StreamInfo.Packed )
pStreamText = new IStream();
else
pStreamText = pStream;
if( StreamInfo.HaveSize )
{
StreamInfo.ReadFileSize(File); //Определим, сколько байт 0xFF и размер размера
WriteSizeToStream(pStreamText);
}
File->Seek(0);
AppendFile(pStreamText, File);
if( StreamInfo.Packed )
{
wxFileOffset SeekZero = 0;
pStreamText->Seek(SeekZero, wxFromStart, NULL);
#warning TODO compress
// iLibEngine->pkCompress(pStreamText, pStream);
pStreamText->Release();
}
if( !FileName.IsNull() ) Msg(2, _U("CPY: '%s'"), FileName.c_str());
return true;
}
bool CStorage::FromFile(wxString& FileName)
{
wxFile File(FileName, wxFile::read);
if( !File.IsOpened() ) return false;
FromFile(&File, FileName);
File.Close();
return true;
}
bool CStorage::StreamFromFile(wxString StreamName, wxString FileName)
{
if( !wxFileExists(FileName) ) return false;
StreamInfo.UpdateInfo(StreamName);
if( StreamInfo.Picture )
{
StreamInfo.DeterminePictureType(FileName);
if( !StreamInfo.PictureType.IsEmpty() )
{
int offset = StreamName.Len() - StreamInfo.PictureType.Len();
StreamName = StreamName.Left(offset); //уберём расширение
}
}
else if( StreamInfo.PictureGallery )
{
return ImportPictureGallery(StreamName, FileName);
}
wxString PictureType = StreamInfo.PictureType; //Сохраним расширение
if( !CreateStream(StreamName) ) return false;
StreamInfo.PictureType = PictureType;
return FromFile(FileName);
}
void CStorage::AddZeroByte()
{
wxMemoryBuffer byte;
byte.AppendByte(0);
if( pStream == NULL ) return;
pStream->Write(&byte, 1, NULL);
}
bool CStorage::StreamFromString(const wxString& StreamName, const wxString& String)
{
if( !CreateStream(StreamName) ) return false;
StreamInfo.ReadSize(String);
IStream* pStreamText;
if( StreamInfo.Packed )
pStreamText = new IStream();
else
pStreamText = pStream;
WriteSizeToStream(pStream);
wxMemoryBuffer buf;
buf.AppendData(String.c_str(), String.Len());
pStream->Write(&buf, String.Len(), NULL);
if( StreamInfo.Packed )
{
wxFileOffset SeekZero = 0;
pStream->Seek(SeekZero, wxFromStart, NULL);
#warning TODO compress
// iLibEngine->pkCompress(pStreamText, pStream);
pStreamText->Release();
}
return true;
}
bool CStorage::StorageFromDir(wxString StorageName, wxString SrcDir)
{
wxString FileName;
wxDir dir;
if( !wxDirExists(SrcDir) ) return false;
if( !Create(StorageName) )
{
Msg(0, _U("ERR: Can't create storage %s"), StorageName.c_str());
return false;
}
GalleryImported = false;
bool cont = dir.GetFirst(&FileName);
while(cont)
{
if( IsIgnoredFile(FileName) ) continue;
wxFileName name(FileName);
if( name.IsDir() )
{
StorageFromDir(name.GetName(), FileName);
Close();
}
else
StreamFromFile(name.GetName(), FileName);
};
return true;
}
void CStorage::WriteSizeToStream(IStream* pStream)
{
wxMemoryBuffer buf;
if( !StreamInfo.HaveSize ) return;
if( StreamInfo.Picture )
{
//Если формат неизвестен - поток был выгружен As Is. Размер писать не нужно
if( StreamInfo.PictureType.IsEmpty() ) return;
unsigned char signature[] = {0x6c, 0x74, 0x00, 0x00};
buf.AppendData(signature, 4);
pStream->Write(&buf, 4, NULL);
}
else
{
buf.AppendByte(0xFF);
//Начальные байты 0xFF
for( unsigned int i = 0; i < StreamInfo.SizeOffset; i++ )
pStream->Write(&buf, 1, NULL);
}
buf.SetDataLen(0);
switch( StreamInfo.SizeBytes )
{
case 1:
buf.AppendData((void*)&StreamInfo.Size, 1);
pStream->Write(&buf, StreamInfo.SizeBytes, NULL);
break;
case 2:
buf.AppendData((void*)&StreamInfo.Size, 2);
pStream->Write(&buf, StreamInfo.SizeBytes, NULL);
break;
case 4:
buf.AppendData((void*)&StreamInfo.Size, 4);
pStream->Write(&buf, StreamInfo.SizeBytes, NULL);
break;
default:
Msg(0, _U("ERR: Don't know how to write size of stream (%i bytes)"), (int)StreamInfo.SizeBytes);
throw NULL;
break;
}
}
//Если файл короче потока, возвращает -1
//Если файл длиннее потока, возвращает 1
//Если размеры одинаковы, то возвращается результат memcmp()
int CStorage::Compare(wxFile* File, wxFileOffset bytes_to_compare)
{
if(!bytes_to_compare) return 0;
//save stream position
wxFileOffset seek_offset = 0, pos;
pStream->Seek(seek_offset, wxFromCurrent, &pos);
wxMemoryBuffer buff_Stream(BUFFER_SIZE), buff_File(BUFFER_SIZE);
wxFileOffset BytesReadF = 0, BytesReadS = 0;
int cmp = 0;
do
{
BytesReadF = File->Read(buff_File.GetWriteBuf(BUFFER_SIZE), BUFFER_SIZE);
pStream->Read(&buff_Stream, BUFFER_SIZE, &BytesReadS);
if( bytes_to_compare > 0 )
{
if( BytesReadF > bytes_to_compare ) BytesReadF = bytes_to_compare;
if( BytesReadS > bytes_to_compare ) BytesReadS = bytes_to_compare;
}
if( BytesReadF < BytesReadS )
{
cmp = -1;
break;
}
if( BytesReadF > BytesReadS )
{
cmp = 1;
break;
}
cmp = memcmp(buff_File.GetData(), buff_Stream.GetData(), BytesReadF);
if( cmp != 0 ) break;
if( bytes_to_compare > 0 )
{
if( bytes_to_compare <= BytesReadF ) break;
bytes_to_compare -= BytesReadF;
}
} while( BUFFER_SIZE == BytesReadF );
//restore stream position
seek_offset = pos;
pStream->Seek(seek_offset, wxFromStart, NULL);
return cmp;
}
int CStorage::Compare(const wxString& FileName, wxFileOffset bytes_to_compare)
{
if( !wxFileExists(FileName) ) return -1;
wxFile File(FileName, wxFile::read);
if (!File.IsOpened() )
{
Msg(0, _U("ERR: Невозможно открыть файл '%s' - %s"), FileName.c_str(), wxSysErrorMsg());
throw NULL;
}
int cmp = Compare(&File, bytes_to_compare);
return cmp;
}
int CStorage::CompareWithString(wxString& str2)
{
//save stream position
wxFileOffset seek_offset = 0, pos;
pStream->Seek(seek_offset, wxFromCurrent, &pos);
wxFileOffset BytesRead;
size_t ind = 0;
int cmp_res = 0;
do
{
wxMemoryBuffer buf;
pStream->Read(&buf, sizeof(char), &BytesRead);
if( BytesRead < sizeof(char) )
{
cmp_res = 1;
break;
}
//skip \r \n in stream
char c = ((char*)buf.GetData())[0];
if( c == '\r' || c == '\n' ) continue;
//skip \r \n in string
while( str2[ind] == '\r' || str2[ind] == '\n' ) ind++;
if( str2[ind] == '\0' )
break;
if( c < str2[ind] )
cmp_res = -1;
else if( c > str2[ind] )
cmp_res = 1;
ind++;
} while( cmp_res == 0 );
//restore stream position
seek_offset = pos;
pStream->Seek(seek_offset, wxFromStart, NULL);
return cmp_res;
}
int CStorage::FullCompare(const wxString& FileName)
{
if( !wxFileExists(FileName) ) return 0;
wxULongLong FileSize = wxFileName::GetSize(FileName);
int cmp = -1;
if ( FileSize != StreamInfo.Size )
{
//Размеры не совпали
Msg(2, _U("File size is: %d - %s"), FileSize.GetValue(), FileName.c_str());
Msg(2, _U("Strm size is: %d"), StreamInfo.Size);
cmp = (FileSize < StreamInfo.Size ? -1 : 1);
}
else
{
Rewind();
cmp = Compare(FileName, 0);
}
return cmp;
}
void CStorage::ParseStream(CMMSObject* Object, const wxString& StreamName, bool ParseWitnNoIDs)
{
wxFile File;
if( !OpenStream(StreamName) ) return;
GetCleanStream();
wxString fname;
fname = wxFileName::CreateTempFileName(_U("tmp_"));
File.Open(fname, wxFile::write_append);
if( !File.IsOpened() )
{
Msg(0, _U("ERR: Невозможно создать временный файл: %s"), wxSysErrorMsg());
throw NULL;
}
wxString FullStreamPath = FullPath()+_U("/")+StreamName;
if( !CopyToFile(&File, 0) )
{
Msg(0, _U("ERR: Не могу извлечь '%s' во временный файл: %s"), FullStreamPath.c_str(), wxSysErrorMsg());
throw NULL;
}
File.Close();
CLexer* Lexer = new CLexer(fname);
try
{
Object->ParseMetadata(*Lexer);
}
catch(...)
{
Msg(0, _U("\tпредыдущая ошибка возникла в потоке %s"), FullStreamPath.c_str());
throw NULL;
}
delete Lexer;
}
void CStorage::AddToExtractedList(wxString& FullFName, void* object)
{
(*ExtractedFiles)[FullFName] = object;
if( object != NULL ) (*ExtractedObjects)[object] = NULL;
}
bool CStorage::ObjectExtracted(void* object)
{
return ExtractedObjects->find(object)!=ExtractedObjects->end();
}
void CStorage::RemoveDirectory(wxString& Path)
{
wxFileName::Rmdir(Path);
}
int CStorage::PruneDirectory(wxString& Path, bool NoEmptyFolders)
{
wxDir dir(Path);
wxString FileName;
int result = 0;
bool cont = dir.GetFirst(&FileName, _U("*.*"));
while(cont)
{
wxString FullFName = Path+_T("/")+FileName;
if( IsIgnoredFile(FullFName) )
{
cont = dir.GetNext(&FileName);
continue;
}
if( wxFileName::DirExists(FullFName) ) // подкаталог
{
int FilesInSubFolder = PruneDirectory(FullFName, NoEmptyFolders);
// в текущем каталоге могут быть только подпапки. А вот в них...
result += FilesInSubFolder;
if( (0 == FilesInSubFolder) && NoEmptyFolders )
{
SetIOPre(_U("DEL"), FullFName);
RemoveDirectory(FullFName);
Msg(1, _U("DEL: %s"), FullFName.c_str());
}
}
else if( ExtractedFiles->find(FullFName)==ExtractedFiles->end() ) // при декомпиляции не было такого файла
{
SetIOPre(_U("DEL"), FullFName);
wxRemoveFile(FullFName);
Msg(1, _U("DEL: %s"), FullFName.c_str());
}
else // был такой файл, сосчитаем его
result++;
cont = dir.GetNext(&FileName);
};
return result;
}
////////////////////////////////////////////////////////////////////////////////////////
wxFileOffset GetStreamSize(IStream* pStream)
{
return pStream->Size();
}
IStorage* OpenStorage(IStorage* pParentStorage, wxString wStorName)
{
IStorage* pStorage;
pParentStorage->OpenStorage(wStorName, NULL, wxFile::read_write , NULL, 0, &pStorage);
//pParentStorage->OpenStorage(wStorName, NULL, STGM_SHARE_DENY_WRITE | STGM_READ, NULL, 0, &pStorage);
return pStorage;
}
IStream* OpenStream(IStorage* pParentStorage, wxString wStreamName)
{
IStream* pStream;
//pParentStorage->OpenStream(wStreamName, NULL, STGM_SHARE_EXCLUSIVE, 0, &pStream);
pParentStorage->OpenStream(wStreamName, NULL, wxFile::read_write, 0, &pStream);
return pStream;
}
bool StringDifferFromFile(wxString& String, wxString& FileName)
{
if( !wxFileExists(FileName) ) return true;
wxFile File(FileName, wxFile::read);
if (!File.IsOpened() )
{
//Msg(0, _U("ERR: Can\t open file '%s' - %s"), FileName.c_str(), strerror(errno));
Msg(0, _U("ERR: Can't open file '%s' - %s"), FileName.c_str(), wxSysErrorMsg());
throw NULL;
}
wxFileOffset FileSize;
long BytesRead;
File.SeekEnd();
FileSize = File.Tell();
File.Seek(0);
bool res = true;
if ( String.Len() == FileSize )
{
wxMemoryBuffer buff;
BytesRead = File.Read(buff.GetWriteBuf(FileSize), FileSize);
res = memcmp(buff.GetData(), String.c_str(), FileSize);
}
return res;
}
bool CStorage::CopyStringToFile(wxString& String, wxString FileName)
{
wxString MsgPrefix;
AddToExtractedList(FileName, NULL);
if( wxFileExists(FileName) )
if( !StringDifferFromFile(String, FileName) )
return true;
else
MsgPrefix = _U("UPD");
else
MsgPrefix = _U("NEW");
SetIOPre(MsgPrefix, FileName);
//Открываем файл как двоичный. О формате конца строк нужно заботиться во
//время формирования текста потока. А иначе потом сравнивать хреново.
wxFile File(FileName.c_str(), wxFile::write);
File.Write(String);
File.Close();
Msg(1, _U("%s: %s"), MsgPrefix.c_str(), FileName.c_str());
return true;
}