- Support for Zip Filesystem. It is now possible to zip the entire Res folder ("store" method preferred, zip so that the root of the zip has ai, player, etc...) in one single file for read only. Write access is done in another folder (hardcoded to be User/ for now, can be updated depending on platforms, etc...
-- zipFS has several limitations... --- in a general way, seekg doesn't work... so getting a file's size needs to be done through JFileSystem. --- getLine on files open with zipFS doesn't work so great. Not sure if it is a normal issue because files are open in binary or not... JFileSystem therefore offers a "readIntoString" function that needs to be used instead of the usual "getline" technique. However getLine can then be used on a stream connected to the string. -- tested on Windows and PSP, I also made sure android still works, but haven't tested zip support on Android. -- I tried to maintain backwards compatibility, but this might break on some platforms, if I broke some platforms and you can't find a way to fix them, please contact me and we'll figure something out -- This removes wagic::ifstream. I didn't reimplement the securities that were involved in this, apologies for that. Might be useful to reimplement such securities in JFileSystem -- I haven't tested options/profiles in a deep way, it is possible I broke that.
This commit is contained in:
651
JGE/src/zipFS/zfsystem.cpp
Normal file
651
JGE/src/zipFS/zfsystem.cpp
Normal file
@@ -0,0 +1,651 @@
|
||||
//Important: This file has been modified in order to be integrated in to JGE++
|
||||
//
|
||||
|
||||
// zfsystem.cpp: implementation of the zip file system classes.
|
||||
//
|
||||
// Copyright (C) 2004 Tanguy Fautré.
|
||||
// For conditions of distribution and use,
|
||||
// see copyright notice in zfsystem.h
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "zfsystem.h"
|
||||
|
||||
#include "fileio.h" // I/O facilities
|
||||
|
||||
|
||||
#if defined (WIN32)
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace zip_file_system {
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Static variables initialization
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
filesystem * izfstream::pDefaultFS = NULL;
|
||||
string filesystem::CurrentZipName = "";
|
||||
ifstream filesystem::CurrentZipFile;
|
||||
filesystem * filesystem::pCurrentFS = NULL;
|
||||
|
||||
static const int STORED = 0;
|
||||
static const int DEFLATED = 8;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
filesystem::filesystem(const char * BasePath, const char * FileExt, bool DefaultFS)
|
||||
: m_BasePath(BasePath), m_FileExt(FileExt)
|
||||
{
|
||||
using io_facilities::search_iterator;
|
||||
|
||||
// Init m_BasePath and be sure the base path finish with a '/' or a '\'
|
||||
if (! m_BasePath.empty()) {
|
||||
string::iterator c = --(m_BasePath.end());
|
||||
if ((*c != '/') && (*c != '\\'))
|
||||
m_BasePath += '/';
|
||||
}
|
||||
|
||||
// Search all *.zip files (or whatever the ZipExt specify as the file extension)
|
||||
vector<string> ZipFiles;
|
||||
|
||||
for (search_iterator ZSrch = (m_BasePath + "*." + m_FileExt).c_str(); ZSrch != ZSrch.end(); ++ZSrch)
|
||||
ZipFiles.push_back(ZSrch.Name());
|
||||
|
||||
// Open each zip files that have been found, in alphabetic order
|
||||
sort(ZipFiles.begin(), ZipFiles.end());
|
||||
|
||||
for (vector<string>::const_iterator ZipIt = ZipFiles.begin(); ZipIt != ZipFiles.end(); ++ZipIt)
|
||||
InsertZip(ZipIt->c_str(), ZipIt - ZipFiles.begin());
|
||||
|
||||
// Should we make this the default File System for ifile?
|
||||
if (DefaultFS)
|
||||
MakeDefault();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// File System Member Functions
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void filesystem::Open(izfstream & File, const char * Filename)
|
||||
{
|
||||
// Close the file if it was opened;
|
||||
File.close();
|
||||
File.setFS(this);
|
||||
|
||||
// Generate the path and see if the file is zipped or not
|
||||
string FullPath = m_BasePath + Filename;
|
||||
|
||||
// File is not zipped
|
||||
if (FileNotZipped(FullPath.c_str())) {
|
||||
|
||||
// Link the izfile object with an opened filebuf
|
||||
filebuf * FileBuf = new filebuf;
|
||||
FileBuf->open(FullPath.c_str(), ios::binary | ios::in);
|
||||
|
||||
if (FileBuf->is_open()) {
|
||||
delete File.rdbuf(FileBuf);
|
||||
File.clear(ios::goodbit);
|
||||
File.m_FilePath = Filename;
|
||||
File.m_FullFilePath = FullPath;
|
||||
File.m_Zipped = false;
|
||||
}
|
||||
|
||||
// File is maybe zipped
|
||||
} else {
|
||||
|
||||
file_info FileInfo;
|
||||
string ZipPath;
|
||||
|
||||
// Check whether the file is zipped, whether the file is a directory and try to open.
|
||||
if (FindFile(Filename, &FileInfo) && (! FileInfo.m_Directory) && (! ((ZipPath = FindZip(FileInfo.m_PackID)).empty()))) {
|
||||
|
||||
// Get the position of the compressed data
|
||||
if (CurrentZipName.size())
|
||||
{
|
||||
if ((pCurrentFS!= this) || (CurrentZipName.compare(ZipPath) != 0))
|
||||
{
|
||||
CurrentZipFile.close();
|
||||
CurrentZipName = "";
|
||||
pCurrentFS = NULL;
|
||||
}
|
||||
}
|
||||
if (!CurrentZipName.size())
|
||||
{
|
||||
CurrentZipName = ZipPath;
|
||||
string zipName = m_BasePath + CurrentZipName;
|
||||
CurrentZipFile.open(zipName.c_str(), ios::binary);
|
||||
pCurrentFS = this;
|
||||
}
|
||||
|
||||
if (!CurrentZipFile) {
|
||||
CurrentZipName = "";
|
||||
pCurrentFS = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
streamoff DataPos = SkipLFHdr(CurrentZipFile, streamoff(FileInfo.m_Offset));
|
||||
|
||||
if (DataPos != streamoff(-1)) {
|
||||
string zipName = m_BasePath + CurrentZipName;
|
||||
// Open the file at the right position
|
||||
((izstream &) File).open(
|
||||
zipName.c_str(),
|
||||
streamoff(DataPos),
|
||||
streamoff(FileInfo.m_CompSize),
|
||||
FileInfo.m_CompMethod
|
||||
);
|
||||
|
||||
if (File) {
|
||||
File.m_FilePath = Filename;
|
||||
File.m_FullFilePath = FullPath;
|
||||
File.m_Zipped = true;
|
||||
File.m_UncompSize = FileInfo.m_Size;
|
||||
File.m_CompSize = FileInfo.m_CompSize;
|
||||
File.m_Offset = FileInfo.m_Offset;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool filesystem::DirExists(const std::string & folderName)
|
||||
{
|
||||
|
||||
//check real folder
|
||||
string FullPath = m_BasePath + folderName;
|
||||
|
||||
#if defined (WIN32)
|
||||
struct _stat statBuffer;
|
||||
if ((_stat(FullPath.c_str(), &statBuffer) >= 0 && // make sure it exists
|
||||
statBuffer.st_mode & S_IFDIR)) // and it's not a file
|
||||
return true;
|
||||
#else
|
||||
struct stat st;
|
||||
if (stat(FullPath.c_str(), &st) == 0)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
//Check in zip
|
||||
file_info FileInfo;
|
||||
|
||||
// Check whether the file is zipped, whether the file is a directory and try to open.
|
||||
if (FindFile(folderName.c_str(), &FileInfo) && (FileInfo.m_Directory))
|
||||
return true;
|
||||
|
||||
//Neither in real folder nor in zip
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: this doesn't scan the folders outside of the zip...should we add that here ?
|
||||
std::vector<std::string>& filesystem::scanfolder(const std::string& folderName, std::vector<std::string>& results)
|
||||
{
|
||||
filemap_const_iterator folderPos = m_Files.find(folderName);
|
||||
|
||||
if (folderPos == m_Files.end())
|
||||
return results;
|
||||
|
||||
filemap_const_iterator It = folderPos;
|
||||
|
||||
string folderNameLC = folderName;
|
||||
std::transform(folderNameLC.begin(), folderNameLC.end(), folderNameLC.begin(), ::tolower);
|
||||
size_t length = folderNameLC.length();
|
||||
|
||||
while(++It != m_Files.end())
|
||||
{
|
||||
string currentFile = (* It).first;
|
||||
string currentFileLC = currentFile;
|
||||
std::transform(currentFileLC.begin(), currentFileLC.end(), currentFileLC.begin(), ::tolower);
|
||||
if (currentFileLC.find(folderNameLC) == 0)
|
||||
{
|
||||
string relativePath = currentFile.substr(length);
|
||||
size_t pos = relativePath.find_first_of("/\\");
|
||||
//Only add direct children, no recursive browse
|
||||
if (pos == string::npos || pos == (relativePath.length() - 1))
|
||||
results.push_back(relativePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
//We know other files will not belong to that folder because of the order of the map
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// File System Protected Member Functions
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool filesystem::FileNotZipped(const char * FilePath) const
|
||||
{
|
||||
//return io_facilities::search_iterator(FilePath);
|
||||
// follow new search_iterator implementation
|
||||
std::ifstream File(FilePath);
|
||||
|
||||
if (! File)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool filesystem::FindFile(const char * Filename, file_info * FileInfo) const
|
||||
{
|
||||
filemap_const_iterator It = m_Files.find(Filename);
|
||||
|
||||
if (It == m_Files.end())
|
||||
return false; // File not found
|
||||
|
||||
* FileInfo = (* It).second;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const string & filesystem::FindZip(size_t PackID) const
|
||||
{
|
||||
static const string EmptyString;
|
||||
|
||||
zipmap_const_iterator It = m_Zips.find(PackID);
|
||||
|
||||
if (It == m_Zips.end())
|
||||
return EmptyString; // PackID not valid
|
||||
|
||||
return (* It).second.m_Filename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void filesystem::InsertZip(const char * Filename, const size_t PackID)
|
||||
{
|
||||
zipfile_info ZipInfo;
|
||||
|
||||
// Get full path to the zip file and prepare ZipInfo
|
||||
ZipInfo.m_Filename = Filename;
|
||||
string ZipPath = m_BasePath + Filename;
|
||||
|
||||
// Open zip
|
||||
ifstream File(ZipPath.c_str(), ios::binary);
|
||||
|
||||
if (! File)
|
||||
return;
|
||||
|
||||
// Find the start of the central directory
|
||||
if (! File.seekg(CentralDir(File))) return;
|
||||
|
||||
// Check every headers within the zip file
|
||||
file_header FileHdr;
|
||||
|
||||
while ((NextHeader(File) == FILE) && (FileHdr.ReadHeader(File))) {
|
||||
|
||||
// Include files into Files map
|
||||
const char * Name = &(* FileHdr.m_Filename.begin());
|
||||
const unsigned short i = FileHdr.m_FilenameSize - 1;
|
||||
if (FileHdr.m_FilenameSize != 0) {
|
||||
|
||||
m_Files[Name] = file_info(
|
||||
PackID, // Package ID
|
||||
FileHdr.m_RelOffset, // "Local File" header offset position
|
||||
FileHdr.m_UncompSize, // File Size
|
||||
FileHdr.m_CompSize, // Compressed File Size
|
||||
FileHdr.m_CompMethod, // Compression Method;
|
||||
((Name[i] == '/') || (Name[i] == '\\')) // Is a directory?
|
||||
);
|
||||
|
||||
++(ZipInfo.m_NbEntries);
|
||||
ZipInfo.m_FilesSize += FileHdr.m_UncompSize;
|
||||
ZipInfo.m_FilesCompSize += FileHdr.m_CompSize;
|
||||
}
|
||||
}
|
||||
|
||||
File.close();
|
||||
|
||||
// Add zip file to Zips data base (only if not empty)
|
||||
if (ZipInfo.m_NbEntries != 0)
|
||||
m_Zips[PackID] = ZipInfo;
|
||||
}
|
||||
|
||||
|
||||
bool filesystem::PreloadZip(const char * Filename, map<string, file_info>& target)
|
||||
{
|
||||
zipfile_info ZipInfo;
|
||||
|
||||
// Open zip
|
||||
izfstream File;
|
||||
File.open(Filename, this);
|
||||
|
||||
if (! File)
|
||||
return false;
|
||||
|
||||
// Find the start of the central directory
|
||||
if (File.Zipped())
|
||||
{
|
||||
streamoff realBeginOfFile = SkipLFHdr(CurrentZipFile, File.getOffset());
|
||||
if (! CurrentZipFile.seekg(CentralDirZipped(CurrentZipFile, realBeginOfFile, File.getCompSize())))
|
||||
return false;
|
||||
|
||||
// Check every headers within the zip file
|
||||
file_header FileHdr;
|
||||
|
||||
while ((NextHeader(CurrentZipFile) == FILE) && (FileHdr.ReadHeader(CurrentZipFile))) {
|
||||
|
||||
// Include files into Files map
|
||||
const char * Name = &(* FileHdr.m_Filename.begin());
|
||||
const unsigned short i = FileHdr.m_FilenameSize - 1;
|
||||
if (FileHdr.m_FilenameSize != 0) {
|
||||
|
||||
// The zip in zip method only supports stored Zips because of JFileSystem limitations
|
||||
if ((FileHdr.m_UncompSize != FileHdr.m_CompSize) || FileHdr.m_CompMethod != STORED)
|
||||
continue;
|
||||
|
||||
target[Name] = file_info(
|
||||
1, // Package ID
|
||||
realBeginOfFile + FileHdr.m_RelOffset, // "Local File" header offset position
|
||||
FileHdr.m_UncompSize, // File Size
|
||||
FileHdr.m_CompSize, // Compressed File Size
|
||||
FileHdr.m_CompMethod, // Compression Method;
|
||||
((Name[i] == '/') || (Name[i] == '\\')) // Is a directory?
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
File.close();
|
||||
return (target.size() ? true : false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! File.seekg(CentralDir(File)))
|
||||
return false;
|
||||
|
||||
// Check every headers within the zip file
|
||||
file_header FileHdr;
|
||||
|
||||
while ((NextHeader(File) == FILE) && (FileHdr.ReadHeader(File))) {
|
||||
|
||||
// Include files into Files map
|
||||
const char * Name = &(* FileHdr.m_Filename.begin());
|
||||
const unsigned short i = FileHdr.m_FilenameSize - 1;
|
||||
if (FileHdr.m_FilenameSize != 0) {
|
||||
|
||||
target[Name] = file_info(
|
||||
1, // Package ID
|
||||
FileHdr.m_RelOffset, // "Local File" header offset position
|
||||
FileHdr.m_UncompSize, // File Size
|
||||
FileHdr.m_CompSize, // Compressed File Size
|
||||
FileHdr.m_CompMethod, // Compression Method;
|
||||
((Name[i] == '/') || (Name[i] == '\\')) // Is a directory?
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
File.close();
|
||||
return (target.size() ? true : false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// File System Friend Functions
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
ostream & operator << (ostream & Out, const filesystem & FS)
|
||||
{
|
||||
size_t NbFiles = 0;
|
||||
filesystem::zipfile_info AllZipsInfo;
|
||||
|
||||
for (filesystem::zipmap_const_iterator It = FS.m_Zips.begin(); It != FS.m_Zips.end(); ++It) {
|
||||
|
||||
const filesystem::zipfile_info & ZInfo = (* It).second;
|
||||
|
||||
// Print zip filename
|
||||
Out << setiosflags(ios::left) << setw(32) << "-> \"" + ZInfo.m_Filename + "\"" << resetiosflags(ios::left);
|
||||
// Print number of entries found in this zip file
|
||||
Out << " " << setw(5) << ZInfo.m_NbEntries << " files";
|
||||
// Print the uncompressed size of all included files
|
||||
Out << " " << setw(7) << ZInfo.m_FilesSize / 1024 << " KB";
|
||||
// Print the compressed size of all these files
|
||||
Out << " " << setw(7) << ZInfo.m_FilesCompSize / 1024 << " KB packed" << endl;
|
||||
|
||||
++NbFiles;
|
||||
AllZipsInfo.m_NbEntries += ZInfo.m_NbEntries;
|
||||
AllZipsInfo.m_FilesSize += ZInfo.m_FilesSize;
|
||||
AllZipsInfo.m_FilesCompSize += ZInfo.m_FilesCompSize;
|
||||
}
|
||||
|
||||
// Print the general info
|
||||
Out << "\nTotal: ";
|
||||
Out << NbFiles << " packs ";
|
||||
Out << AllZipsInfo.m_NbEntries << " files ";
|
||||
Out << float(AllZipsInfo.m_FilesSize) / (1024 * 1024) << " MB ";
|
||||
Out << float(AllZipsInfo.m_FilesCompSize) / (1024 * 1024) << " MB packed." << endl;
|
||||
|
||||
return Out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// "Less Than" Comparaison lt_path_str Member Functions
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool filesystem::lt_path::operator () (const string & s1, const string & s2) const
|
||||
{
|
||||
const char * A = s1.c_str();
|
||||
const char * B = s2.c_str();
|
||||
|
||||
for (size_t i = 0; ; ++i) {
|
||||
|
||||
if ((A[i] == '\0') && (B[i] == '\0'))
|
||||
return false;
|
||||
|
||||
// case insensitive and '/' is the same as '\'
|
||||
if (! (
|
||||
(A[i] == B[i] + ('a' - 'A')) ||
|
||||
(A[i] == B[i] - ('a' - 'A')) ||
|
||||
(A[i] == B[i]) ||
|
||||
((A[i] == '\\') && (B[i] == '/')) ||
|
||||
((A[i] == '/') && (B[i] == '\\'))
|
||||
)) {
|
||||
|
||||
if ((A[i] == '\0') || (A[i] < B[i]))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Zip Header Classes Related Member Functions
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
streamoff filesystem::CentralDirZipped(std::istream & File, std::streamoff begin, std::size_t size) const
|
||||
{
|
||||
using io_facilities::readvar;
|
||||
|
||||
std::streamoff eof = begin + size;
|
||||
|
||||
// Look for the "end of central dir" header. Start minimum 22 bytes before end.
|
||||
if (! File.seekg(eof - 22, ios::beg))
|
||||
return -1;
|
||||
|
||||
streamoff EndPos;
|
||||
streamoff StartPos = File.tellg();
|
||||
|
||||
if (StartPos == streamoff(0))
|
||||
return -1;
|
||||
|
||||
if (StartPos <= begin + streamoff(65536))
|
||||
EndPos = 1;
|
||||
else
|
||||
EndPos = StartPos - streamoff(65536);
|
||||
|
||||
// Start the scan
|
||||
do {
|
||||
unsigned int RawSignature;
|
||||
|
||||
if (! readvar(File, RawSignature, 4))
|
||||
return -1;
|
||||
|
||||
eofcd_header Header;
|
||||
streampos Pos = File.tellg();
|
||||
|
||||
// Found a potential "eofcd" header?
|
||||
if ((RawSignature == ENDOFDIR) && (File.seekg(-4, ios::cur)) && (Header.ReadHeader(File))) {
|
||||
|
||||
// Check invariant values (1 disk only)
|
||||
if ((Header.m_NbDisks == 0) && (0 == Header.m_DirDisk) && (Header.m_LocalEntries == Header.m_TotalEntries)) {
|
||||
|
||||
// Check comment ends at eof
|
||||
if (! File.seekg(eof - 1 , ios::beg))
|
||||
return -1;
|
||||
if ((File.tellg() + streamoff(1)) == (Pos + streamoff(Header.m_CommentSize + 22 - 4))) {
|
||||
|
||||
// Check the start offset leads to a correct directory/file header;
|
||||
if (! File.seekg(begin + Header.m_Offset)) return -1;
|
||||
if (! readvar(File, RawSignature, 4)) return -1;
|
||||
if (RawSignature == FILE)
|
||||
return begin + Header.m_Offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File.seekg(Pos);
|
||||
|
||||
} while ((File.seekg(-5, ios::cur)) && (File.tellg() > EndPos) && (File.tellg() > begin));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
streamoff filesystem::CentralDir(istream & File) const
|
||||
{
|
||||
using io_facilities::readvar;
|
||||
|
||||
// Look for the "end of central dir" header. Start minimum 22 bytes before end.
|
||||
if (! File.seekg(-22, ios::end)) return -1;
|
||||
|
||||
streamoff EndPos;
|
||||
streamoff StartPos = File.tellg();
|
||||
|
||||
if (StartPos == streamoff(0)) return -1;
|
||||
|
||||
if (StartPos <= streamoff(65536))
|
||||
EndPos = 1;
|
||||
else
|
||||
EndPos = StartPos - streamoff(65536);
|
||||
|
||||
// Start the scan
|
||||
do {
|
||||
unsigned int RawSignature;
|
||||
|
||||
if (! readvar(File, RawSignature, 4)) return -1;
|
||||
|
||||
eofcd_header Header;
|
||||
streampos Pos = File.tellg();
|
||||
|
||||
// Found a potential "eofcd" header?
|
||||
if ((RawSignature == ENDOFDIR) && (File.seekg(-4, ios::cur)) && (Header.ReadHeader(File))) {
|
||||
|
||||
// Check invariant values (1 disk only)
|
||||
if ((Header.m_NbDisks == 0) && (0 == Header.m_DirDisk) && (Header.m_LocalEntries == Header.m_TotalEntries)) {
|
||||
|
||||
// Check comment ends at eof
|
||||
if (! File.seekg(-1, ios::end)) return -1;
|
||||
if ((File.tellg() + streamoff(1)) == (Pos + streamoff(Header.m_CommentSize + 22 - 4))) {
|
||||
|
||||
// Check the start offset leads to a correct directory/file header;
|
||||
if (! File.seekg(Header.m_Offset)) return -1;
|
||||
if (! readvar(File, RawSignature, 4)) return -1;
|
||||
if (RawSignature == FILE)
|
||||
return Header.m_Offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File.seekg(Pos);
|
||||
|
||||
} while ((File.seekg(-5, ios::cur)) && (File.tellg() > EndPos));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
streamoff filesystem::SkipLFHdr(istream & File, streamoff LFHdrPos)
|
||||
{
|
||||
using io_facilities::readvar;
|
||||
|
||||
unsigned short NameSize;
|
||||
unsigned short FieldSize;
|
||||
unsigned int RawSignature;
|
||||
|
||||
// verify it's a local header
|
||||
if (! File.seekg(LFHdrPos)) return -1;
|
||||
if (! readvar(File, RawSignature, 4)) return -1;
|
||||
if (RawSignature != LOCALFILE) return -1;
|
||||
|
||||
// Skip and go directly to comment/field size
|
||||
if (! File.seekg(22, ios::cur)) return -1;
|
||||
if (! readvar(File, NameSize, 2)) return -1;
|
||||
if (! readvar(File, FieldSize, 2)) return -1;
|
||||
|
||||
// Skip comment and extra field
|
||||
if (! File.seekg(NameSize + FieldSize, ios::cur)) return -1;
|
||||
|
||||
// Now we are at the compressed data position
|
||||
return (File.tellg());
|
||||
}
|
||||
|
||||
|
||||
|
||||
headerid filesystem::NextHeader(istream & File) const
|
||||
{
|
||||
using io_facilities::readvar;
|
||||
|
||||
unsigned int RawSignature;
|
||||
|
||||
if (! readvar(File, RawSignature, 4))
|
||||
return READERROR;
|
||||
|
||||
if (! File.seekg(-4, ios::cur))
|
||||
return READERROR;
|
||||
|
||||
headerid Signature = headerid(RawSignature);
|
||||
|
||||
switch (Signature) {
|
||||
case FILE:
|
||||
case LOCALFILE:
|
||||
case ENDOFDIR:
|
||||
return Signature;
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace zip_file_system
|
||||
Reference in New Issue
Block a user