mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
** Big Maps Projects code (incl. Multiplayer v1.5 ** ********************************************************** - Merged Big Maps Project code from BMP+MP trunk (Revision: 3340) o Complete SVN Revision history: https://81.169.133.124/source/ja2/branches/Wanne/JA2%201.13%20MP - Before THIS merge, I made a branch of the existing 1.13 source o SVN Branch: https://81.169.133.124/source/ja2/branches/JA2_rev.3336/src - Removed old VS 6.0 and VS 2003 project and solutions files, because compilation is broken long time ago - I will add VS 2010 projects and solution file in the next few days git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@3341 3b4a5df2-a311-0410-b5c6-a8a6f20db521
402 lines
11 KiB
C++
402 lines
11 KiB
C++
#include <cstring>
|
|
|
|
#include "../vfs_types.h"
|
|
|
|
#include "vfs_create_7z_library.h"
|
|
#include "../vfs_file_raii.h"
|
|
#include "../vfs_debug.h"
|
|
|
|
namespace sz
|
|
{
|
|
extern "C"
|
|
{
|
|
#include "7zCrc.h"
|
|
#include "Archive/7z/7zIn.h"
|
|
}
|
|
};
|
|
|
|
#include <vector>
|
|
#include <sstream>
|
|
|
|
/******************************************************************************************/
|
|
/******************************************************************************************/
|
|
/******************************************************************************************/
|
|
namespace szExt
|
|
{
|
|
inline ::size_t WRITEBYTE(std::ostream& out, sz::Byte const& value)
|
|
{
|
|
out.write((char*)&value,sizeof(sz::Byte));
|
|
return 1;
|
|
}
|
|
template<typename T>
|
|
inline ::size_t WRITEALL(std::ostream& out, T const& value)
|
|
{
|
|
out.write((char*)&value,sizeof(T));
|
|
return sizeof(T);
|
|
}
|
|
template<typename T>
|
|
inline ::size_t WRITEBUFFER(std::ostream& out, T* value, ::size_t num_elements)
|
|
{
|
|
out.write((char*)value, num_elements*sizeof(T));
|
|
return num_elements*sizeof(T);
|
|
}
|
|
|
|
/**
|
|
* "compress" numbers by removing heading zero-bytes
|
|
* - add additional byte that represents a bit-vector of bytes within a 64-bit/8-byte number
|
|
* - if the number is smaller than 128, use the extra byte to store the value
|
|
*/
|
|
template<typename T>
|
|
inline ::size_t WRITE(std::ostream& out, T const& value)
|
|
{
|
|
::size_t count = 0;
|
|
sz::Byte data[8];
|
|
sz::Byte firstByte = 0;
|
|
sz::Byte* b = (sz::Byte*)&value;
|
|
::size_t SIZE = sizeof(T);
|
|
b+= SIZE-1;
|
|
vfs::Int32 i;
|
|
for(i = (vfs::Int32)(SIZE-1); i>=0; --i)
|
|
{
|
|
if( (*b & 0xFF) != 0)
|
|
{
|
|
break;
|
|
}
|
|
b--;
|
|
}
|
|
if(i < 0)
|
|
{
|
|
count += WRITEBYTE(out,0);
|
|
return count;
|
|
}
|
|
if(i == 0)
|
|
{
|
|
if(*b >= 0x80)
|
|
{
|
|
count += WRITEBYTE(out,0x80);
|
|
}
|
|
count += WRITEBYTE(out,*b);
|
|
return count;
|
|
}
|
|
vfs::Int32 num = 0;
|
|
for(;i >= 0; --i)
|
|
{
|
|
firstByte |= 1 << (8 - i - 1);
|
|
data[i] = *b--;
|
|
num++;
|
|
}
|
|
count += WRITEBYTE(out,firstByte);
|
|
count += WRITEBUFFER(out,data,num);
|
|
return count;
|
|
}
|
|
}
|
|
/******************************************************************************************/
|
|
/******************************************************************************************/
|
|
/******************************************************************************************/
|
|
|
|
vfs::CCreateUncompressed7zLibrary::CCreateUncompressed7zLibrary()
|
|
: m_pLibFile(NULL)
|
|
{
|
|
sz::CrcGenerateTable();
|
|
}
|
|
|
|
vfs::CCreateUncompressed7zLibrary::~CCreateUncompressed7zLibrary()
|
|
{
|
|
m_pLibFile = NULL;
|
|
|
|
m_lFileInfo.clear();
|
|
m_mapDirInfo.clear();
|
|
}
|
|
|
|
bool vfs::CCreateUncompressed7zLibrary::addFile(vfs::tReadableFile* pFile)
|
|
{
|
|
if(!pFile)
|
|
{
|
|
// at least nothing bad happened
|
|
return true;
|
|
}
|
|
try
|
|
{
|
|
vfs::COpenReadFile infile(pFile);
|
|
}
|
|
catch(CBasicException &ex)
|
|
{
|
|
std::wstringstream wss;
|
|
wss << L"Could not open File \"" << pFile->getPath()() << L"\"";
|
|
RETHROWEXCEPTION(wss.str().c_str(),&ex);
|
|
}
|
|
SFileInfo fi;
|
|
vfs::Path filename = pFile->getPath();
|
|
fi.name = filename.c_wcs();
|
|
fi.size = pFile->getSize();
|
|
if(m_lFileInfo.empty())
|
|
{
|
|
fi.offset = 0;
|
|
}
|
|
else
|
|
{
|
|
SFileInfo const& fic = m_lFileInfo.back();
|
|
fi.offset = fic.offset + fic.size;
|
|
}
|
|
|
|
typedef std::vector<vfs::Byte> tByteVector;
|
|
tByteVector data( (tByteVector::size_type)fi.size );
|
|
THROWIFFALSE(fi.size == pFile->read(&data[0], (vfs::size_t)fi.size), L"");
|
|
fi.CRC = sz::CrcCalc(&data[0],(::size_t)fi.size);
|
|
m_ssFileStream.write(&data[0],(std::streamsize)fi.size);
|
|
|
|
m_lFileInfo.push_back(fi);
|
|
|
|
vfs::Path path,dummy;
|
|
filename.splitLast(path,dummy);
|
|
if(!path.empty())
|
|
{
|
|
tDirInfo::iterator it_find = m_mapDirInfo.find(path.c_wcs());
|
|
if(it_find == m_mapDirInfo.end())
|
|
{
|
|
SFileInfo dir;
|
|
dir.name = path.c_wcs();
|
|
dir.offset = 0;
|
|
dir.size = 0;
|
|
dir.time_creation = 0;
|
|
dir.time_last_access = 0;
|
|
dir.time_write = 0;
|
|
m_mapDirInfo.insert(std::make_pair(dir.name,dir));
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool vfs::CCreateUncompressed7zLibrary::writeLibrary(vfs::Path const& sLibName)
|
|
{
|
|
vfs::COpenWriteFile outfile(sLibName,true);
|
|
return writeLibrary(&outfile.file());
|
|
}
|
|
bool vfs::CCreateUncompressed7zLibrary::writeLibrary(vfs::tWritableFile* pFile)
|
|
{
|
|
if(!pFile)
|
|
{
|
|
return false;
|
|
}
|
|
if(m_lFileInfo.empty())
|
|
{
|
|
return false;
|
|
}
|
|
m_pLibFile = pFile;
|
|
if(!m_pLibFile->isOpenWrite() && !m_pLibFile->openWrite(true,true))
|
|
{
|
|
return false;
|
|
}
|
|
//
|
|
writeNextHeader(m_ssInfoStream);
|
|
//
|
|
std::stringstream ssSigHeader;
|
|
writeSignatureHeader(ssSigHeader);
|
|
//
|
|
m_pLibFile->write(ssSigHeader.str().c_str() , (vfs::size_t)ssSigHeader.str().length());
|
|
//
|
|
m_pLibFile->write(m_ssFileStream.str().c_str() , (vfs::size_t)m_ssFileStream.str().length());
|
|
//
|
|
m_pLibFile->write(m_ssInfoStream.str().c_str() , (vfs::size_t)m_ssInfoStream.str().length());
|
|
|
|
return true;
|
|
}
|
|
|
|
/**************************************************************************************/
|
|
|
|
bool vfs::CCreateUncompressed7zLibrary::writeSignatureHeader(std::ostream& out)
|
|
{
|
|
::size_t count=0;
|
|
|
|
// #define k7zSignatureSize -> not in namespace sz
|
|
count += szExt::WRITEBUFFER(out, sz::k7zSignature, k7zSignatureSize);
|
|
|
|
sz::Byte Major = 0, Minor = 2;
|
|
count += szExt::WRITEALL(out, (sz::Byte)Major );
|
|
count += szExt::WRITEALL(out, (sz::Byte)Minor );
|
|
|
|
sz::UInt32 StartHeaderCRC, NextHeaderCRC;
|
|
|
|
SFileInfo const& fi = m_lFileInfo.back();
|
|
sz::UInt64 NextHeaderOffset = fi.offset + fi.size;
|
|
sz::UInt64 NextHeaderSize = m_ssInfoStream.str().length()*sizeof(char);
|
|
NextHeaderCRC = sz::CrcCalc(m_ssInfoStream.str().c_str(),(::size_t)NextHeaderSize);
|
|
|
|
std::stringstream sstemp;
|
|
count += szExt::WRITEALL(sstemp, (sz::UInt64)NextHeaderOffset );
|
|
count += szExt::WRITEALL(sstemp, (sz::UInt64)NextHeaderSize );
|
|
count += szExt::WRITEALL(sstemp, (sz::UInt32)NextHeaderCRC );
|
|
StartHeaderCRC = sz::CrcCalc(sstemp.str().c_str(), sstemp.str().length()*sizeof(char));
|
|
|
|
count += szExt::WRITEALL(out, (sz::UInt32)StartHeaderCRC );
|
|
out << sstemp.str();
|
|
|
|
return true;
|
|
}
|
|
bool vfs::CCreateUncompressed7zLibrary::writeNextHeader(std::ostream& out)
|
|
{
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdHeader);
|
|
|
|
// this->WriteArchiveProperties(out);
|
|
|
|
// this->WriteAdditionalStreamsInfo(out)
|
|
|
|
//
|
|
this->writeMainStreamsInfo(out);
|
|
|
|
//
|
|
this->writeFilesInfo(out);
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool vfs::CCreateUncompressed7zLibrary::writeMainStreamsInfo(std::ostream& out)
|
|
{
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdMainStreamsInfo );
|
|
|
|
this->writePackInfo(out);
|
|
|
|
this->writeUnPackInfo(out);
|
|
|
|
this->writeSubStreamsInfo(out);
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool vfs::CCreateUncompressed7zLibrary::writePackInfo(std::ostream& out)
|
|
{
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdPackInfo );
|
|
szExt::WRITE(out, (sz::UInt64)0 ); // data offset
|
|
szExt::WRITE(out, (sz::UInt32)m_lFileInfo.size() );
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdSize );
|
|
std::list<SFileInfo>::iterator it = m_lFileInfo.begin();
|
|
for(;it != m_lFileInfo.end(); ++it)
|
|
{
|
|
szExt::WRITE(out, (sz::UInt64)it->size );
|
|
}
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd );
|
|
return true;
|
|
}
|
|
bool vfs::CCreateUncompressed7zLibrary::writeUnPackInfo(std::ostream& out)
|
|
{
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdUnpackInfo );
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdFolder );
|
|
szExt::WRITE(out, (sz::UInt64)m_lFileInfo.size() );
|
|
szExt::WRITE(out, (sz::Byte)0 ); // External
|
|
|
|
std::list<SFileInfo>::iterator fit = m_lFileInfo.begin();
|
|
for(;fit != m_lFileInfo.end(); ++fit)
|
|
{
|
|
this->writeFolder(out);
|
|
}
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdCodersUnpackSize );
|
|
fit = m_lFileInfo.begin();
|
|
for(;fit != m_lFileInfo.end(); ++fit)
|
|
{
|
|
szExt::WRITE(out, (sz::UInt64)fit->size );
|
|
}
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd );
|
|
|
|
return true;
|
|
}
|
|
bool vfs::CCreateUncompressed7zLibrary::writeSubStreamsInfo(std::ostream& out)
|
|
{
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdSubStreamsInfo );
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdCRC );
|
|
|
|
szExt::WRITE(out, (sz::Byte)1 ); // early out - all CRCs defined
|
|
std::list<SFileInfo>::iterator fit = m_lFileInfo.begin();
|
|
for(;fit != m_lFileInfo.end(); ++fit )
|
|
{
|
|
szExt::WRITEALL(out, (sz::UInt32)fit->CRC);
|
|
}
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd );
|
|
return true;
|
|
}
|
|
|
|
bool vfs::CCreateUncompressed7zLibrary::writeFolder(std::ostream& out)
|
|
{
|
|
szExt::WRITE(out, (sz::UInt32)1 ); // NumCoders
|
|
|
|
szExt::WRITE(out, (sz::Byte)1 ); // MainByte
|
|
|
|
szExt::WRITE(out, (sz::Byte)0 ); // Methods
|
|
|
|
return true;
|
|
}
|
|
bool vfs::CCreateUncompressed7zLibrary::writeFilesInfo(std::ostream& out)
|
|
{
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdFilesInfo );
|
|
|
|
vfs::UInt64 num_files = (m_lFileInfo.size()+m_mapDirInfo.size());
|
|
szExt::WRITE(out, (sz::UInt64)num_files );
|
|
|
|
// empty stream -> pack info in bit-vector
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdEmptyStream );
|
|
sz::UInt64 num_empty64 = num_files/8 + (num_files%8 == 0 ? 0 : 1);
|
|
::size_t num_empty = (::size_t)num_empty64;
|
|
THROWIFFALSE(num_empty == num_empty64, L"WTF");
|
|
|
|
sz::Byte *empty_vector = new sz::Byte[num_empty];
|
|
memset(empty_vector,0,(::size_t)num_empty);
|
|
for(::size_t e=m_lFileInfo.size(); e < num_files; ++e)
|
|
{
|
|
::size_t index = e / 8;
|
|
empty_vector[index] |= 1 << (7 - e%8);
|
|
}
|
|
szExt::WRITE(out, (sz::UInt64)num_empty ); // size
|
|
szExt::WRITEBUFFER(out, empty_vector, (::size_t)num_empty);
|
|
delete[] empty_vector;
|
|
|
|
// names
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdName );
|
|
::size_t count = 0;
|
|
std::stringstream name_stream;
|
|
count += szExt::WRITE(name_stream, (sz::Byte)0 ); // switch
|
|
std::list<SFileInfo>::iterator fit = m_lFileInfo.begin();
|
|
for(;fit != m_lFileInfo.end(); ++fit)
|
|
{
|
|
count += (::size_t)this->writeFileName(name_stream, fit->name);
|
|
}
|
|
std::map<utf8string::str_t,SFileInfo>::iterator dit = m_mapDirInfo.begin();
|
|
for(;dit != m_mapDirInfo.end(); ++dit)
|
|
{
|
|
count += (::size_t)this->writeFileName(name_stream, dit->second.name);
|
|
}
|
|
szExt::WRITE(out, (sz::UInt64)count ); // size
|
|
szExt::WRITEBUFFER(out, name_stream.str().c_str(), name_stream.str().length() );
|
|
|
|
//szExt::WRITE(out, (sz::Byte)sz::k7zIdEmptyFile );
|
|
//szExt::WRITE(out, (sz::Byte)sz::k7zIdCTime ); // create
|
|
//szExt::WRITE(out, (sz::Byte)sz::k7zIdATime ); // last access
|
|
//szExt::WRITE(out, (sz::Byte)sz::k7zIdMTime ); // write
|
|
|
|
//szExt::WRITE(out, (sz::Byte)sz::k7zIdWinAttributes );
|
|
|
|
szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd );
|
|
|
|
return true;
|
|
}
|
|
|
|
vfs::size_t vfs::CCreateUncompressed7zLibrary::writeFileName(std::ostream& out, utf8string const& filename)
|
|
{
|
|
::size_t count = 0;
|
|
THROWIFFALSE(filename.length(), L"zero length name");
|
|
count += szExt::WRITEBUFFER(out, filename.c_str(), filename.length());
|
|
count += szExt::WRITE(out, (sz::Byte)0);
|
|
count += szExt::WRITE(out, (sz::Byte)0);
|
|
return (vfs::size_t)count;
|
|
}
|
|
|