Initial commit
This commit is contained in:
242
Torque/SDK/engine/core/zipAggregate.cc
Normal file
242
Torque/SDK/engine/core/zipAggregate.cc
Normal file
@@ -0,0 +1,242 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "core/stringTable.h"
|
||||
|
||||
#include "core/fileStream.h" // Streams
|
||||
|
||||
#include "core/zipAggregate.h" // Own header, and private includes
|
||||
#include "core/zipHeaders.h"
|
||||
|
||||
ZipAggregate::ZipAggregate()
|
||||
: m_pZipFileName(NULL)
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(m_fileList);
|
||||
}
|
||||
|
||||
ZipAggregate::~ZipAggregate()
|
||||
{
|
||||
closeAggregate();
|
||||
}
|
||||
|
||||
bool
|
||||
ZipAggregate::refreshAggregate()
|
||||
{
|
||||
AssertFatal(m_pZipFileName != NULL, "No filename? Must not be open. Disallowed");
|
||||
|
||||
char tmpBuff[512];
|
||||
dStrcpy(tmpBuff, m_pZipFileName);
|
||||
|
||||
return openAggregate(tmpBuff);
|
||||
}
|
||||
|
||||
bool
|
||||
ZipAggregate::openAggregate(const char* in_pFileName)
|
||||
{
|
||||
closeAggregate();
|
||||
|
||||
AssertFatal(in_pFileName != NULL, "No filename to open!");
|
||||
|
||||
m_pZipFileName = new char[dStrlen(in_pFileName) + 1];
|
||||
dStrcpy(m_pZipFileName, in_pFileName);
|
||||
|
||||
FileStream* pStream = new FileStream;
|
||||
if (pStream->open(m_pZipFileName, FileStream::Read) == false ||
|
||||
createZipDirectory(pStream) == false) {
|
||||
// Failure, abort the open...
|
||||
//
|
||||
delete pStream;
|
||||
|
||||
delete [] m_pZipFileName;
|
||||
m_pZipFileName = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finished! Open for business
|
||||
delete pStream;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ZipAggregate::closeAggregate()
|
||||
{
|
||||
destroyZipDirectory();
|
||||
|
||||
delete [] m_pZipFileName;
|
||||
m_pZipFileName = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ZipAggregate::destroyZipDirectory()
|
||||
{
|
||||
m_fileList.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
ZipAggregate::createZipDirectory(Stream* io_pStream)
|
||||
{
|
||||
AssertFatal(io_pStream != NULL, "Error, stream not open.");
|
||||
|
||||
U32 streamSize = io_pStream->getStreamSize();
|
||||
U32 initialPosition = io_pStream->getPosition();
|
||||
|
||||
// We assume that the CD is 22 bytes from the end. This will be invalid
|
||||
// in the case that the zip file has comments. Perhaps test the quick
|
||||
// way, then degrade to seaching the final 64k+22b (!) of the stream?
|
||||
//
|
||||
bool posSuccess = io_pStream->setPosition(streamSize - sizeof(ZipEOCDRecord::EOCDRecord));
|
||||
if (posSuccess == false) {
|
||||
AssertWarn(false, "Unable to position stream to start of EOCDRecord");
|
||||
return false;
|
||||
}
|
||||
|
||||
ZipEOCDRecord* pEOCDRecord = new ZipEOCDRecord;
|
||||
if (pEOCDRecord->readFromStream(*io_pStream) == false) {
|
||||
// This is where we would try to degrade to general case...
|
||||
//
|
||||
AssertWarn(false, "Unable to locate central directory. "
|
||||
"Zip File might have comments");
|
||||
delete pEOCDRecord;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the consistency of the zipFile.
|
||||
//
|
||||
if ((pEOCDRecord->m_record.diskNumber != pEOCDRecord->m_record.eocdDiskNumber) ||
|
||||
(pEOCDRecord->m_record.numCDEntriesDisk != pEOCDRecord->m_record.numCDEntriesTotal)) {
|
||||
AssertWarn(false, "Zipfile appears to be part of a "
|
||||
"multi-zip disk span set, unsupported");
|
||||
delete pEOCDRecord;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're here, we're good! Scan to the start of the CDirectory, and
|
||||
// start scanning the entries into our directory structure...
|
||||
//
|
||||
U32 startCDPosition = pEOCDRecord->m_record.cdOffset;
|
||||
U32 endCDPosition = pEOCDRecord->m_record.cdOffset +
|
||||
pEOCDRecord->m_record.cdSize;
|
||||
|
||||
posSuccess = io_pStream->setPosition(startCDPosition);
|
||||
if (posSuccess == false) {
|
||||
AssertWarn(false, "Unable to position to CD entries.");
|
||||
delete pEOCDRecord;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dirReadSuccess = true;
|
||||
for (U16 i = 0; i < pEOCDRecord->m_record.numCDEntriesTotal; i++) {
|
||||
ZipDirFileHeader zdfHeader;
|
||||
|
||||
bool hrSuccess = zdfHeader.readFromStream(*io_pStream);
|
||||
if (hrSuccess == false) {
|
||||
AssertWarn(false, "Error reading a CD Entry in zip aggregate");
|
||||
dirReadSuccess = false;
|
||||
break;
|
||||
}
|
||||
|
||||
enterZipDirRecord(zdfHeader);
|
||||
}
|
||||
|
||||
delete pEOCDRecord;
|
||||
if (dirReadSuccess == true) {
|
||||
// Every thing went well, we're done, position the stream to the end of the
|
||||
// CD...
|
||||
//
|
||||
io_pStream->setPosition(endCDPosition);
|
||||
return true;
|
||||
} else {
|
||||
// Oh, crap.
|
||||
io_pStream->setPosition(initialPosition);
|
||||
destroyZipDirectory();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ZipAggregate::enterZipDirRecord(const ZipDirFileHeader& in_rHeader)
|
||||
{
|
||||
// First figure out whether we are looking at a directory
|
||||
// or a file. Directories have a trailing / in the file name
|
||||
// and a filelength of 0
|
||||
if (in_rHeader.m_pFileName[dStrlen(in_rHeader.m_pFileName) - 1] == '/' &&
|
||||
(in_rHeader.m_header.compressedSize == 0 &&
|
||||
in_rHeader.m_header.uncompressedSize == 0))
|
||||
return;
|
||||
|
||||
// We have a file if we are here, so enter it
|
||||
// into the directory
|
||||
m_fileList.increment();
|
||||
FileEntry& rEntry = m_fileList.last();
|
||||
|
||||
// Copy the path to a file within a zip to tempString
|
||||
char tempString[1024];
|
||||
dStrcpy(tempString, in_rHeader.m_pFileName);
|
||||
|
||||
// Iterate through the string and change any
|
||||
// characters with \\ to /
|
||||
char* scan = tempString;
|
||||
while (*scan != '\0')
|
||||
{
|
||||
if (*scan == '\\')
|
||||
*scan = '/';
|
||||
scan++;
|
||||
}
|
||||
|
||||
// Allocate memory for zipPath and then copy the
|
||||
// full path of the zip, so thats
|
||||
// <location>/<name>.zip
|
||||
char* zipPath = new char[dStrlen(m_pZipFileName) + dStrlen(tempString) + 2];
|
||||
dStrcpy(zipPath, m_pZipFileName);
|
||||
|
||||
// Get all the text from the . until the end of
|
||||
// the string
|
||||
char* dot = dStrrchr(zipPath, '.') - 2;
|
||||
|
||||
// Kill the extension so the zipPath string
|
||||
// becomes <location>/<name>
|
||||
dot[2] = '\0';
|
||||
|
||||
|
||||
// Create the FULL path to the contents within a zip now
|
||||
// So zipPath becomes
|
||||
// <harddrive path>/<zip name>/<zip path>/<zip files>.*
|
||||
dStrcat(zipPath, "/");
|
||||
dStrcat(zipPath, tempString);
|
||||
|
||||
// Create file base name
|
||||
char* pPathEnd = dStrrchr(zipPath, '/');
|
||||
if(pPathEnd != NULL)
|
||||
{
|
||||
// Put our path and file into the string table and store
|
||||
// them for the ResourceManager
|
||||
pPathEnd[0] = '\0';
|
||||
rEntry.pPath = StringTable->insert(zipPath);
|
||||
rEntry.pFileName = StringTable->insert(pPathEnd + 1);
|
||||
}
|
||||
|
||||
// Tell ResourceManger the appropriate file attributes
|
||||
rEntry.fileSize = in_rHeader.m_header.uncompressedSize;
|
||||
rEntry.compressedFileSize = in_rHeader.m_header.compressedSize;
|
||||
rEntry.fileOffset = in_rHeader.m_header.relativeOffsetOfLocalHeader;
|
||||
|
||||
// Tell ResourceManager the appropriate file compressions used on the file
|
||||
if(in_rHeader.m_header.compressionMethod == ZipDirFileHeader::Deflated)
|
||||
rEntry.flags = FileEntry::Compressed;
|
||||
else if(in_rHeader.m_header.compressionMethod == ZipDirFileHeader::Stored)
|
||||
{
|
||||
rEntry.flags = FileEntry::Uncompressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We can't have anything other than Stored or Deflated zips
|
||||
AssertWarn(0, avar("Warning, non-stored or deflated resource in %s", m_pZipFileName));
|
||||
m_fileList.decrement();
|
||||
}
|
||||
|
||||
// important!! or we have memory leaks :)
|
||||
delete [] zipPath;
|
||||
}
|
||||
Reference in New Issue
Block a user