#include "wxinc.h" #include #ifdef LINUX #include "xvt_type.h" #endif #include "agasys.h" /////////////////////////////////////////////////////////// // Unzip support /////////////////////////////////////////////////////////// #include #include #pragma pack(2) struct ZipLocalFileHeader { unsigned short nVersionNeeded; unsigned short nFlags; unsigned short nMethod; unsigned short nLastModTime; unsigned short nLastModDate; unsigned long dwCRC; unsigned long dwCompressedSize; unsigned long dwUncompressedSize; unsigned short nNameLength; unsigned short nExtraLength; }; struct ZipDirectoryFileHeader { unsigned short nVersionUsed; ZipLocalFileHeader zlfh; unsigned short nCommentLength; unsigned short nStartDisk; unsigned short nInternalAttr; unsigned long nExternalAttr; unsigned long nLocalHeaderOffset; }; struct ZipDirectoryEnd { unsigned short nThisDisk; unsigned short nStartDisk; unsigned short nDiskEntries; unsigned short nTotalEntries; unsigned long nSize; unsigned long nStartOffset; unsigned short nCommentLength; }; #pragma pack() unsigned int aga_ziplist(const char* zipfile, wxArrayString& aFiles) { const unsigned long dwDirectorySignature = 0x02014B50; const unsigned long dwEndDirectorySignature = 0x06054B50; wxFileInputStream fin(zipfile); const off_t off = sizeof(ZipDirectoryEnd)+sizeof(dwEndDirectorySignature); fin.SeekI(-off, wxFromEnd); unsigned long dwSignature = 0; fin.Read(&dwSignature, sizeof(dwSignature)); if (dwSignature != dwEndDirectorySignature) return 0; ZipDirectoryEnd zde; fin.Read(&zde, sizeof(zde)); if (zde.nThisDisk < zde.nStartDisk || zde.nDiskEntries == 0 || zde.nSize == 0) return 0; fin.SeekI(zde.nStartOffset, wxFromStart); for (unsigned int f = 0; f < zde.nDiskEntries; f++) { fin.Read(&dwSignature, sizeof(dwSignature)); if (dwSignature != dwDirectorySignature) break; ZipDirectoryFileHeader zdfh; memset(&zdfh, 0, sizeof(zdfh)); fin.Read(&zdfh, sizeof(zdfh)); char name[_MAX_PATH]; memset(name, 0, sizeof(name)); fin.Read(name, zdfh.zlfh.nNameLength); aFiles.Add(name); } return aFiles.GetCount(); } bool aga_unzip(const char* zipfile, const char* destdir) { wxArrayString aFiles; const unsigned int files = aga_ziplist(zipfile, aFiles); for (unsigned int f = 0; f < files; f++) { const wxString& strFileName = aFiles[f]; wxZipInputStream fin(zipfile, strFileName); wxString strOutFile = destdir; strOutFile += '/'; strOutFile += strFileName; wxString strPath; ::wxSplitPath(strOutFile, &strPath, NULL, NULL); if (!::wxDirExists(strPath)) ::wxMkdir(strPath); wxFileOutputStream fout(strOutFile); fout.Write(fin); } return files > 0; } /////////////////////////////////////////////////////////// // Zip support /////////////////////////////////////////////////////////// #include #include <../src/zlib/zlib.h> class AgaZlibOutputStream : public wxZlibOutputStream { enum { AGA_COMPRESSION_LEVEL = 9 }; public: AgaZlibOutputStream(wxOutputStream& stream); }; #if wxCHECK_VERSION(2,3,4) // Da questa vesrione si deve taroccare il sorgente della deflateInit in zlib AgaZlibOutputStream::AgaZlibOutputStream(wxOutputStream& stream) : wxZlibOutputStream(stream, AGA_COMPRESSION_LEVEL) { } #else AgaZlibOutputStream::AgaZlibOutputStream(wxOutputStream& stream) : wxZlibOutputStream(stream, AGA_COMPRESSION_LEVEL) { const int DEF_MEM_LEVEL = 8; deflateInit2_(m_deflate, AGA_COMPRESSION_LEVEL, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, "1.1.2", sizeof(*m_deflate)); } #endif static int AddFilesToList(const wxString& strBase, const wxString& strMask, wxStringList& aFiles) { int n = 0; wxString f = strBase + "/" + strMask; f = ::wxFindFirstFile(f, 0); while (!f.IsEmpty()) { if (wxDirExists(f)) { n += AddFilesToList(f, strMask, aFiles); } else { aFiles.Add(f); n++; } f = ::wxFindNextFile(); } return n; } static void AddFileToZip(const wxString& strPrefix, const wxString& strFile, wxFileOutputStream& fout, wxFileOutputStream& fdir) { if (!wxFileExists(strFile)) return; wxString strPath, strName, strExt; wxSplitPath(strFile, &strPath, &strName, &strExt); wxString strRelName; strRelName = strPath.Mid(strPrefix.Length()); if (!strRelName.IsEmpty()) strRelName += '/'; strRelName += strName; strRelName += '.'; strRelName += strExt; const off_t nStartPos = fout.TellO(); // Memorizzo posizione const unsigned long dwLocalSignature = 0x04034B50; fout.Write(&dwLocalSignature, sizeof(dwLocalSignature)); // Scrivo PK34 ZipLocalFileHeader zlfh; memset(&zlfh, 0, sizeof(zlfh)); zlfh.nVersionNeeded = 20; // You need at least pkunzip 2.0 zlfh.nFlags = 0x0002; // Deep Hacking ??? zlfh.nMethod = 8; // Implode zlfh.nNameLength = strRelName.Length(); fout.Write(&zlfh, sizeof(zlfh)); // Scrivo header azzerato fout.Write((const char*)strRelName, zlfh.nNameLength); // Scrivo nome file const off_t nDataStart = fout.TellO(); // Memorizzo posizione dati compressi const int nMagicOffset = -4; // Deep hacking :-) { wxFileInputStream fin(strFile); AgaZlibOutputStream zout(fout); zout.Write(fin); // Scrivo file compresso zlfh.dwUncompressedSize = fin.TellI(); } fout.SeekO(nMagicOffset, wxFromEnd); zlfh.dwCompressedSize = fout.TellO(); zlfh.dwCompressedSize -= nDataStart; zlfh.dwCRC = ComputeFileCRC32(strFile); const time_t tMod = ::wxFileModificationTime(strFile); const struct tm* t = localtime(&tMod); if (t != NULL) { zlfh.nLastModDate = t->tm_mday + ((t->tm_mon+1) << 5) + ((t->tm_year-80) << 9); zlfh.nLastModTime = t->tm_sec/2 + (t->tm_min << 5) + (t->tm_hour << 11); } fout.SeekO(nStartPos+sizeof(dwLocalSignature), wxFromStart); fout.Write(&zlfh, sizeof(zlfh)); // fout.Write((const char*)strRelName, strRelName.Length()); // Deep Hacking Here! // const wxByte pkHeader = 0x85; // fout.Write(&pkHeader, 1); fout.SeekO(nMagicOffset, wxFromEnd); ZipDirectoryFileHeader zdfh; memset(&zdfh, 0, sizeof(zdfh)); zdfh.nVersionUsed = zlfh.nVersionNeeded; memcpy(&zdfh.zlfh, &zlfh, sizeof(zlfh)); zdfh.nLocalHeaderOffset = nStartPos; const unsigned long dwDirectorySignature = 0x02014B50; // Scrivo PK12 fdir.Write(&dwDirectorySignature, sizeof(dwDirectorySignature)); fdir.Write(&zdfh, sizeof(zdfh)); // Scrivo entry directory fdir.Write((const char*)strRelName, strRelName.Length()); } static bool AddFilesToZip(const wxString& strBase, wxStringList& aFiles, const char* zipfile) { const char* zipdir = "zipdir.tmp"; wxFileOutputStream fout(zipfile); off_t nDirSize = 0, nDirStart = 0; if (aFiles.GetCount() > 0) // Dummy test { wxFileOutputStream fdir(zipdir); wxStringListNode* node = aFiles.GetFirst(); while (node) { const wxString strFile = node->GetData(); AddFileToZip(strBase, strFile, fout, fdir); node = node->GetNext(); } nDirSize = fdir.TellO(); nDirStart = fout.TellO(); } if (nDirSize > 0) { wxFileInputStream fdir(zipdir); fout.Write(fdir); // Append central directory ZipDirectoryEnd zde; memset(&zde, 0, sizeof(zde)); zde.nDiskEntries = zde.nTotalEntries = aFiles.GetCount(); zde.nSize = nDirSize; zde.nStartOffset = nDirStart; const unsigned long dwEndDirectorySignature = 0x06054B50; fout.Write(&dwEndDirectorySignature, sizeof(dwEndDirectorySignature)); fout.Write(&zde, sizeof(zde)); } if (nDirSize > 0) wxRemoveFile(zipdir); return nDirSize > 0; } bool aga_zip(const char* srcfiles, const char* zipfile) { wxString strBase, strMask, strExt; wxSplitPath(srcfiles, &strBase, &strMask, &strExt); strMask += '.'; strMask += strExt; wxStringList aFiles; AddFilesToList(strBase, strMask, aFiles); return AddFilesToZip(strBase, aFiles, zipfile); } bool aga_zip_filelist(const char* filelist, const char* zipfile) { wxStringList aFiles; ifstream fin(filelist); while (!fin.eof()) { char name[_MAX_PATH]; fin.getline(name, sizeof(name)); if (*name) aFiles.Add(name); else break; } return AddFilesToZip("", aFiles, zipfile); }