#include "wxinc.h" #ifdef LINUX #include "xvt_type.h" #include "incstr.h" #else #include #endif #include "agasys.h" /////////////////////////////////////////////////////////// // Unzip support /////////////////////////////////////////////////////////// #include #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(); } int aga_find_slash(const wxString& path, int from) { for (int i = from; path[i]; i++) if (wxIsPathSeparator(path[i])) return i; return -1; } void aga_create_dir(wxString strPath) { if (!wxEndsWithPathSeparator(strPath)) strPath += wxFILE_SEP_PATH; for (int i = aga_find_slash(strPath, 0); i > 0; i = aga_find_slash(strPath, i+1)) { const wxString strDir = strPath.Mid(0,i); if (!::wxDirExists(strDir)) ::wxMkdir(strDir); } } 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]; if (wxEndsWithPathSeparator(strFileName)) // Is dir name { wxString strOutDir = destdir; if (!wxEndsWithPathSeparator(strOutDir)) strOutDir += wxFILE_SEP_PATH; strOutDir += strFileName; if (!::wxDirExists(strOutDir)) ::wxMkdir(strOutDir); } else { wxZipInputStream fin(zipfile, strFileName); wxString strOutFile = destdir; if (!wxEndsWithPathSeparator(strOutFile) && !wxIsPathSeparator(strFileName[0])) strOutFile += wxFILE_SEP_PATH; strOutFile += strFileName; wxString strPath; ::wxSplitPath(strOutFile, &strPath, NULL, NULL); aga_create_dir(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); }; // Ricordarsi di taroccare il sorgente della deflateInit in zlib AgaZlibOutputStream::AgaZlibOutputStream(wxOutputStream& stream) : wxZlibOutputStream(stream, AGA_COMPRESSION_LEVEL) { } static size_t AddFilesToList(const wxString& strBase, const wxString& strMask, wxArrayString& aFiles) { const size_t n = wxDir::GetAllFiles(strBase, &aFiles, strMask); 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, wxArrayString& 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); for (size_t i = 0; i < aFiles.GetCount(); i++) AddFileToZip(strBase, aFiles[i], fout, fdir); 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 || aFiles.GetCount() == 0); } bool aga_zip(const char* srcfiles, const char* zipfile) { wxString strBase, strMask, strExt; wxSplitPath(srcfiles, &strBase, &strMask, &strExt); strMask += '.'; strMask += strExt; wxArrayString aFiles; AddFilesToList(strBase, strMask, aFiles); return AddFilesToZip(strBase, aFiles, zipfile); } bool aga_zip_filelist(const char* filelist, const char* zipfile) { wxArrayString 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); }