Files
source/VFS/Location/vfs_7z_library.cpp
T
Wanne 47db604b50 *** Merged Code from Multiplayer Branch Revision 2960 ***
- Virtual File System (VFS) by birdflu. This is needed for Multiplayer and is also used for Single Player. Very neat system :-)
- Multiplayer Version 1.1 + some additional features and bugfixes
* INFO: If you compile a new EXE and want to test, be sure to also use the latest SVN GameDir files in your JA2 install directory *




git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@2961 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2009-06-04 21:01:45 +00:00

216 lines
5.2 KiB
C++

#include "vfs_7z_library.h"
#include "vfs_lib_dir.h"
#include "../File/vfs_lib_file.h"
#include "../vfs_file_raii.h"
namespace sz
{
extern "C"
{
#include "7zCrc.h"
#include "Archive/7z/7zAlloc.h"
#include "Archive/7z/7zExtract.h"
#include "Archive/7z/7zIn.h"
}
}
/********************************************************************************************/
/*** my 7z extensions ***/
/********************************************************************************************/
namespace szExt
{
typedef struct CSzVfsFile
{
vfs::tReadableFile* file;
} CSzVfsFile;
typedef struct CVfsFileInStream
{
sz::ISeekInStream s;
CSzVfsFile file;
} CVfsFileInStream;
static sz::SRes VfsFileInStream_Read(void *pp, void *buf, size_t *size)
{
CVfsFileInStream *p = (CVfsFileInStream *)pp;
vfs::UInt32 to_read = *size;
vfs::UInt32 has_read = 0;
sz::SRes res;
if(p->file.file->Read((vfs::Byte*)buf,to_read, has_read))
{
res = SZ_OK;
}
else
{
res = SZ_ERROR_READ;
}
*size = has_read;
return res;
}
static sz::SRes VfsFileInStream_Seek(void *pp, sz::Int64 *pos, sz::ESzSeek origin)
{
CVfsFileInStream *p = (CVfsFileInStream *)pp;
vfs::IBaseFile::ESeekDir eSD;
switch (origin)
{
case sz::SZ_SEEK_SET:
eSD = vfs::IBaseFile::SD_BEGIN;
break;
case sz::SZ_SEEK_CUR:
eSD = vfs::IBaseFile::SD_CURRENT;
break;
case sz::SZ_SEEK_END:
eSD = vfs::IBaseFile::SD_END;
break;
default:
return ERROR_INVALID_PARAMETER;
}
vfs::Int32 _pos = (vfs::Int32)(*pos); // only 32 bit
sz::SRes res;
if(p->file.file->SetReadLocation(_pos,eSD))
{
*pos = p->file.file->GetReadLocation();
res = SZ_OK;
}
else
{
res = SZ_ERROR_READ;
}
return res;
}
void VfsFileInStream_CreateVTable(CVfsFileInStream *p)
{
p->s.Read = VfsFileInStream_Read;
p->s.Seek = VfsFileInStream_Seek;
}
}; // end namespace szExt
/********************************************************************************************/
/********************************************************************************************/
/********************************************************************************************/
#define k_Copy 0
sz::UInt64 GetSum(const sz::UInt64 *values, sz::UInt32 index)
{
sz::UInt64 sum = 0;
sz::UInt32 i;
for (i = 0; i < index; i++)
{
sum += values[i];
}
return sum;
}
bool vfs::CUncompressed7zLibrary::Init()
{
if(!m_pLibraryFile)
{
return false;
}
szExt::CVfsFileInStream archiveStream;
sz::CLookToRead lookStream;
sz::CSzArEx db;
sz::SRes res;
sz::ISzAlloc allocImp;
sz::ISzAlloc allocTempImp;
if(!m_pLibraryFile->OpenRead())
{
return false;
}
archiveStream.file.file = m_pLibraryFile;
szExt::VfsFileInStream_CreateVTable(&archiveStream);
sz::LookToRead_CreateVTable(&lookStream, False);
lookStream.realStream = &archiveStream.s;
sz::LookToRead_Init(&lookStream);
allocImp.Alloc = sz::SzAlloc;
allocImp.Free = sz::SzFree;
allocTempImp.Alloc = sz::SzAllocTemp;
allocTempImp.Free = sz::SzFreeTemp;
sz::CrcGenerateTable();
sz::SzArEx_Init(&db);
if( SZ_OK != (res = sz::SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp)) )
{
std::stringstream wss;
wss << "Could not open 7z archive [" << m_pLibraryFile->GetFullPath()().utf8() << "]";
THROWEXCEPTION(wss.str().c_str());
}
vfs::IDirectory<ILibrary::tWriteType>* pLD = NULL;
vfs::Path oDir, oFile;
vfs::Path oDirPath;
for(vfs::UInt32 i = 0; i < db.db.NumFiles; i++)
{
sz::CSzFileItem *f = db.db.Files + i;
if (f->IsDir)
{
continue;
}
vfs::Path sPath(f->Name);
sPath.SplitLast(oDir,oFile);
oDirPath = m_sMountPoint;
if(!oDir.empty())
{
oDirPath += oDir;
}
// determine offset and size
sz::UInt32 folderIndex = db.FileIndexToFolderIndexMap[i];
sz::CSzFolder *folder = db.db.Folders + folderIndex;
sz::UInt64 unpackSizeSpec = sz::SzFolder_GetUnpackSize(folder);
size_t unpackSize = (size_t)unpackSizeSpec;
sz::UInt64 startOffset = sz::SzArEx_GetFolderStreamPos(&db, folderIndex, 0);
const sz::UInt64 *packSizes = db.db.PackSizes + db.FolderStartPackStreamIndex[folderIndex];
//CSzCoderInfo *coder = &folder->Coders[0];
//if (coder->MethodID == k_Copy)
//{
// UInt32 si = 0;
// UInt64 offset;
// UInt64 inSize;
// offset = GetSum(packSizes, si);
// inSize = packSizes[si];
//}
// get or create according directory object
tDirCatalogue::iterator it = m_catDirs.find(oDirPath);
if(it != m_catDirs.end())
{
pLD = it->second;
}
else
{
pLD = new CLibDirectory(oDir,oDirPath);
m_catDirs.insert(std::make_pair(oDirPath,pLD));
}
// create file
vfs::CLibFile *pFile = vfs::CLibFile::Create(oFile,pLD,this,_allocator);
// add file to directory
if(!pLD->AddFile(pFile))
{
// something is wrong
m_pLibraryFile->Close();
return false;
}
// link file data struct to file object
m_mapLibData.insert(std::pair<tFileType*,sFileData>(pFile,sFileData(unpackSize, (UInt32)startOffset)));
}
return true;
}