mirror of
https://github.com/leozide/leocad
synced 2025-01-17 18:11:42 +01:00
Added support for writing zip files.
This commit is contained in:
parent
b1c1c6bf11
commit
748ad35ff4
3 changed files with 269 additions and 6 deletions
|
@ -89,7 +89,7 @@ bool lcPiecesLibrary::OpenArchive(const char* FileName)
|
||||||
{
|
{
|
||||||
mZipFile = new lcZipFile();
|
mZipFile = new lcZipFile();
|
||||||
|
|
||||||
if (!mZipFile->Open(FileName))
|
if (!mZipFile->OpenRead(FileName))
|
||||||
{
|
{
|
||||||
delete mZipFile;
|
delete mZipFile;
|
||||||
mZipFile = NULL;
|
mZipFile = NULL;
|
||||||
|
@ -146,7 +146,7 @@ bool lcPiecesLibrary::OpenArchive(const char* FileName)
|
||||||
}
|
}
|
||||||
else if (!memcmp(Name + 6, "P/", 2))
|
else if (!memcmp(Name + 6, "P/", 2))
|
||||||
{
|
{
|
||||||
lcLibraryPrimitive* Prim = new lcLibraryPrimitive(Name + 8, FileIdx, (memcmp(Prim->mName, "STU", 3) == 0), false);
|
lcLibraryPrimitive* Prim = new lcLibraryPrimitive(Name + 8, FileIdx, (memcmp(Name + 8, "STU", 3) == 0), false);
|
||||||
mPrimitives.Add(Prim);
|
mPrimitives.Add(Prim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "lc_file.h"
|
#include "lc_file.h"
|
||||||
#include "lc_math.h"
|
#include "lc_math.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
#include <zutil.h>
|
||||||
|
|
||||||
lcZipFile::lcZipFile()
|
lcZipFile::lcZipFile()
|
||||||
{
|
{
|
||||||
|
@ -11,10 +12,11 @@ lcZipFile::lcZipFile()
|
||||||
|
|
||||||
lcZipFile::~lcZipFile()
|
lcZipFile::~lcZipFile()
|
||||||
{
|
{
|
||||||
|
Flush();
|
||||||
delete mFile;
|
delete mFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lcZipFile::Open(const char* FilePath)
|
bool lcZipFile::OpenRead(const char* FilePath)
|
||||||
{
|
{
|
||||||
lcDiskFile* File = new lcDiskFile();
|
lcDiskFile* File = new lcDiskFile();
|
||||||
mFile = File;
|
mFile = File;
|
||||||
|
@ -29,6 +31,32 @@ bool lcZipFile::Open(const char* FilePath)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool lcZipFile::OpenWrite(const char* FilePath)
|
||||||
|
{
|
||||||
|
lcDiskFile* File = new lcDiskFile();
|
||||||
|
mFile = File;
|
||||||
|
bool Exists = true;
|
||||||
|
|
||||||
|
if (!File->Open(FilePath, "r+b") || !Open())
|
||||||
|
{
|
||||||
|
Exists = false;
|
||||||
|
mNumEntries = 0;
|
||||||
|
mCentralDirSize = 0;
|
||||||
|
mCentralDirOffset = 0;
|
||||||
|
mBytesBeforeZipFile = 0;
|
||||||
|
mCentralPos = 0;
|
||||||
|
|
||||||
|
if (!File->Open(FilePath, "wb"))
|
||||||
|
{
|
||||||
|
delete File;
|
||||||
|
mFile = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
lcuint64 lcZipFile::SearchCentralDir()
|
lcuint64 lcZipFile::SearchCentralDir()
|
||||||
{
|
{
|
||||||
lcuint64 SizeFile, MaxBack, BackRead, PosFound;
|
lcuint64 SizeFile, MaxBack, BackRead, PosFound;
|
||||||
|
@ -320,14 +348,16 @@ bool lcZipFile::ReadCentralDir()
|
||||||
lcuint64 PosInCentralDir = mCentralDirOffset;
|
lcuint64 PosInCentralDir = mCentralDirOffset;
|
||||||
|
|
||||||
mFile->Seek((long)(PosInCentralDir + mBytesBeforeZipFile), SEEK_SET);
|
mFile->Seek((long)(PosInCentralDir + mBytesBeforeZipFile), SEEK_SET);
|
||||||
mFiles.SetSize((int)mNumEntries);
|
mFiles.Expand((int)mNumEntries);
|
||||||
|
|
||||||
for (lcuint64 FileNum = 0; FileNum < mNumEntries; FileNum++)
|
for (lcuint64 FileNum = 0; FileNum < mNumEntries; FileNum++)
|
||||||
{
|
{
|
||||||
lcuint32 Magic, Number32;
|
lcuint32 Magic, Number32;
|
||||||
lcZipFileInfo& FileInfo = mFiles[(int)FileNum];
|
lcZipFileInfo& FileInfo = mFiles.Add();
|
||||||
long Seek = 0;
|
long Seek = 0;
|
||||||
|
|
||||||
|
FileInfo.write_buffer = NULL;
|
||||||
|
|
||||||
if (mFile->ReadU32(&Magic, 1) != 1 || Magic != 0x02014b50)
|
if (mFile->ReadU32(&Magic, 1) != 1 || Magic != 0x02014b50)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -689,3 +719,230 @@ bool lcZipFile::ExtractFile(int FileIndex, lcMemFile& File, lcuint32 MaxLength)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool lcZipFile::AddFile(const char* FileName, lcMemFile& File)
|
||||||
|
{
|
||||||
|
const int BufferSize = 16384;
|
||||||
|
char WriteBuffer[BufferSize];
|
||||||
|
z_stream Stream;
|
||||||
|
lcuint32 Crc32 = 0;
|
||||||
|
|
||||||
|
File.Seek(0, SEEK_SET);
|
||||||
|
|
||||||
|
Stream.zalloc = (alloc_func)0;
|
||||||
|
Stream.zfree = (free_func)0;
|
||||||
|
Stream.opaque = (voidpf)0;
|
||||||
|
|
||||||
|
if (deflateInit2(&Stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lcMemFile* OutFile = new lcMemFile();
|
||||||
|
lcMemFile& CompressedFile = *OutFile;
|
||||||
|
|
||||||
|
Bytef* BufferIn = File.mBuffer;
|
||||||
|
int Flush;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
uInt Read = lcMin(File.GetLength() - (BufferIn - File.mBuffer), BufferSize);
|
||||||
|
Stream.avail_in = Read;
|
||||||
|
Stream.next_in = BufferIn;
|
||||||
|
Crc32 = crc32(Crc32, BufferIn, Read);
|
||||||
|
BufferIn += Read;
|
||||||
|
|
||||||
|
Flush = (BufferIn >= File.mBuffer + File.GetLength()) ? Z_FINISH : Z_NO_FLUSH;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Stream.avail_out = BufferSize;
|
||||||
|
Stream.next_out = (Bytef*)WriteBuffer;
|
||||||
|
deflate(&Stream, Flush);
|
||||||
|
CompressedFile.WriteBuffer(WriteBuffer, BufferSize - Stream.avail_out);
|
||||||
|
} while (Stream.avail_out == 0);
|
||||||
|
} while (Flush != Z_FINISH);
|
||||||
|
|
||||||
|
deflateEnd(&Stream);
|
||||||
|
|
||||||
|
lcZipFileInfo& Info = mFiles.Add();
|
||||||
|
|
||||||
|
Info.version = 0;
|
||||||
|
if (CompressedFile.GetLength() >= 0xffffffff || File.GetLength() >= 0xffffffff)
|
||||||
|
Info.version_needed = 45;
|
||||||
|
else
|
||||||
|
Info.version_needed = 20;
|
||||||
|
Info.flag = 0;
|
||||||
|
Info.compression_method = Z_DEFLATED;
|
||||||
|
Info.crc = Crc32;
|
||||||
|
Info.compressed_size = CompressedFile.GetLength();
|
||||||
|
Info.uncompressed_size = File.GetLength();
|
||||||
|
Info.size_filename = strlen(FileName);
|
||||||
|
Info.size_file_extra = 0;
|
||||||
|
Info.size_file_comment = 0;
|
||||||
|
Info.disk_num_start = 0;
|
||||||
|
Info.internal_fa = 0;
|
||||||
|
Info.external_fa = 0;
|
||||||
|
Info.offset_curfile = 0;
|
||||||
|
strncpy(Info.file_name, FileName, sizeof(Info.file_name));
|
||||||
|
|
||||||
|
time_t rawtime;
|
||||||
|
struct tm* timeinfo;
|
||||||
|
|
||||||
|
time(&rawtime);
|
||||||
|
timeinfo = localtime(&rawtime);
|
||||||
|
|
||||||
|
Info.tmu_date.tm_sec = timeinfo->tm_sec;
|
||||||
|
Info.tmu_date.tm_min = timeinfo->tm_min;
|
||||||
|
Info.tmu_date.tm_hour = timeinfo->tm_hour;
|
||||||
|
Info.tmu_date.tm_mday = timeinfo->tm_mday;
|
||||||
|
Info.tmu_date.tm_mon = timeinfo->tm_mon ;
|
||||||
|
Info.tmu_date.tm_year = timeinfo->tm_year - 80;
|
||||||
|
Info.dosDate = (((timeinfo->tm_mday) + (32 * (timeinfo->tm_mon + 1)) + (512 * timeinfo->tm_year)) << 16) | ((timeinfo->tm_sec / 2) + (32 * timeinfo->tm_min) + (2048 * (uLong)timeinfo->tm_hour));
|
||||||
|
|
||||||
|
Info.write_buffer = OutFile;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lcZipFile::Flush()
|
||||||
|
{
|
||||||
|
int FirstFileAdded = -1;
|
||||||
|
|
||||||
|
if (!mFile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int FileIdx = 0; FileIdx < mFiles.GetSize(); FileIdx++)
|
||||||
|
{
|
||||||
|
lcZipFileInfo& FileInfo = mFiles[FileIdx];
|
||||||
|
|
||||||
|
if (FileInfo.write_buffer)
|
||||||
|
{
|
||||||
|
FirstFileAdded = FileIdx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FirstFileAdded == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lcuint64 CurrentOffset = mCentralDirOffset + mBytesBeforeZipFile;
|
||||||
|
mFile->Seek((long)CurrentOffset, SEEK_SET);
|
||||||
|
|
||||||
|
void* CentralDir = malloc((long)mCentralDirSize);
|
||||||
|
mFile->ReadBuffer(CentralDir, (long)mCentralDirSize);
|
||||||
|
mFile->Seek((long)CurrentOffset, SEEK_SET);
|
||||||
|
|
||||||
|
for (int FileIdx = FirstFileAdded; FileIdx < mFiles.GetSize(); FileIdx++)
|
||||||
|
{
|
||||||
|
lcZipFileInfo& FileInfo = mFiles[FileIdx];
|
||||||
|
|
||||||
|
FileInfo.offset_curfile = CurrentOffset;
|
||||||
|
|
||||||
|
if (FileInfo.offset_curfile >= 0xffffffff)
|
||||||
|
FileInfo.version_needed = 45;
|
||||||
|
|
||||||
|
mFile->WriteU32(0x04034b50);
|
||||||
|
mFile->WriteU16(FileInfo.version_needed);
|
||||||
|
mFile->WriteU16(FileInfo.flag);
|
||||||
|
mFile->WriteU16(FileInfo.compression_method);
|
||||||
|
mFile->WriteU32(FileInfo.dosDate);
|
||||||
|
mFile->WriteU32(FileInfo.crc);
|
||||||
|
if (FileInfo.compressed_size >= 0xffffffff)
|
||||||
|
mFile->WriteU32(0xffffffff);
|
||||||
|
else
|
||||||
|
mFile->WriteU32((lcuint32)FileInfo.compressed_size);
|
||||||
|
if (FileInfo.uncompressed_size >= 0xffffffff)
|
||||||
|
mFile->WriteU32(0xffffffff);
|
||||||
|
else
|
||||||
|
mFile->WriteU32((lcuint32)FileInfo.uncompressed_size);
|
||||||
|
mFile->WriteU16(FileInfo.size_filename);
|
||||||
|
mFile->WriteU16(FileInfo.size_file_extra);
|
||||||
|
mFile->WriteBuffer(FileInfo.file_name, FileInfo.size_filename);
|
||||||
|
|
||||||
|
mFile->WriteBuffer(FileInfo.write_buffer->mBuffer, FileInfo.write_buffer->GetLength());
|
||||||
|
delete FileInfo.write_buffer;
|
||||||
|
FileInfo.write_buffer = NULL;
|
||||||
|
|
||||||
|
CurrentOffset = mFile->GetPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
lcuint64 CentralDirPos = mFile->GetPosition();
|
||||||
|
mFile->WriteBuffer(CentralDir, (long)mCentralDirSize);
|
||||||
|
free(CentralDir);
|
||||||
|
|
||||||
|
for (int FileIdx = FirstFileAdded; FileIdx < mFiles.GetSize(); FileIdx++)
|
||||||
|
{
|
||||||
|
lcZipFileInfo& FileInfo = mFiles[FileIdx];
|
||||||
|
|
||||||
|
mFile->WriteU32(0x02014b50);
|
||||||
|
mFile->WriteU16(FileInfo.version);
|
||||||
|
mFile->WriteU16(FileInfo.version_needed);
|
||||||
|
mFile->WriteU16(FileInfo.flag);
|
||||||
|
mFile->WriteU16(FileInfo.compression_method);
|
||||||
|
mFile->WriteU32(FileInfo.dosDate);
|
||||||
|
mFile->WriteU32(FileInfo.crc);
|
||||||
|
if (FileInfo.compressed_size >= 0xffffffff)
|
||||||
|
mFile->WriteU32(0xffffffff);
|
||||||
|
else
|
||||||
|
mFile->WriteU32((lcuint32)FileInfo.compressed_size);
|
||||||
|
if (FileInfo.uncompressed_size >= 0xffffffff)
|
||||||
|
mFile->WriteU32(0xffffffff);
|
||||||
|
else
|
||||||
|
mFile->WriteU32((lcuint32)FileInfo.uncompressed_size);
|
||||||
|
mFile->WriteU16(FileInfo.size_filename);
|
||||||
|
mFile->WriteU16(FileInfo.size_file_extra);
|
||||||
|
mFile->WriteU16(FileInfo.size_file_comment);
|
||||||
|
mFile->WriteU16(FileInfo.disk_num_start);
|
||||||
|
mFile->WriteU16(FileInfo.internal_fa);
|
||||||
|
mFile->WriteU32(FileInfo.external_fa);
|
||||||
|
|
||||||
|
if (FileInfo.offset_curfile >= 0xffffffff)
|
||||||
|
mFile->WriteU32(0xffffffff);
|
||||||
|
else
|
||||||
|
mFile->WriteU32((lcuint32)(FileInfo.offset_curfile - mBytesBeforeZipFile));
|
||||||
|
|
||||||
|
mFile->WriteBuffer(FileInfo.file_name, FileInfo.size_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
lcuint64 CentralDirEnd = mFile->GetPosition();
|
||||||
|
|
||||||
|
if (CentralDirPos - mBytesBeforeZipFile >= 0xffffffff)
|
||||||
|
{
|
||||||
|
mFile->WriteU32(0x6064b50);
|
||||||
|
mFile->WriteU64(44);
|
||||||
|
mFile->WriteU16(45);
|
||||||
|
mFile->WriteU16(45);
|
||||||
|
mFile->WriteU32(0);
|
||||||
|
mFile->WriteU32(0);
|
||||||
|
mFile->WriteU64(mFiles.GetSize());
|
||||||
|
mFile->WriteU64(mFiles.GetSize());
|
||||||
|
mFile->WriteU64(CentralDirEnd - CentralDirPos);
|
||||||
|
mFile->WriteU64(CentralDirPos - mBytesBeforeZipFile);
|
||||||
|
|
||||||
|
mFile->WriteU32(0x7064b50);
|
||||||
|
mFile->WriteU32(0);
|
||||||
|
mFile->WriteU64(CentralDirEnd - mBytesBeforeZipFile);
|
||||||
|
mFile->WriteU32(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mFile->WriteU32(0x06054b50);
|
||||||
|
mFile->WriteU16(0);
|
||||||
|
mFile->WriteU16(0);
|
||||||
|
|
||||||
|
if (mFiles.GetSize() >= 0xffff)
|
||||||
|
mFile->WriteU16(0xffff);
|
||||||
|
else
|
||||||
|
mFile->WriteU16(mFiles.GetSize());
|
||||||
|
|
||||||
|
if (mFiles.GetSize() >= 0xffff)
|
||||||
|
mFile->WriteU16(0xffff);
|
||||||
|
else
|
||||||
|
mFile->WriteU16(mFiles.GetSize());
|
||||||
|
|
||||||
|
mFile->WriteU32((lcuint32)(CentralDirEnd - CentralDirPos));
|
||||||
|
if (CentralDirPos - mBytesBeforeZipFile >= 0xffffffff)
|
||||||
|
mFile->WriteU32(0xffffffff);
|
||||||
|
else
|
||||||
|
mFile->WriteU32((lcuint32)(CentralDirPos - mBytesBeforeZipFile));
|
||||||
|
|
||||||
|
mFile->WriteU16(0);
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ struct lcZipFileInfo
|
||||||
lcuint64 offset_curfile; // relative offset of local header 8 bytes
|
lcuint64 offset_curfile; // relative offset of local header 8 bytes
|
||||||
char file_name[256];
|
char file_name[256];
|
||||||
tm_unz tmu_date;
|
tm_unz tmu_date;
|
||||||
|
|
||||||
|
lcMemFile* write_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class lcZipFile
|
class lcZipFile
|
||||||
|
@ -46,9 +48,13 @@ public:
|
||||||
lcZipFile();
|
lcZipFile();
|
||||||
~lcZipFile();
|
~lcZipFile();
|
||||||
|
|
||||||
bool Open(const char* FilePath);
|
bool OpenRead(const char* FilePath);
|
||||||
|
bool OpenWrite(const char* FilePath);
|
||||||
|
void Flush();
|
||||||
|
|
||||||
bool ExtractFile(int FileIndex, lcMemFile& File, lcuint32 MaxLength = 0xffffffff);
|
bool ExtractFile(int FileIndex, lcMemFile& File, lcuint32 MaxLength = 0xffffffff);
|
||||||
bool ExtractFile(const char* FileName, lcMemFile& File, lcuint32 MaxLength = 0xffffffff);
|
bool ExtractFile(const char* FileName, lcMemFile& File, lcuint32 MaxLength = 0xffffffff);
|
||||||
|
bool AddFile(const char* FileName, lcMemFile& File);
|
||||||
|
|
||||||
ObjArray<lcZipFileInfo> mFiles;
|
ObjArray<lcZipFileInfo> mFiles;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue