1、第一次感觉MS也有这么难用的MFC类;

2、CFtpFileFind类只能实例化一个,多个实例同时查找会出错(因此下载时不能递归),采用队列存储目录再依次下载;

3、本程序支持文件夹嵌套上传下载;

4、boost::filesystem::create_directory不能递归创建文件夹,需手动实现

5、同时支持文件夹先打包压缩再上传功能(m_bZibFlag控制是否压缩)

 

 

代码如下:

CFtpClient.h

 1 #ifndef __ftp_client_h__
 2 #define __ftp_client_h__
 3 
 4 #include <afxinet.h>
 5 #include <iostream>
 6 #include <sstream>
 7 #include <queue>
 8 #include <boost/filesystem/operations.hpp>
 9 #include <boost/filesystem/path.hpp>
10 #include "zip.h"
11 
12 class CFtpClient
13 {
14 public:
15     CFtpClient();
16     ~CFtpClient();
17 
18     bool Connect();
19     bool Close();
20     int Download(std::string strServerDir = "\\", std::string strFilename = "*");
21     int Upload(const std::string strLocalPath);
22 private:
23     //下载文件夹
24     int DownloadFolder();
25     //下载文件
26     int DownloadFile(std::string strServerDir, std::string strFilename);
27     //创建多级目录
28     void CreateDirectory(boost::filesystem::path path);
29     //获取打包压缩文件名称
30     std::string GetZipFolder(const std::string strFolderPath);
31     //压缩文件夹打包
32     void MakeZipFolder(HZIP hz, const std::string strRoot, const std::string strFolderPath);
33 private:
34     CInternetSession* m_pInternetSession;
35     CFtpConnection* m_pFtpConnection;
36 
37     //参数配置
38     std::string m_strServerAddress;               //FTP:服务器地址
39     int m_nServerPort;                            //FTP:服务器端口号
40     std::string m_strUsername;                    //FTP:登录用户名
41     std::string m_strPassword;                    //FTP:登录密码
42     bool m_bZibFlag;                              //文件夹打包上传标志[true:先压缩文件夹打包再上传,false:直接上传文件夹]
43 
44     std::string m_strUploadServerDir;             //上传服务器存储目录
45     std::string m_strDownloadLocalDir;            //下载本地存储目录
46     std::queue<std::string> queServerDir;         //等待下载目录队列
47 };
48 
49 
50 #endif

 

CFtpClient.cpp

  1 //------------------------------------------------------------------------------
  2 // 版权声明:转载请注明出处
  5 // 模块名称:
  6 // 模块描述:FTP上传下载类
  7 // 开发作者:可笑痴狂 http://www.cnblogs.com/dongsheng/
  8 // 创建日期:2015-12-10
  9 // 模块版本:1.0.0.0
 10 // 备注:压缩算法引入zip.h和zip.cpp文件,无需lib或dll,
 11 //       详情参考:http://www.codeproject.com/Articles/7530/Zip-Utils-clean-elegant-simple-C-Win
 12 //------------------------------------------------------------------------------
 13 
 14 #include <string>
 15 #include <iostream>
 16 #include <sstream>
 17 #include "CFtpClient.h"
 18 #include <boost/assert.hpp>
 19 #include <boost/lexical_cast.hpp>
 20 #include <boost/foreach.hpp>
 21 
 22 
 23 CFtpClient::CFtpClient()
 24 {
 25     m_pInternetSession = NULL;
 26     m_pFtpConnection = NULL;
 27     m_strServerAddress = "127.0.0.1";
 28     m_strUsername = "123";
 29     m_strPassword = "123";
 30     m_nServerPort = 21;
 31     m_strDownloadLocalDir = "D:\\DownloadLocal";
 32     m_strUploadServerDir = "\\";
 33     m_bZibFlag = true;
 34 }
 35 
 36 CFtpClient::~CFtpClient()
 37 {
 38     this->Close();
 39 }
 40 
 41 bool CFtpClient::Connect()
 42 {
 43     if (m_pInternetSession != NULL)
 44     {
 45         return true;
 46     }
 47 
 48     m_pInternetSession = new CInternetSession("OTC_FTP_Client");
 49     int nCnt = 1;
 50     while(nCnt++)
 51     {
 52         try
 53         {
 54             m_pFtpConnection = m_pInternetSession->GetFtpConnection(m_strServerAddress.c_str(), m_strUsername.c_str(), m_strPassword.c_str(), 
                                          m_nServerPort);
55 } 56 catch(CInternetException *pEx) 57 { 58 char szErrMsg[1024+1] = {0}; 59 if (pEx->GetErrorMessage(szErrMsg, 1024)) 60 { 61 std::cout << "连接FTP服务器失败, ErrMsg:" << szErrMsg << std::endl; 62 if (nCnt > 5) 63 { 64 return false; 65 } 66 std::cout << "正在尝试重新连接[" << nCnt-1 << "]......" << std::endl; 67 } 68 continue; 69 } 70 return true; 71 } 72 73 return true; 74 } 75 76 bool CFtpClient::Close() 77 { 78 if (NULL != m_pInternetSession) 79 { 80 m_pInternetSession->Close(); 81 delete m_pInternetSession; 82 m_pInternetSession = NULL; 83 } 84 if (NULL != m_pFtpConnection) 85 { 86 m_pFtpConnection->Close(); 87 delete m_pFtpConnection; 88 m_pFtpConnection = NULL; 89 } 90 91 return true; 92 } 93 int CFtpClient::Download(std::string strServerDir /*="\\"*/, std::string strFilename /*= "*"*/) 94 { 95 if ("*" == strFilename) 96 { 97 queServerDir.push(strServerDir); 98 return this->DownloadFolder(); 99 } 100 else 101 { 102 return this->DownloadFile(strServerDir, strFilename); 103 } 104 105 } 106 int CFtpClient::DownloadFile(std::string strServerDir, std::string strFilename) 107 { 108 int nRet = 0; 109 CFtpFileFind* pFtpFileFind = NULL; 110 if(!this->Connect()) 111 { 112 nRet = -1; 113 goto __end; 114 } 115 else 116 { 117 boost::filesystem::path LocalPath(m_strDownloadLocalDir); 118 if (!boost::filesystem::exists(LocalPath)) 119 { 120 this->CreateDirectory(LocalPath); 121 } 122 if (0 == m_pFtpConnection->SetCurrentDirectory(strServerDir.c_str())) 123 { 124 nRet = -1; 125 std::cout << "设置服务器下载目录[" << strServerDir << "]失败!ErrCode=" << GetLastError() << std::endl; 126 DWORD dw = 0; 127 char szBuf[512]={0}; 128 DWORD dwLen = sizeof(szBuf)-1; 129 InternetGetLastResponseInfo(&dw, szBuf, &dwLen); 130 std::cout << "错误信息:" << szBuf << std::endl; 131 goto __end; 132 } 133 if (pFtpFileFind == NULL) 134 { 135 pFtpFileFind = new CFtpFileFind(m_pFtpConnection); 136 } 137 int nRet = pFtpFileFind->FindFile(strFilename.c_str()); 138 if(nRet) 139 { 140 nRet = pFtpFileFind->FindNextFile(); 141 142 std::string strLocalFilename = m_strDownloadLocalDir + "\\" + strFilename; 143 std::string strServerFilename = strFilename; 144 if(m_pFtpConnection->GetFile(strServerFilename.c_str(), strLocalFilename.c_str(), FALSE)) 145 std::cout << "下载文件[" << strServerFilename << "]到[" << strLocalFilename << "]成功!" << std::endl; 146 else 147 { 148 std::cout << "下载文件[" << strServerFilename << "]到[" << strLocalFilename << "]失败!" << std::endl; 149 char szBuf[512]={0}; 150 DWORD dw = 0; 151 DWORD dwLen = sizeof(szBuf)-1; 152 InternetGetLastResponseInfo(&dw, szBuf, &dwLen); 153 dw = GetLastError(); 154 std::cout << "错误信息:" << szBuf << std::endl; 155 nRet = -1; 156 } 157 } 158 } 159 __end: 160 this->Close(); 161 if (pFtpFileFind) 162 { 163 pFtpFileFind->Close(); 164 delete pFtpFileFind; 165 } 166 167 return nRet; 168 } 169 int CFtpClient::DownloadFolder() 170 { 171 std::string strServerDir; 172 std::string strFilename; 173 CFtpFileFind* pFtpFileFind = NULL; 174 int nRet = 0; 175 176 if(!this->Connect()) 177 { 178 nRet = -1; 179 goto __end; 180 } 181 else 182 { 183 while(!queServerDir.empty()) 184 { 185 strServerDir = queServerDir.front(); 186 queServerDir.pop(); 187 188 boost::filesystem::path LocalPath(m_strDownloadLocalDir); 189 if (!boost::filesystem::exists(LocalPath / strServerDir)) 190 { 191 this->CreateDirectory(LocalPath / strServerDir); 192 } 193 194 if (0 == m_pFtpConnection->SetCurrentDirectory(strServerDir.c_str())) 195 { 196 nRet = -1; 197 std::cout << "设置服务器下载目录[" << strServerDir << "]失败!ErrCode=" << GetLastError() << std::endl; 198 DWORD dw = 0; 199 char szBuf[512]={0}; 200 DWORD dwLen = sizeof(szBuf)-1; 201 InternetGetLastResponseInfo(&dw, szBuf, &dwLen); 202 std::cout << "错误信息:" << szBuf << std::endl; 203 goto __end; 204 } 205 if (pFtpFileFind == NULL) 206 { 207 pFtpFileFind = new CFtpFileFind(m_pFtpConnection); 208 } 209 210 int nRet = pFtpFileFind->FindFile(); 211 while(nRet) 212 { 213 nRet = pFtpFileFind->FindNextFile(); 214 strFilename = pFtpFileFind->GetFilePath(); 215 if (pFtpFileFind->IsDirectory()) 216 { 217 queServerDir.push(std::string(pFtpFileFind->GetFilePath())); 218 continue; 219 } 220 221 std::string strLocalFilename = m_strDownloadLocalDir + strFilename; 222 std::string strServerFilename = strFilename; 223 224 if(m_pFtpConnection->GetFile(strServerFilename.c_str(), strLocalFilename.c_str(), FALSE)) 225 std::cout << "下载文件[" << strServerFilename << "]到[" << strLocalFilename << "]成功!" << std::endl; 226 else 227 { 228 std::cout << "下载文件[" << strServerFilename << "]到[" << strLocalFilename << "]失败!" << std::endl; 229 char szBuf[512]={0}; 230 DWORD dw = 0; 231 DWORD dwLen = sizeof(szBuf)-1; 232 InternetGetLastResponseInfo(&dw, szBuf, &dwLen); 233 dw = GetLastError(); 234 std::cout << "错误信息:" << szBuf << std::endl; 235 nRet = -1; 236 } 237 } 238 } 239 } 240 __end: 241 this->Close(); 242 if (pFtpFileFind != NULL) 243 { 244 pFtpFileFind->Close(); 245 delete pFtpFileFind; 246 } 247 return nRet; 248 } 249 250 int CFtpClient::Upload(const std::string strLocalPath) 251 { 252 int nRet = 0; 253 CFtpFileFind* pFtpFileFind = NULL; 254 boost::filesystem::path localPath(strLocalPath); 255 256 if (m_bZibFlag) 257 {//文件夹先压缩再上传 258 if (boost::filesystem::exists(localPath)) 259 { 260 if (boost::filesystem::is_directory(localPath)) 261 { 262 std::string strUploadName = this->GetZipFolder(localPath.string()); 263 localPath = strUploadName;//改为上传压缩文件 264 } 265 } 266 else 267 { 268 std::cout << "指定上传文件不存在!" << std::endl; 269 nRet = -1; 270 goto __end; 271 } 272 } 273 274 275 //由于压缩大文件很耗时,为防止长时间占用FTP连接产生的异常,因此先压缩文件后连接上传。 276 if(!this->Connect()) 277 { 278 nRet = -1; 279 goto __end; 280 } 281 else 282 { 283 if (0 == m_pFtpConnection->SetCurrentDirectory(m_strUploadServerDir.c_str())) 284 { 285 nRet = -1; 286 std::cout << "设置服务器上传目录[" << m_strUploadServerDir << "]失败!ErrCode=" << GetLastError() << std::endl; 287 DWORD dw = 0; 288 char szBuf[512]={0}; 289 DWORD dwLen = sizeof(szBuf)-1; 290 InternetGetLastResponseInfo(&dw, szBuf, &dwLen); 291 std::cout << "错误信息:" << szBuf << std::endl; 292 goto __end; 293 } 294 295 if (boost::filesystem::exists(localPath)) 296 { 297 if (boost::filesystem::is_directory(localPath)) 298 { 299 m_pFtpConnection->CreateDirectory(localPath.leaf().string().c_str()); 300 301 //directory_iterator:只支持本层目录遍历 302 boost::filesystem::directory_iterator itor_begin(localPath); 303 boost::filesystem::directory_iterator itor_end; 304 305 std::string strServerDir = m_strUploadServerDir; 306 for (; itor_begin != itor_end; itor_begin++) 307 {//回溯算法 308 m_strUploadServerDir += std::string("\\") + localPath.leaf().string(); 309 this->Upload(itor_begin->path().string()); 310 m_strUploadServerDir = strServerDir; 311 } 312 313 } 314 else 315 { 316 if(m_pFtpConnection->PutFile(localPath.string().c_str(), localPath.leaf().string().c_str(), 317 FTP_TRANSFER_TYPE_BINARY,0)) 318 std::cout << "上传文件[" << localPath.leaf().string() << "]成功!" << std::endl; 319 else 320 { 321 DWORD dw0 = GetLastError(); 322 if (dw0) 323 { 324 char szBuf[512]={0}; 325 DWORD dw = 0; 326 DWORD dwLen = sizeof(szBuf)-1; 327 InternetGetLastResponseInfo(&dw, szBuf, &dwLen); 328 std::cout << "上传文件[" << localPath.leaf().string() << "]失败!ErrCode:" << dw0 << "ErrMsg:" << szBuf << std::endl; 329 goto __end; 330 } 331 } 332 } 333 } 334 else 335 { 336 std::cout << "指定上传文件不存在!" << std::endl; 337 nRet = -1; 338 goto __end; 339 } 340 } 341 342 __end: 343 if (pFtpFileFind != NULL) 344 { 345 pFtpFileFind->Close(); 346 delete pFtpFileFind; 347 } 348 this->Close(); 349 return nRet; 350 } 351 352 void CFtpClient::CreateDirectory(boost::filesystem::path path) 353 { 354 boost::filesystem::path::iterator itor = path.begin(); 355 boost::filesystem::path pathTmp; 356 while(itor != path.end()) 357 { 358 pathTmp /= (*itor).string(); 359 if (!pathTmp.empty() && !boost::filesystem::exists(pathTmp)) 360 { 361 boost::filesystem::create_directory(pathTmp); 362 } 363 ++itor; 364 } 365 } 366 367 std::string CFtpClient::GetZipFolder(const std::string strFolderPath) 368 { 369 boost::filesystem::path pathFolder(strFolderPath); 370 std::string strZipName = strFolderPath + ".zip"; 371 std::string strRootPath = pathFolder.branch_path().string(); 372 373 HZIP hz = CreateZip(strZipName.c_str(), 0); 374 this->MakeZipFolder(hz, strRootPath, strFolderPath); 375 CloseZip(hz); 376 377 return strZipName; 378 } 379 380 void CFtpClient::MakeZipFolder(HZIP hz, const std::string strRoot, const std::string strFolderPath) 381 { 382 boost::filesystem::path FolderPath(strFolderPath); 383 ZipAddFolder(hz, FolderPath.leaf().string().c_str()); 384 385 //recursive_directory_iterator:支持深层目录遍历 386 boost::filesystem::recursive_directory_iterator itor_begin(FolderPath); 387 boost::filesystem::recursive_directory_iterator itor_end; 388 389 for (; itor_begin != itor_end; itor_begin++) 390 { 391 std::cout << "正在压缩文件:" << itor_begin->path().string() << "......" << std::endl; 392 std::string strFilePath = itor_begin->path().string(); 393 int nPos = strFilePath.find(strRoot); 394 if (nPos != std::string::npos) 395 {//取得相对于压缩文件本身的路径 396 strFilePath = strFilePath.substr(nPos+strRoot.length()); 397 } 398 399 if (boost::filesystem::is_directory(*itor_begin)) 400 { 401 ZipAddFolder(hz, strFilePath.c_str()); 402 } 403 else 404 { 405 ZipAdd(hz, strFilePath.c_str(), itor_begin->path().string().c_str()); 406 } 407 } 408 }

zip.h

  1 #ifndef _zip_H
  2 #define _zip_H
  3 //
  4 #ifdef ZIP_STD
  5 #include <time.h>
  6 #define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
  7 #ifndef MAX_PATH
  8 #define MAX_PATH 1024
  9 #endif
 10 typedef unsigned long DWORD;
 11 typedef char TCHAR;
 12 typedef FILE* HANDLE;
 13 typedef time_t FILETIME;
 14 #endif
 15 
 16 // ZIP functions -- for creating zip files
 17 // This file is a repackaged form of the Info-Zip source code available
 18 // at www.info-zip.org. The original copyright notice may be found in
 19 // zip.cpp. The repackaging was done by Lucian Wischik to simplify and
 20 // extend its use in Windows/C++. Also to add encryption and unicode.
 21 
 22 
 23 #ifndef _unzip_H
 24 DECLARE_HANDLE(HZIP);
 25 #endif
 26 // An HZIP identifies a zip file that is being created
 27 
 28 typedef DWORD ZRESULT;
 29 // return codes from any of the zip functions. Listed later.
 30 
 31 
 32 
 33 HZIP CreateZip(const TCHAR *fn, const char *password);
 34 HZIP CreateZip(void *buf,unsigned int len, const char *password);
 35 HZIP CreateZipHandle(HANDLE h, const char *password);
 36 // CreateZip - call this to start the creation of a zip file.
 37 // As the zip is being created, it will be stored somewhere:
 38 // to a pipe:              CreateZipHandle(hpipe_write);
 39 // in a file (by handle):  CreateZipHandle(hfile);
 40 // in a file (by name):    CreateZip("c:\\test.zip");
 41 // in memory:              CreateZip(buf, len);
 42 // or in pagefile memory:  CreateZip(0, len);
 43 // The final case stores it in memory backed by the system paging file,
 44 // where the zip may not exceed len bytes. This is a bit friendlier than
 45 // allocating memory with new[]: it won't lead to fragmentation, and the
 46 // memory won't be touched unless needed. That means you can give very
 47 // large estimates of the maximum-size without too much worry.
 48 // As for the password, it lets you encrypt every file in the archive.
 49 // (This api doesn't support per-file encryption.)
 50 // Note: because pipes don't allow random access, the structure of a zipfile
 51 // created into a pipe is slightly different from that created into a file
 52 // or memory. In particular, the compressed-size of the item cannot be
 53 // stored in the zipfile until after the item itself. (Also, for an item added
 54 // itself via a pipe, the uncompressed-size might not either be known until
 55 // after.) This is not normally a problem. But if you try to unzip via a pipe
 56 // as well, then the unzipper will not know these things about the item until
 57 // after it has been unzipped. Therefore: for unzippers which don't just write
 58 // each item to disk or to a pipe, but instead pre-allocate memory space into
 59 // which to unzip them, then either you have to create the zip not to a pipe,
 60 // or you have to add items not from a pipe, or at least when adding items
 61 // from a pipe you have to specify the length.
 62 // Note: for windows-ce, you cannot close the handle until after CloseZip.
 63 // but for real windows, the zip makes its own copy of your handle, so you
 64 // can close yours anytime.
 65 
 66 
 67 ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn);
 68 ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len);
 69 ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h);
 70 ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len);
 71 ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn);
 72 // ZipAdd - call this for each file to be added to the zip.
 73 // dstzn is the name that the file will be stored as in the zip file.
 74 // The file to be added to the zip can come
 75 // from a pipe:  ZipAddHandle(hz,"file.dat", hpipe_read);
 76 // from a file:  ZipAddHandle(hz,"file.dat", hfile);
 77 // from a filen: ZipAdd(hz,"file.dat", "c:\\docs\\origfile.dat");
 78 // from memory:  ZipAdd(hz,"subdir\\file.dat", buf,len);
 79 // (folder):     ZipAddFolder(hz,"subdir");
 80 // Note: if adding an item from a pipe, and if also creating the zip file itself
 81 // to a pipe, then you might wish to pass a non-zero length to the ZipAddHandle
 82 // function. This will let the zipfile store the item's size ahead of the
 83 // compressed item itself, which in turn makes it easier when unzipping the
 84 // zipfile from a pipe.
 85 
 86 ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len);
 87 // ZipGetMemory - If the zip was created in memory, via ZipCreate(0,len),
 88 // then this function will return information about that memory block.
 89 // buf will receive a pointer to its start, and len its length.
 90 // Note: you can't add any more after calling this.
 91 
 92 ZRESULT CloseZip(HZIP hz);
 93 // CloseZip - the zip handle must be closed with this function.
 94 
 95 unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len);
 96 // FormatZipMessage - given an error code, formats it as a string.
 97 // It returns the length of the error message. If buf/len points
 98 // to a real buffer, then it also writes as much as possible into there.
 99 
100 
101 
102 // These are the result codes:
103 #define ZR_OK         0x00000000     // nb. the pseudo-code zr-recent is never returned,
104 #define ZR_RECENT     0x00000001     // but can be passed to FormatZipMessage.
105 // The following come from general system stuff (e.g. files not openable)
106 #define ZR_GENMASK    0x0000FF00
107 #define ZR_NODUPH     0x00000100     // couldn't duplicate the handle
108 #define ZR_NOFILE     0x00000200     // couldn't create/open the file
109 #define ZR_NOALLOC    0x00000300     // failed to allocate some resource
110 #define ZR_WRITE      0x00000400     // a general error writing to the file
111 #define ZR_NOTFOUND   0x00000500     // couldn't find that file in the zip
112 #define ZR_MORE       0x00000600     // there's still more data to be unzipped
113 #define ZR_CORRUPT    0x00000700     // the zipfile is corrupt or not a zipfile
114 #define ZR_READ       0x00000800     // a general error reading the file
115 // The following come from mistakes on the part of the caller
116 #define ZR_CALLERMASK 0x00FF0000
117 #define ZR_ARGS       0x00010000     // general mistake with the arguments
118 #define ZR_NOTMMAP    0x00020000     // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
119 #define ZR_MEMSIZE    0x00030000     // the memory size is too small
120 #define ZR_FAILED     0x00040000     // the thing was already failed when you called this function
121 #define ZR_ENDED      0x00050000     // the zip creation has already been closed
122 #define ZR_MISSIZE    0x00060000     // the indicated input file size turned out mistaken
123 #define ZR_PARTIALUNZ 0x00070000     // the file had already been partially unzipped
124 #define ZR_ZMODE      0x00080000     // tried to mix creating/opening a zip 
125 // The following come from bugs within the zip library itself
126 #define ZR_BUGMASK    0xFF000000
127 #define ZR_NOTINITED  0x01000000     // initialisation didn't work
128 #define ZR_SEEK       0x02000000     // trying to seek in an unseekable file
129 #define ZR_NOCHANGE   0x04000000     // changed its mind on storage, but not allowed
130 #define ZR_FLATE      0x05000000     // an internal error in the de/inflation code
131 
132 
133 
134 
135 
136 
137 // e.g.
138 //
139 // (1) Traditional use, creating a zipfile from existing files
140 //     HZIP hz = CreateZip("c:\\simple1.zip",0);
141 //     ZipAdd(hz,"znsimple.bmp", "c:\\simple.bmp");
142 //     ZipAdd(hz,"znsimple.txt", "c:\\simple.txt");
143 //     CloseZip(hz);
144 //
145 // (2) Memory use, creating an auto-allocated mem-based zip file from various sources
146 //     HZIP hz = CreateZip(0,100000, 0);
147 //     // adding a conventional file...
148 //     ZipAdd(hz,"src1.txt",  "c:\\src1.txt");
149 //     // adding something from memory...
150 //     char buf[1000]; for (int i=0; i<1000; i++) buf[i]=(char)(i&0x7F);
151 //     ZipAdd(hz,"file.dat",  buf,1000);
152 //     // adding something from a pipe...
153 //     HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,NULL,0);
154 //     HANDLE hthread = CreateThread(0,0,ThreadFunc,(void*)hwrite,0,0);
155 //     ZipAdd(hz,"unz3.dat",  hread,1000);  // the '1000' is optional.
156 //     WaitForSingleObject(hthread,INFINITE);
157 //     CloseHandle(hthread); CloseHandle(hread);
158 //     ... meanwhile DWORD WINAPI ThreadFunc(void *dat)
159 //                   { HANDLE hwrite = (HANDLE)dat;
160 //                     char buf[1000]={17};
161 //                     DWORD writ; WriteFile(hwrite,buf,1000,&writ,NULL);
162 //                     CloseHandle(hwrite);
163 //                     return 0;
164 //                   }
165 //     // and now that the zip is created, let's do something with it:
166 //     void *zbuf; unsigned long zlen; ZipGetMemory(hz,&zbuf,&zlen);
167 //     HANDLE hfz = CreateFile("test2.zip",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
168 //     DWORD writ; WriteFile(hfz,zbuf,zlen,&writ,NULL);
169 //     CloseHandle(hfz);
170 //     CloseZip(hz);
171 //
172 // (3) Handle use, for file handles and pipes
173 //     HANDLE hzread,hzwrite; CreatePipe(&hzread,&hzwrite,0,0);
174 //     HANDLE hthread = CreateThread(0,0,ZipReceiverThread,(void*)hzread,0,0);
175 //     HZIP hz = CreateZipHandle(hzwrite,0);
176 //     // ... add to it
177 //     CloseZip(hz);
178 //     CloseHandle(hzwrite);
179 //     WaitForSingleObject(hthread,INFINITE);
180 //     CloseHandle(hthread);
181 //     ... meanwhile DWORD WINAPI ZipReceiverThread(void *dat)
182 //                   { HANDLE hread = (HANDLE)dat;
183 //                     char buf[1000];
184 //                     while (true)
185 //                     { DWORD red; ReadFile(hread,buf,1000,&red,NULL);
186 //                       // ... and do something with this zip data we're receiving
187 //                       if (red==0) break;
188 //                     }
189 //                     CloseHandle(hread);
190 //                     return 0;
191 //                   }
192 
193 
194 
195 // Now we indulge in a little skullduggery so that the code works whether
196 // the user has included just zip or both zip and unzip.
197 // Idea: if header files for both zip and unzip are present, then presumably
198 // the cpp files for zip and unzip are both present, so we will call
199 // one or the other of them based on a dynamic choice. If the header file
200 // for only one is present, then we will bind to that particular one.
201 ZRESULT CloseZipZ(HZIP hz);
202 unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len);
203 bool IsZipHandleZ(HZIP hz);
204 #ifdef _unzip_H
205 #undef CloseZip
206 #define CloseZip(hz) (IsZipHandleZ(hz)?CloseZipZ(hz):CloseZipU(hz))
207 #else
208 #define CloseZip CloseZipZ
209 #define FormatZipMessage FormatZipMessageZ
210 #endif
211 
212 
213 
214 #endif
View Code

zip.cpp

   1 #ifdef ZIP_STD
   2 #include <stdio.h>
   3 #include <stdlib.h>
   4 #include <stdarg.h>
   5 #include <time.h>
   6 #include <sys/types.h>
   7 #include <sys/stat.h>
   8 #include <memory.h>
   9 #include <string.h>
  10 #include <ctype.h>
  11 
  12 #include "zip.h"
  13 //
  14 typedef unsigned short WORD;
  15 #define _tcslen strlen
  16 #define _tcsicmp stricmp
  17 #define _tcsncpy strncpy
  18 #define _tcsstr strstr
  19 #define INVALID_HANDLE_VALUE 0
  20 #ifndef _T
  21 #define _T(s) s
  22 #endif
  23 #ifndef S_IWUSR
  24 #define S_IWUSR 0000200
  25 #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
  26 #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
  27 #endif
  28 
  29 //
  30 #else
  31 #include <windows.h>
  32 #include <tchar.h>
  33 #include <ctype.h>
  34 #include <stdio.h>
  35 #include "zip.h"
  36 #endif
  37 
  38 
  39 // THIS FILE is almost entirely based upon code by info-zip.
  40 // It has been modified by Lucian Wischik. The modifications
  41 // were a complete rewrite of the bit of code that generates the
  42 // layout of the zipfile, and support for zipping to/from memory
  43 // or handles or pipes or pagefile or diskfiles, encryption, unicode.
  44 // The original code may be found at http://www.info-zip.org
  45 // The original copyright text follows.
  46 //
  47 //
  48 //
  49 // This is version 1999-Oct-05 of the Info-ZIP copyright and license.
  50 // The definitive version of this document should be available at
  51 // ftp://ftp.cdrom.com/pub/infozip/license.html indefinitely.
  52 //
  53 // Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
  54 //
  55 // For the purposes of this copyright and license, "Info-ZIP" is defined as
  56 // the following set of individuals:
  57 //
  58 //   Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
  59 //   Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase,
  60 //   Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David Kirschbaum,
  61 //   Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve P. Miller,
  62 //   Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, Kai Uwe Rommel,
  63 //   Steve Salisbury, Dave Smith, Christian Spieler, Antoine Verheijen,
  64 //   Paul von Behren, Rich Wales, Mike White
  65 //
  66 // This software is provided "as is," without warranty of any kind, express
  67 // or implied.  In no event shall Info-ZIP or its contributors be held liable
  68 // for any direct, indirect, incidental, special or consequential damages
  69 // arising out of the use of or inability to use this software.
  70 //
  71 // Permission is granted to anyone to use this software for any purpose,
  72 // including commercial applications, and to alter it and redistribute it
  73 // freely, subject to the following restrictions:
  74 //
  75 //    1. Redistributions of source code must retain the above copyright notice,
  76 //       definition, disclaimer, and this list of conditions.
  77 //
  78 //    2. Redistributions in binary form must reproduce the above copyright
  79 //       notice, definition, disclaimer, and this list of conditions in
  80 //       documentation and/or other materials provided with the distribution.
  81 //
  82 //    3. Altered versions--including, but not limited to, ports to new operating
  83 //       systems, existing ports with new graphical interfaces, and dynamic,
  84 //       shared, or static library versions--must be plainly marked as such
  85 //       and must not be misrepresented as being the original source.  Such
  86 //       altered versions also must not be misrepresented as being Info-ZIP
  87 //       releases--including, but not limited to, labeling of the altered
  88 //       versions with the names "Info-ZIP" (or any variation thereof, including,
  89 //       but not limited to, different capitalizations), "Pocket UnZip," "WiZ"
  90 //       or "MacZip" without the explicit permission of Info-ZIP.  Such altered
  91 //       versions are further prohibited from misrepresentative use of the
  92 //       Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s).
  93 //
  94 //    4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
  95 //       "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its own source and
  96 //       binary releases.
  97 //
  98 
  99 
 100 typedef unsigned char uch;      // unsigned 8-bit value
 101 typedef unsigned short ush;     // unsigned 16-bit value
 102 typedef unsigned long ulg;      // unsigned 32-bit value
 103 typedef size_t extent;          // file size
 104 typedef unsigned Pos;   // must be at least 32 bits
 105 typedef unsigned IPos; // A Pos is an index in the character window. Pos is used only for parameter passing
 106 
 107 #ifndef EOF
 108 #define EOF (-1)
 109 #endif
 110 
 111 
 112 
 113 
 114 
 115 
 116 // Error return values.  The values 0..4 and 12..18 follow the conventions
 117 // of PKZIP.   The values 4..10 are all assigned to "insufficient memory"
 118 // by PKZIP, so the codes 5..10 are used here for other purposes.
 119 #define ZE_MISS         -1      // used by procname(), zipbare()
 120 #define ZE_OK           0       // success
 121 #define ZE_EOF          2       // unexpected end of zip file
 122 #define ZE_FORM         3       // zip file structure error
 123 #define ZE_MEM          4       // out of memory
 124 #define ZE_LOGIC        5       // internal logic error
 125 #define ZE_BIG          6       // entry too large to split
 126 #define ZE_NOTE         7       // invalid comment format
 127 #define ZE_TEST         8       // zip test (-T) failed or out of memory
 128 #define ZE_ABORT        9       // user interrupt or termination
 129 #define ZE_TEMP         10      // error using a temp file
 130 #define ZE_READ         11      // read or seek error
 131 #define ZE_NONE         12      // nothing to do
 132 #define ZE_NAME         13      // missing or empty zip file
 133 #define ZE_WRITE        14      // error writing to a file
 134 #define ZE_CREAT        15      // couldn't open to write
 135 #define ZE_PARMS        16      // bad command line
 136 #define ZE_OPEN         18      // could not open a specified file to read
 137 #define ZE_MAXERR       18      // the highest error number
 138 
 139 
 140 // internal file attribute
 141 #define UNKNOWN (-1)
 142 #define BINARY  0
 143 #define ASCII   1
 144 
 145 #define BEST -1                 // Use best method (deflation or store)
 146 #define STORE 0                 // Store method
 147 #define DEFLATE 8               // Deflation method
 148 
 149 #define CRCVAL_INITIAL  0L
 150 
 151 // MSDOS file or directory attributes
 152 #define MSDOS_HIDDEN_ATTR 0x02
 153 #define MSDOS_DIR_ATTR 0x10
 154 
 155 // Lengths of headers after signatures in bytes
 156 #define LOCHEAD 26
 157 #define CENHEAD 42
 158 #define ENDHEAD 18
 159 
 160 // Definitions for extra field handling:
 161 #define EB_HEADSIZE       4     /* length of a extra field block header */
 162 #define EB_LEN            2     /* offset of data length field in header */
 163 #define EB_UT_MINLEN      1     /* minimal UT field contains Flags byte */
 164 #define EB_UT_FLAGS       0     /* byte offset of Flags field */
 165 #define EB_UT_TIME1       1     /* byte offset of 1st time value */
 166 #define EB_UT_FL_MTIME    (1 << 0)      /* mtime present */
 167 #define EB_UT_FL_ATIME    (1 << 1)      /* atime present */
 168 #define EB_UT_FL_CTIME    (1 << 2)      /* ctime present */
 169 #define EB_UT_LEN(n)      (EB_UT_MINLEN + 4 * (n))
 170 #define EB_L_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(3))
 171 #define EB_C_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(1))
 172 
 173 
 174 // Macros for writing machine integers to little-endian format
 175 #define PUTSH(a,f) {char _putsh_c=(char)((a)&0xff); wfunc(param,&_putsh_c,1); _putsh_c=(char)((a)>>8); wfunc(param,&_putsh_c,1);}
 176 #define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))}
 177 
 178 
 179 // -- Structure of a ZIP file --
 180 // Signatures for zip file information headers
 181 #define LOCSIG     0x04034b50L
 182 #define CENSIG     0x02014b50L
 183 #define ENDSIG     0x06054b50L
 184 #define EXTLOCSIG  0x08074b50L
 185 
 186 
 187 #define MIN_MATCH  3
 188 #define MAX_MATCH  258
 189 // The minimum and maximum match lengths
 190 
 191 
 192 #define WSIZE  (0x8000)
 193 // Maximum window size = 32K. If you are really short of memory, compile
 194 // with a smaller WSIZE but this reduces the compression ratio for files
 195 // of size > WSIZE. WSIZE must be a power of two in the current implementation.
 196 //
 197 
 198 #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
 199 // Minimum amount of lookahead, except at the end of the input file.
 200 // See deflate.c for comments about the MIN_MATCH+1.
 201 //
 202 
 203 #define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
 204 // In order to simplify the code, particularly on 16 bit machines, match
 205 // distances are limited to MAX_DIST instead of WSIZE.
 206 //
 207 
 208 
 209 #define ZIP_HANDLE   1
 210 #define ZIP_FILENAME 2
 211 #define ZIP_MEMORY   3
 212 #define ZIP_FOLDER   4
 213 
 214 
 215 
 216 // ===========================================================================
 217 // Constants
 218 //
 219 
 220 #define MAX_BITS 15
 221 // All codes must not exceed MAX_BITS bits
 222 
 223 #define MAX_BL_BITS 7
 224 // Bit length codes must not exceed MAX_BL_BITS bits
 225 
 226 #define LENGTH_CODES 29
 227 // number of length codes, not counting the special END_BLOCK code
 228 
 229 #define LITERALS  256
 230 // number of literal bytes 0..255
 231 
 232 #define END_BLOCK 256
 233 // end of block literal code
 234 
 235 #define L_CODES (LITERALS+1+LENGTH_CODES)
 236 // number of Literal or Length codes, including the END_BLOCK code
 237 
 238 #define D_CODES   30
 239 // number of distance codes
 240 
 241 #define BL_CODES  19
 242 // number of codes used to transfer the bit lengths
 243 
 244 
 245 #define STORED_BLOCK 0
 246 #define STATIC_TREES 1
 247 #define DYN_TREES    2
 248 // The three kinds of block type
 249 
 250 #define LIT_BUFSIZE  0x8000
 251 #define DIST_BUFSIZE  LIT_BUFSIZE
 252 // Sizes of match buffers for literals/lengths and distances.  There are
 253 // 4 reasons for limiting LIT_BUFSIZE to 64K:
 254 //   - frequencies can be kept in 16 bit counters
 255 //   - if compression is not successful for the first block, all input data is
 256 //     still in the window so we can still emit a stored block even when input
 257 //     comes from standard input.  (This can also be done for all blocks if
 258 //     LIT_BUFSIZE is not greater than 32K.)
 259 //   - if compression is not successful for a file smaller than 64K, we can
 260 //     even emit a stored file instead of a stored block (saving 5 bytes).
 261 //   - creating new Huffman trees less frequently may not provide fast
 262 //     adaptation to changes in the input data statistics. (Take for
 263 //     example a binary file with poorly compressible code followed by
 264 //     a highly compressible string table.) Smaller buffer sizes give
 265 //     fast adaptation but have of course the overhead of transmitting trees
 266 //     more frequently.
 267 //   - I can't count above 4
 268 // The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
 269 // memory at the expense of compression). Some optimizations would be possible
 270 // if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
 271 //
 272 
 273 #define REP_3_6      16
 274 // repeat previous bit length 3-6 times (2 bits of repeat count)
 275 
 276 #define REPZ_3_10    17
 277 // repeat a zero length 3-10 times  (3 bits of repeat count)
 278 
 279 #define REPZ_11_138  18
 280 // repeat a zero length 11-138 times  (7 bits of repeat count)
 281 
 282 #define HEAP_SIZE (2*L_CODES+1)
 283 // maximum heap size
 284 
 285 
 286 // ===========================================================================
 287 // Local data used by the "bit string" routines.
 288 //
 289 
 290 #define Buf_size (8 * 2*sizeof(char))
 291 // Number of bits used within bi_buf. (bi_buf may be implemented on
 292 // more than 16 bits on some systems.)
 293 
 294 // Output a 16 bit value to the bit stream, lower (oldest) byte first
 295 #define PUTSHORT(state,w) \
 296 { if (state.bs.out_offset >= state.bs.out_size-1) \
 297     state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \
 298   state.bs.out_buf[state.bs.out_offset++] = (char) ((w) & 0xff); \
 299   state.bs.out_buf[state.bs.out_offset++] = (char) ((ush)(w) >> 8); \
 300 }
 301 
 302 #define PUTBYTE(state,b) \
 303 { if (state.bs.out_offset >= state.bs.out_size) \
 304     state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \
 305   state.bs.out_buf[state.bs.out_offset++] = (char) (b); \
 306 }
 307 
 308 // DEFLATE.CPP HEADER
 309 
 310 #define HASH_BITS  15
 311 // For portability to 16 bit machines, do not use values above 15.
 312 
 313 #define HASH_SIZE (unsigned)(1<<HASH_BITS)
 314 #define HASH_MASK (HASH_SIZE-1)
 315 #define WMASK     (WSIZE-1)
 316 // HASH_SIZE and WSIZE must be powers of two
 317 
 318 #define NIL 0
 319 // Tail of hash chains
 320 
 321 #define FAST 4
 322 #define SLOW 2
 323 // speed options for the general purpose bit flag
 324 
 325 #define TOO_FAR 4096
 326 // Matches of length 3 are discarded if their distance exceeds TOO_FAR
 327 
 328 
 329 
 330 #define EQUAL 0
 331 // result of memcmp for equal strings
 332 
 333 
 334 // ===========================================================================
 335 // Local data used by the "longest match" routines.
 336 
 337 #define H_SHIFT  ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
 338 // Number of bits by which ins_h and del_h must be shifted at each
 339 // input step. It must be such that after MIN_MATCH steps, the oldest
 340 // byte no longer takes part in the hash key, that is:
 341 //   H_SHIFT * MIN_MATCH >= HASH_BITS
 342 
 343 #define max_insert_length  max_lazy_match
 344 // Insert new strings in the hash table only if the match length
 345 // is not greater than this length. This saves time but degrades compression.
 346 // max_insert_length is used only for compression levels <= 3.
 347 
 348 
 349 
 350 const int extra_lbits[LENGTH_CODES] // extra bits for each length code
 351    = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
 352 
 353 const int extra_dbits[D_CODES] // extra bits for each distance code
 354    = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
 355 
 356 const int extra_blbits[BL_CODES]// extra bits for each bit length code
 357    = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
 358 
 359 const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
 360 // The lengths of the bit length codes are sent in order of decreasing
 361 // probability, to avoid transmitting the lengths for unused bit length codes.
 362 
 363 
 364 typedef struct config {
 365    ush good_length; // reduce lazy search above this match length
 366    ush max_lazy;    // do not perform lazy search above this match length
 367    ush nice_length; // quit search above this match length
 368    ush max_chain;
 369 } config;
 370 
 371 // Values for max_lazy_match, good_match, nice_match and max_chain_length,
 372 // depending on the desired pack level (0..9). The values given below have
 373 // been tuned to exclude worst case performance for pathological files.
 374 // Better values may be found for specific files.
 375 //
 376 
 377 const config configuration_table[10] = {
 378 //  good lazy nice chain
 379     {0,    0,  0,    0},  // 0 store only
 380     {4,    4,  8,    4},  // 1 maximum speed, no lazy matches
 381     {4,    5, 16,    8},  // 2
 382     {4,    6, 32,   32},  // 3
 383     {4,    4, 16,   16},  // 4 lazy matches */
 384     {8,   16, 32,   32},  // 5
 385     {8,   16, 128, 128},  // 6
 386     {8,   32, 128, 256},  // 7
 387     {32, 128, 258, 1024}, // 8
 388     {32, 258, 258, 4096}};// 9 maximum compression */
 389 
 390 // Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
 391 // For deflate_fast() (levels <= 3) good is ignored and lazy has a different meaning.
 392 
 393 
 394 
 395 
 396 
 397 
 398 
 399 // Data structure describing a single value and its code string.
 400 typedef struct ct_data {
 401     union {
 402         ush  freq;       // frequency count
 403         ush  code;       // bit string
 404     } fc;
 405     union {
 406         ush  dad;        // father node in Huffman tree
 407         ush  len;        // length of bit string
 408     } dl;
 409 } ct_data;
 410 
 411 typedef struct tree_desc {
 412     ct_data *dyn_tree;      // the dynamic tree
 413     ct_data *static_tree;   // corresponding static tree or NULL
 414     const int *extra_bits;  // extra bits for each code or NULL
 415     int     extra_base;     // base index for extra_bits
 416     int     elems;          // max number of elements in the tree
 417     int     max_length;     // max bit length for the codes
 418     int     max_code;       // largest code with non zero frequency
 419 } tree_desc;
 420 
 421 
 422 
 423 
 424 class TTreeState
 425 { public:
 426   TTreeState();
 427 
 428   ct_data dyn_ltree[HEAP_SIZE];    // literal and length tree
 429   ct_data dyn_dtree[2*D_CODES+1];  // distance tree
 430   ct_data static_ltree[L_CODES+2]; // the static literal tree...
 431   // ... Since the bit lengths are imposed, there is no need for the L_CODES
 432   // extra codes used during heap construction. However the codes 286 and 287
 433   // are needed to build a canonical tree (see ct_init below).
 434   ct_data static_dtree[D_CODES]; // the static distance tree...
 435   // ... (Actually a trivial tree since all codes use 5 bits.)
 436   ct_data bl_tree[2*BL_CODES+1];  // Huffman tree for the bit lengths
 437 
 438   tree_desc l_desc;
 439   tree_desc d_desc;
 440   tree_desc bl_desc;
 441 
 442   ush bl_count[MAX_BITS+1];  // number of codes at each bit length for an optimal tree
 443 
 444   int heap[2*L_CODES+1]; // heap used to build the Huffman trees
 445   int heap_len;               // number of elements in the heap
 446   int heap_max;               // element of largest frequency
 447   // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
 448   // The same heap array is used to build all trees.
 449 
 450   uch depth[2*L_CODES+1];
 451   // Depth of each subtree used as tie breaker for trees of equal frequency
 452 
 453   uch length_code[MAX_MATCH-MIN_MATCH+1];
 454   // length code for each normalized match length (0 == MIN_MATCH)
 455 
 456   uch dist_code[512];
 457   // distance codes. The first 256 values correspond to the distances
 458   // 3 .. 258, the last 256 values correspond to the top 8 bits of
 459   // the 15 bit distances.
 460 
 461   int base_length[LENGTH_CODES];
 462   // First normalized length for each code (0 = MIN_MATCH)
 463 
 464   int base_dist[D_CODES];
 465   // First normalized distance for each code (0 = distance of 1)
 466 
 467   uch l_buf[LIT_BUFSIZE];  // buffer for literals/lengths
 468   ush d_buf[DIST_BUFSIZE]; // buffer for distances
 469 
 470   uch flag_buf[(LIT_BUFSIZE/8)];
 471   // flag_buf is a bit array distinguishing literals from lengths in
 472   // l_buf, and thus indicating the presence or absence of a distance.
 473 
 474   unsigned last_lit;    // running index in l_buf
 475   unsigned last_dist;   // running index in d_buf
 476   unsigned last_flags;  // running index in flag_buf
 477   uch flags;            // current flags not yet saved in flag_buf
 478   uch flag_bit;         // current bit used in flags
 479   // bits are filled in flags starting at bit 0 (least significant).
 480   // Note: these flags are overkill in the current code since we don't
 481   // take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
 482 
 483   ulg opt_len;          // bit length of current block with optimal trees
 484   ulg static_len;       // bit length of current block with static trees
 485 
 486   ulg cmpr_bytelen;     // total byte length of compressed file
 487   ulg cmpr_len_bits;    // number of bits past 'cmpr_bytelen'
 488 
 489   ulg input_len;        // total byte length of input file
 490   // input_len is for debugging only since we can get it by other means.
 491 
 492   ush *file_type;       // pointer to UNKNOWN, BINARY or ASCII
 493 //  int *file_method;     // pointer to DEFLATE or STORE
 494 };
 495 
 496 TTreeState::TTreeState()
 497 { tree_desc a = {dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};  l_desc = a;
 498   tree_desc b = {dyn_dtree, static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS, 0};  d_desc = b;
 499   tree_desc c = {bl_tree, NULL,       extra_blbits, 0,         BL_CODES, MAX_BL_BITS, 0};  bl_desc = c;
 500   last_lit=0;
 501   last_dist=0;
 502   last_flags=0;
 503 }
 504 
 505 
 506 
 507 class TBitState
 508 { public:
 509 
 510   int flush_flg;
 511   //
 512   unsigned bi_buf;
 513   // Output buffer. bits are inserted starting at the bottom (least significant
 514   // bits). The width of bi_buf must be at least 16 bits.
 515   int bi_valid;
 516   // Number of valid bits in bi_buf.  All bits above the last valid bit
 517   // are always zero.
 518   char *out_buf;
 519   // Current output buffer.
 520   unsigned out_offset;
 521   // Current offset in output buffer.
 522   // On 16 bit machines, the buffer is limited to 64K.
 523   unsigned out_size;
 524   // Size of current output buffer
 525   ulg bits_sent;   // bit length of the compressed data  only needed for debugging???
 526 };
 527 
 528 
 529 
 530 
 531 
 532 
 533 
 534 class TDeflateState
 535 { public:
 536   TDeflateState() {window_size=0;}
 537 
 538   uch    window[2L*WSIZE];
 539   // Sliding window. Input bytes are read into the second half of the window,
 540   // and move to the first half later to keep a dictionary of at least WSIZE
 541   // bytes. With this organization, matches are limited to a distance of
 542   // WSIZE-MAX_MATCH bytes, but this ensures that IO is always
 543   // performed with a length multiple of the block size. Also, it limits
 544   // the window size to 64K, which is quite useful on MSDOS.
 545   // To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would
 546   // be less efficient since the data would have to be copied WSIZE/CBSZ times)
 547   Pos    prev[WSIZE];
 548   // Link to older string with same hash index. To limit the size of this
 549   // array to 64K, this link is maintained only for the last 32K strings.
 550   // An index in this array is thus a window index modulo 32K.
 551   Pos    head[HASH_SIZE];
 552   // Heads of the hash chains or NIL. If your compiler thinks that
 553   // HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC.
 554 
 555   ulg window_size;
 556   // window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
 557   // input file length plus MIN_LOOKAHEAD.
 558 
 559   long block_start;
 560   // window position at the beginning of the current output block. Gets
 561   // negative when the window is moved backwards.
 562 
 563   int sliding;
 564   // Set to false when the input file is already in memory
 565 
 566   unsigned ins_h;  // hash index of string to be inserted
 567 
 568   unsigned int prev_length;
 569   // Length of the best match at previous step. Matches not greater than this
 570   // are discarded. This is used in the lazy match evaluation.
 571 
 572   unsigned strstart;         // start of string to insert
 573   unsigned match_start; // start of matching string
 574   int      eofile;           // flag set at end of input file
 575   unsigned lookahead;        // number of valid bytes ahead in window
 576 
 577   unsigned max_chain_length;
 578   // To speed up deflation, hash chains are never searched beyond this length.
 579   // A higher limit improves compression ratio but degrades the speed.
 580 
 581   unsigned int max_lazy_match;
 582   // Attempt to find a better match only when the current match is strictly
 583   // smaller than this value. This mechanism is used only for compression
 584   // levels >= 4.
 585 
 586   unsigned good_match;
 587   // Use a faster search when the previous match is longer than this
 588 
 589   int nice_match; // Stop searching when current match exceeds this
 590 };
 591 
 592 typedef long lutime_t;       // define it ourselves since we don't include time.h
 593 
 594 typedef struct iztimes {
 595   lutime_t atime,mtime,ctime;
 596 } iztimes; // access, modify, create times
 597 
 598 typedef struct zlist {
 599   ush vem, ver, flg, how;       // See central header in zipfile.c for what vem..off are
 600   ulg tim, crc, siz, len;
 601   extent nam, ext, cext, com;   // offset of ext must be >= LOCHEAD
 602   ush dsk, att, lflg;           // offset of lflg must be >= LOCHEAD
 603   ulg atx, off;
 604   char name[MAX_PATH];          // File name in zip file
 605   char *extra;                  // Extra field (set only if ext != 0)
 606   char *cextra;                 // Extra in central (set only if cext != 0)
 607   char *comment;                // Comment (set only if com != 0)
 608   char iname[MAX_PATH];         // Internal file name after cleanup
 609   char zname[MAX_PATH];         // External version of internal name
 610   int mark;                     // Marker for files to operate on
 611   int trash;                    // Marker for files to delete
 612   int dosflag;                  // Set to force MSDOS file attributes
 613   struct zlist *nxt;        // Pointer to next header in list
 614 } TZipFileInfo;
 615 
 616 
 617 struct TState;
 618 typedef unsigned (*READFUNC)(TState &state, char *buf,unsigned size);
 619 typedef unsigned (*FLUSHFUNC)(void *param, const char *buf, unsigned *size);
 620 typedef unsigned (*WRITEFUNC)(void *param, const char *buf, unsigned size);
 621 struct TState
 622 { void *param;
 623   int level; bool seekable;
 624   READFUNC readfunc; FLUSHFUNC flush_outbuf;
 625   TTreeState ts; TBitState bs; TDeflateState ds;
 626   const char *err;
 627 };
 628 
 629 
 630 
 631 
 632 // ----------------------------------------------------------------------
 633 // some windows<->linux portability things
 634 #ifdef ZIP_STD
 635 void filetime2dosdatetime(const FILETIME ft, WORD *dosdate, WORD *dostime)
 636 { struct tm *st=gmtime(&ft);
 637   *dosdate = (ush)(((st->tm_year+1900 -1980)&0x7f) << 9);
 638   *dosdate |= (ush)((st->tm_mon&0xf) << 5);
 639   *dosdate |= (ush)((st->tm_mday&0x1f));
 640   *dostime = (ush)((st->tm_hour&0x1f) << 11);
 641   *dostime |= (ush)((st->tm_min&0x3f) << 5);
 642   *dostime |= (ush)((st->tm_sec*2)&0x1f);
 643 }
 644 
 645 void GetNow(lutime_t *ft, WORD *dosdate, WORD *dostime)
 646 { time_t tm = time(0);
 647   filetime2dosdatetime(tm,dosdate,dostime);
 648   *ft = (lutime_t)tm;
 649 }
 650 
 651 DWORD GetFilePosZ(HANDLE hfout)
 652 { struct stat st; fstat(fileno(hfout),&st); 
 653   if ((st.st_mode&S_IFREG)==0) return 0xFFFFFFFF;
 654   return ftell(hfout);
 655 }
 656 
 657 ZRESULT GetFileInfo(FILE *hf, ulg *attr, long *size, iztimes *times, ulg *timestamp)
 658 { // The handle must be a handle to a file
 659   // The date and time is returned in a long with the date most significant to allow
 660   // unsigned integer comparison of absolute times. The attributes have two
 661   // high bytes unix attr, and two low bytes a mapping of that to DOS attr.
 662   struct stat bhi; int res=fstat(fileno(hf),&bhi); if (res==-1) return ZR_NOFILE;
 663   ulg fa=bhi.st_mode; ulg a=0;
 664   // Zip uses the lower word for its interpretation of windows stuff
 665   if ((fa&S_IWUSR)==0) a|=0x01;
 666   if (S_ISDIR(fa)) a|=0x10;
 667   // It uses the upper word for standard unix attr
 668   a |= ((fa&0xFFFF)<<16);
 669   //
 670   if (attr!=NULL) *attr = a;
 671   if (size!=NULL) *size = bhi.st_size;
 672   if (times!=NULL)
 673   { times->atime = (lutime_t)bhi.st_atime;
 674     times->mtime = (lutime_t)bhi.st_mtime;
 675     times->ctime = (lutime_t)bhi.st_ctime;
 676   }
 677   if (timestamp!=NULL)
 678   { ush dosdate,dostime;
 679     filetime2dosdatetime(bhi.st_mtime,&dosdate,&dostime);
 680     *timestamp = (ush)dostime | (((ulg)dosdate)<<16);
 681   }
 682   return ZR_OK;
 683 }
 684 
 685 
 686 // ----------------------------------------------------------------------
 687 #else
 688 void filetime2dosdatetime(const FILETIME ft, WORD *dosdate,WORD *dostime)
 689 { // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980
 690   // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23
 691   SYSTEMTIME st; FileTimeToSystemTime(&ft,&st);
 692   *dosdate = (WORD)(((st.wYear-1980)&0x7f) << 9);
 693   *dosdate |= (WORD)((st.wMonth&0xf) << 5);
 694   *dosdate |= (WORD)((st.wDay&0x1f));
 695   *dostime = (WORD)((st.wHour&0x1f) << 11);
 696   *dostime |= (WORD)((st.wMinute&0x3f) << 5);
 697   *dostime |= (WORD)((st.wSecond*2)&0x1f);
 698 }
 699 
 700 lutime_t filetime2timet(const FILETIME ft)
 701 { LONGLONG i = *(LONGLONG*)&ft; 
 702   return (lutime_t)((i-116444736000000000LL)/10000000LL);
 703 }
 704 
 705 void GetNow(lutime_t *pft, WORD *dosdate, WORD *dostime)
 706 { SYSTEMTIME st; GetLocalTime(&st);
 707   FILETIME ft;   SystemTimeToFileTime(&st,&ft);
 708   filetime2dosdatetime(ft,dosdate,dostime);
 709   *pft = filetime2timet(ft);
 710 }
 711 
 712 DWORD GetFilePosZ(HANDLE hfout)
 713 { return SetFilePointer(hfout,0,0,FILE_CURRENT);
 714 }
 715 
 716 
 717 ZRESULT GetFileInfo(HANDLE hf, ulg *attr, long *size, iztimes *times, ulg *timestamp)
 718 { // The handle must be a handle to a file
 719   // The date and time is returned in a long with the date most significant to allow
 720   // unsigned integer comparison of absolute times. The attributes have two
 721   // high bytes unix attr, and two low bytes a mapping of that to DOS attr.
 722   //struct stat s; int res=stat(fn,&s); if (res!=0) return false;
 723   // translate windows file attributes into zip ones.
 724   BY_HANDLE_FILE_INFORMATION bhi; BOOL res=GetFileInformationByHandle(hf,&bhi);
 725   if (!res) return ZR_NOFILE;
 726   DWORD fa=bhi.dwFileAttributes; ulg a=0;
 727   // Zip uses the lower word for its interpretation of windows stuff
 728   if (fa&FILE_ATTRIBUTE_READONLY) a|=0x01;
 729   if (fa&FILE_ATTRIBUTE_HIDDEN)   a|=0x02;
 730   if (fa&FILE_ATTRIBUTE_SYSTEM)   a|=0x04;
 731   if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x10;
 732   if (fa&FILE_ATTRIBUTE_ARCHIVE)  a|=0x20;
 733   // It uses the upper word for standard unix attr, which we manually construct
 734   if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x40000000;  // directory
 735   else a|=0x80000000;  // normal file
 736   a|=0x01000000;      // readable
 737   if (fa&FILE_ATTRIBUTE_READONLY) {} else a|=0x00800000; // writeable
 738   // now just a small heuristic to check if it's an executable:
 739   DWORD red, hsize=GetFileSize(hf,NULL); if (hsize>40)
 740   { SetFilePointer(hf,0,NULL,FILE_BEGIN); unsigned short magic; ReadFile(hf,&magic,sizeof(magic),&red,NULL);
 741     SetFilePointer(hf,36,NULL,FILE_BEGIN); unsigned long hpos;  ReadFile(hf,&hpos,sizeof(hpos),&red,NULL);
 742     if (magic==0x54AD && hsize>hpos+4+20+28)
 743     { SetFilePointer(hf,hpos,NULL,FILE_BEGIN); unsigned long signature; ReadFile(hf,&signature,sizeof(signature),&red,NULL);
 744       if (signature==IMAGE_DOS_SIGNATURE || signature==IMAGE_OS2_SIGNATURE
 745          || signature==IMAGE_OS2_SIGNATURE_LE || signature==IMAGE_NT_SIGNATURE)
 746       { a |= 0x00400000; // executable
 747       }
 748     }
 749   }
 750   //
 751   if (attr!=NULL) *attr = a;
 752   if (size!=NULL) *size = hsize;
 753   if (times!=NULL)
 754   { // lutime_t is 32bit number of seconds elapsed since 0:0:0GMT, Jan1, 1970.
 755     // but FILETIME is 64bit number of 100-nanosecs since Jan1, 1601
 756     times->atime = filetime2timet(bhi.ftLastAccessTime);
 757     times->mtime = filetime2timet(bhi.ftLastWriteTime);
 758     times->ctime = filetime2timet(bhi.ftCreationTime);
 759   }
 760   if (timestamp!=NULL)
 761   { WORD dosdate,dostime;
 762     filetime2dosdatetime(bhi.ftLastWriteTime,&dosdate,&dostime);
 763     *timestamp = (WORD)dostime | (((DWORD)dosdate)<<16);
 764   }
 765   return ZR_OK;
 766 }
 767 #endif
 768 // ----------------------------------------------------------------------
 769 
 770 
 771 
 772 
 773 
 774 void Assert(TState &state,bool cond, const char *msg)
 775 { if (cond) return;
 776   state.err=msg;
 777 }
 778 void Trace(const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);}
 779 void Tracec(bool ,const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);}
 780 
 781 
 782 
 783 // ===========================================================================
 784 // Local (static) routines in this file.
 785 //
 786 
 787 void init_block     (TState &);
 788 void pqdownheap     (TState &,ct_data *tree, int k);
 789 void gen_bitlen     (TState &,tree_desc *desc);
 790 void gen_codes      (TState &state,ct_data *tree, int max_code);
 791 void build_tree     (TState &,tree_desc *desc);
 792 void scan_tree      (TState &,ct_data *tree, int max_code);
 793 void send_tree      (TState &state,ct_data *tree, int max_code);
 794 int  build_bl_tree  (TState &);
 795 void send_all_trees (TState &state,int lcodes, int dcodes, int blcodes);
 796 void compress_block (TState &state,ct_data *ltree, ct_data *dtree);
 797 void set_file_type  (TState &);
 798 void send_bits      (TState &state, int value, int length);
 799 unsigned bi_reverse (unsigned code, int len);
 800 void bi_windup      (TState &state);
 801 void copy_block     (TState &state,char *buf, unsigned len, int header);
 802 
 803 
 804 #define send_code(state, c, tree) send_bits(state, tree[c].fc.code, tree[c].dl.len)
 805 // Send a code of the given tree. c and tree must not have side effects
 806 
 807 // alternatively...
 808 //#define send_code(state, c, tree)
 809 //     { if (state.verbose>1) fprintf(stderr,"\ncd %3d ",(c));
 810 //       send_bits(state, tree[c].fc.code, tree[c].dl.len); }
 811 
 812 #define d_code(dist) ((dist) < 256 ? state.ts.dist_code[dist] : state.ts.dist_code[256+((dist)>>7)])
 813 // Mapping from a distance to a distance code. dist is the distance - 1 and
 814 // must not have side effects. dist_code[256] and dist_code[257] are never used.
 815 
 816 #define Max(a,b) (a >= b ? a : b)
 817 /* the arguments must not have side effects */
 818 
 819 /* ===========================================================================
 820  * Allocate the match buffer, initialize the various tables and save the
 821  * location of the internal file attribute (ascii/binary) and method
 822  * (DEFLATE/STORE).
 823  */
 824 void ct_init(TState &state, ush *attr)
 825 {
 826     int n;        /* iterates over tree elements */
 827     int bits;     /* bit counter */
 828     int length;   /* length value */
 829     int code;     /* code value */
 830     int dist;     /* distance index */
 831 
 832     state.ts.file_type = attr;
 833     //state.ts.file_method = method;
 834     state.ts.cmpr_bytelen = state.ts.cmpr_len_bits = 0L;
 835     state.ts.input_len = 0L;
 836 
 837     if (state.ts.static_dtree[0].dl.len != 0) return; /* ct_init already called */
 838 
 839     /* Initialize the mapping length (0..255) -> length code (0..28) */
 840     length = 0;
 841     for (code = 0; code < LENGTH_CODES-1; code++) {
 842         state.ts.base_length[code] = length;
 843         for (n = 0; n < (1<<extra_lbits[code]); n++) {
 844             state.ts.length_code[length++] = (uch)code;
 845         }
 846     }
 847     Assert(state,length == 256, "ct_init: length != 256");
 848     /* Note that the length 255 (match length 258) can be represented
 849      * in two different ways: code 284 + 5 bits or code 285, so we
 850      * overwrite length_code[255] to use the best encoding:
 851      */
 852     state.ts.length_code[length-1] = (uch)code;
 853 
 854     /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
 855     dist = 0;
 856     for (code = 0 ; code < 16; code++) {
 857         state.ts.base_dist[code] = dist;
 858         for (n = 0; n < (1<<extra_dbits[code]); n++) {
 859             state.ts.dist_code[dist++] = (uch)code;
 860         }
 861     }
 862     Assert(state,dist == 256, "ct_init: dist != 256");
 863     dist >>= 7; /* from now on, all distances are divided by 128 */
 864     for ( ; code < D_CODES; code++) {
 865         state.ts.base_dist[code] = dist << 7;
 866         for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
 867             state.ts.dist_code[256 + dist++] = (uch)code;
 868         }
 869     }
 870     Assert(state,dist == 256, "ct_init: 256+dist != 512");
 871 
 872     /* Construct the codes of the static literal tree */
 873     for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0;
 874     n = 0;
 875     while (n <= 143) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++;
 876     while (n <= 255) state.ts.static_ltree[n++].dl.len = 9, state.ts.bl_count[9]++;
 877     while (n <= 279) state.ts.static_ltree[n++].dl.len = 7, state.ts.bl_count[7]++;
 878     while (n <= 287) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++;
 879     /* fc.codes 286 and 287 do not exist, but we must include them in the
 880      * tree construction to get a canonical Huffman tree (longest code
 881      * all ones)
 882      */
 883     gen_codes(state,(ct_data *)state.ts.static_ltree, L_CODES+1);
 884 
 885     /* The static distance tree is trivial: */
 886     for (n = 0; n < D_CODES; n++) {
 887         state.ts.static_dtree[n].dl.len = 5;
 888         state.ts.static_dtree[n].fc.code = (ush)bi_reverse(n, 5);
 889     }
 890 
 891     /* Initialize the first block of the first file: */
 892     init_block(state);
 893 }
 894 
 895 /* ===========================================================================
 896  * Initialize a new block.
 897  */
 898 void init_block(TState &state)
 899 {
 900     int n; /* iterates over tree elements */
 901 
 902     /* Initialize the trees. */
 903     for (n = 0; n < L_CODES;  n++) state.ts.dyn_ltree[n].fc.freq = 0;
 904     for (n = 0; n < D_CODES;  n++) state.ts.dyn_dtree[n].fc.freq = 0;
 905     for (n = 0; n < BL_CODES; n++) state.ts.bl_tree[n].fc.freq = 0;
 906 
 907     state.ts.dyn_ltree[END_BLOCK].fc.freq = 1;
 908     state.ts.opt_len = state.ts.static_len = 0L;
 909     state.ts.last_lit = state.ts.last_dist = state.ts.last_flags = 0;
 910     state.ts.flags = 0; state.ts.flag_bit = 1;
 911 }
 912 
 913 #define SMALLEST 1
 914 /* Index within the heap array of least frequent node in the Huffman tree */
 915 
 916 
 917 /* ===========================================================================
 918  * Remove the smallest element from the heap and recreate the heap with
 919  * one less element. Updates heap and heap_len.
 920  */
 921 #define pqremove(tree, top) \
 922 {\
 923     top = state.ts.heap[SMALLEST]; \
 924     state.ts.heap[SMALLEST] = state.ts.heap[state.ts.heap_len--]; \
 925     pqdownheap(state,tree, SMALLEST); \
 926 }
 927 
 928 /* ===========================================================================
 929  * Compares to subtrees, using the tree depth as tie breaker when
 930  * the subtrees have equal frequency. This minimizes the worst case length.
 931  */
 932 #define smaller(tree, n, m) \
 933    (tree[n].fc.freq < tree[m].fc.freq || \
 934    (tree[n].fc.freq == tree[m].fc.freq && state.ts.depth[n] <= state.ts.depth[m]))
 935 
 936 /* ===========================================================================
 937  * Restore the heap property by moving down the tree starting at node k,
 938  * exchanging a node with the smallest of its two sons if necessary, stopping
 939  * when the heap property is re-established (each father smaller than its
 940  * two sons).
 941  */
 942 void pqdownheap(TState &state,ct_data *tree, int k)
 943 {
 944     int v = state.ts.heap[k];
 945     int j = k << 1;  /* left son of k */
 946     int htemp;       /* required because of bug in SASC compiler */
 947 
 948     while (j <= state.ts.heap_len) {
 949         /* Set j to the smallest of the two sons: */
 950         if (j < state.ts.heap_len && smaller(tree, state.ts.heap[j+1], state.ts.heap[j])) j++;
 951 
 952         /* Exit if v is smaller than both sons */
 953         htemp = state.ts.heap[j];
 954         if (smaller(tree, v, htemp)) break;
 955 
 956         /* Exchange v with the smallest son */
 957         state.ts.heap[k] = htemp;
 958         k = j;
 959 
 960         /* And continue down the tree, setting j to the left son of k */
 961         j <<= 1;
 962     }
 963     state.ts.heap[k] = v;
 964 }
 965 
 966 /* ===========================================================================
 967  * Compute the optimal bit lengths for a tree and update the total bit length
 968  * for the current block.
 969  * IN assertion: the fields freq and dad are set, heap[heap_max] and
 970  *    above are the tree nodes sorted by increasing frequency.
 971  * OUT assertions: the field len is set to the optimal bit length, the
 972  *     array bl_count contains the frequencies for each bit length.
 973  *     The length opt_len is updated; static_len is also updated if stree is
 974  *     not null.
 975  */
 976 void gen_bitlen(TState &state,tree_desc *desc)
 977 {
 978     ct_data *tree  = desc->dyn_tree;
 979     const int *extra     = desc->extra_bits;
 980     int base            = desc->extra_base;
 981     int max_code        = desc->max_code;
 982     int max_length      = desc->max_length;
 983     ct_data *stree = desc->static_tree;
 984     int h;              /* heap index */
 985     int n, m;           /* iterate over the tree elements */
 986     int bits;           /* bit length */
 987     int xbits;          /* extra bits */
 988     ush f;              /* frequency */
 989     int overflow = 0;   /* number of elements with bit length too large */
 990 
 991     for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0;
 992 
 993     /* In a first pass, compute the optimal bit lengths (which may
 994      * overflow in the case of the bit length tree).
 995      */
 996     tree[state.ts.heap[state.ts.heap_max]].dl.len = 0; /* root of the heap */
 997 
 998     for (h = state.ts.heap_max+1; h < HEAP_SIZE; h++) {
 999         n = state.ts.heap[h];
1000         bits = tree[tree[n].dl.dad].dl.len + 1;
1001         if (bits > max_length) bits = max_length, overflow++;
1002         tree[n].dl.len = (ush)bits;
1003         /* We overwrite tree[n].dl.dad which is no longer needed */
1004 
1005         if (n > max_code) continue; /* not a leaf node */
1006 
1007         state.ts.bl_count[bits]++;
1008         xbits = 0;
1009         if (n >= base) xbits = extra[n-base];
1010         f = tree[n].fc.freq;
1011         state.ts.opt_len += (ulg)f * (bits + xbits);
1012         if (stree) state.ts.static_len += (ulg)f * (stree[n].dl.len + xbits);
1013     }
1014     if (overflow == 0) return;
1015 
1016     Trace("\nbit length overflow\n");
1017     /* This happens for example on obj2 and pic of the Calgary corpus */
1018 
1019     /* Find the first bit length which could increase: */
1020     do {
1021         bits = max_length-1;
1022         while (state.ts.bl_count[bits] == 0) bits--;
1023         state.ts.bl_count[bits]--;           /* move one leaf down the tree */
1024         state.ts.bl_count[bits+1] += (ush)2; /* move one overflow item as its brother */
1025         state.ts.bl_count[max_length]--;
1026         /* The brother of the overflow item also moves one step up,
1027          * but this does not affect bl_count[max_length]
1028          */
1029         overflow -= 2;
1030     } while (overflow > 0);
1031 
1032     /* Now recompute all bit lengths, scanning in increasing frequency.
1033      * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
1034      * lengths instead of fixing only the wrong ones. This idea is taken
1035      * from 'ar' written by Haruhiko Okumura.)
1036      */
1037     for (bits = max_length; bits != 0; bits--) {
1038         n = state.ts.bl_count[bits];
1039         while (n != 0) {
1040             m = state.ts.heap[--h];
1041             if (m > max_code) continue;
1042             if (tree[m].dl.len != (ush)bits) {
1043                 Trace("code %d bits %d->%d\n", m, tree[m].dl.len, bits);
1044                 state.ts.opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq;
1045                 tree[m].dl.len = (ush)bits;
1046             }
1047             n--;
1048         }
1049     }
1050 }
1051 
1052 /* ===========================================================================
1053  * Generate the codes for a given tree and bit counts (which need not be
1054  * optimal).
1055  * IN assertion: the array bl_count contains the bit length statistics for
1056  * the given tree and the field len is set for all tree elements.
1057  * OUT assertion: the field code is set for all tree elements of non
1058  *     zero code length.
1059  */
1060 void gen_codes (TState &state, ct_data *tree, int max_code)
1061 {
1062     ush next_code[MAX_BITS+1]; /* next code value for each bit length */
1063     ush code = 0;              /* running code value */
1064     int bits;                  /* bit index */
1065     int n;                     /* code index */
1066 
1067     /* The distribution counts are first used to generate the code values
1068      * without bit reversal.
1069      */
1070     for (bits = 1; bits <= MAX_BITS; bits++) {
1071         next_code[bits] = code = (ush)((code + state.ts.bl_count[bits-1]) << 1);
1072     }
1073     /* Check that the bit counts in bl_count are consistent. The last code
1074      * must be all ones.
1075      */
1076     Assert(state,code + state.ts.bl_count[MAX_BITS]-1 == (1<< ((ush) MAX_BITS)) - 1,
1077             "inconsistent bit counts");
1078     Trace("\ngen_codes: max_code %d ", max_code);
1079 
1080     for (n = 0;  n <= max_code; n++) {
1081         int len = tree[n].dl.len;
1082         if (len == 0) continue;
1083         /* Now reverse the bits */
1084         tree[n].fc.code = (ush)bi_reverse(next_code[len]++, len);
1085 
1086         //Tracec(tree != state.ts.static_ltree, "\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].fc.code, next_code[len]-1);
1087     }
1088 }
1089 
1090 /* ===========================================================================
1091  * Construct one Huffman tree and assigns the code bit strings and lengths.
1092  * Update the total bit length for the current block.
1093  * IN assertion: the field freq is set for all tree elements.
1094  * OUT assertions: the fields len and code are set to the optimal bit length
1095  *     and corresponding code. The length opt_len is updated; static_len is
1096  *     also updated if stree is not null. The field max_code is set.
1097  */
1098 void build_tree(TState &state,tree_desc *desc)
1099 {
1100     ct_data *tree   = desc->dyn_tree;
1101     ct_data *stree  = desc->static_tree;
1102     int elems            = desc->elems;
1103     int n, m;          /* iterate over heap elements */
1104     int max_code = -1; /* largest code with non zero frequency */
1105     int node = elems;  /* next internal node of the tree */
1106 
1107     /* Construct the initial heap, with least frequent element in
1108      * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
1109      * heap[0] is not used.
1110      */
1111     state.ts.heap_len = 0, state.ts.heap_max = HEAP_SIZE;
1112 
1113     for (n = 0; n < elems; n++) {
1114         if (tree[n].fc.freq != 0) {
1115             state.ts.heap[++state.ts.heap_len] = max_code = n;
1116             state.ts.depth[n] = 0;
1117         } else {
1118             tree[n].dl.len = 0;
1119         }
1120     }
1121 
1122     /* The pkzip format requires that at least one distance code exists,
1123      * and that at least one bit should be sent even if there is only one
1124      * possible code. So to avoid special checks later on we force at least
1125      * two codes of non zero frequency.
1126      */
1127     while (state.ts.heap_len < 2) {
1128         int newcp = state.ts.heap[++state.ts.heap_len] = (max_code < 2 ? ++max_code : 0);
1129         tree[newcp].fc.freq = 1;
1130         state.ts.depth[newcp] = 0;
1131         state.ts.opt_len--; if (stree) state.ts.static_len -= stree[newcp].dl.len;
1132         /* new is 0 or 1 so it does not have extra bits */
1133     }
1134     desc->max_code = max_code;
1135 
1136     /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
1137      * establish sub-heaps of increasing lengths:
1138      */
1139     for (n = state.ts.heap_len/2; n >= 1; n--) pqdownheap(state,tree, n);
1140 
1141     /* Construct the Huffman tree by repeatedly combining the least two
1142      * frequent nodes.
1143      */
1144     do {
1145         pqremove(tree, n);   /* n = node of least frequency */
1146         m = state.ts.heap[SMALLEST];  /* m = node of next least frequency */
1147 
1148         state.ts.heap[--state.ts.heap_max] = n; /* keep the nodes sorted by frequency */
1149         state.ts.heap[--state.ts.heap_max] = m;
1150 
1151         /* Create a new node father of n and m */
1152         tree[node].fc.freq = (ush)(tree[n].fc.freq + tree[m].fc.freq);
1153         state.ts.depth[node] = (uch) (Max(state.ts.depth[n], state.ts.depth[m]) + 1);
1154         tree[n].dl.dad = tree[m].dl.dad = (ush)node;
1155         /* and insert the new node in the heap */
1156         state.ts.heap[SMALLEST] = node++;
1157         pqdownheap(state,tree, SMALLEST);
1158 
1159     } while (state.ts.heap_len >= 2);
1160 
1161     state.ts.heap[--state.ts.heap_max] = state.ts.heap[SMALLEST];
1162 
1163     /* At this point, the fields freq and dad are set. We can now
1164      * generate the bit lengths.
1165      */
1166     gen_bitlen(state,(tree_desc *)desc);
1167 
1168     /* The field len is now set, we can generate the bit codes */
1169     gen_codes (state,(ct_data *)tree, max_code);
1170 }
1171 
1172 /* ===========================================================================
1173  * Scan a literal or distance tree to determine the frequencies of the codes
1174  * in the bit length tree. Updates opt_len to take into account the repeat
1175  * counts. (The contribution of the bit length codes will be added later
1176  * during the construction of bl_tree.)
1177  */
1178 void scan_tree (TState &state,ct_data *tree, int max_code)
1179 {
1180     int n;                     /* iterates over all tree elements */
1181     int prevlen = -1;          /* last emitted length */
1182     int curlen;                /* length of current code */
1183     int nextlen = tree[0].dl.len; /* length of next code */
1184     int count = 0;             /* repeat count of the current code */
1185     int max_count = 7;         /* max repeat count */
1186     int min_count = 4;         /* min repeat count */
1187 
1188     if (nextlen == 0) max_count = 138, min_count = 3;
1189     tree[max_code+1].dl.len = (ush)-1; /* guard */
1190 
1191     for (n = 0; n <= max_code; n++) {
1192         curlen = nextlen; nextlen = tree[n+1].dl.len;
1193         if (++count < max_count && curlen == nextlen) {
1194             continue;
1195         } else if (count < min_count) {
1196             state.ts.bl_tree[curlen].fc.freq = (ush)(state.ts.bl_tree[curlen].fc.freq + count);
1197         } else if (curlen != 0) {
1198             if (curlen != prevlen) state.ts.bl_tree[curlen].fc.freq++;
1199             state.ts.bl_tree[REP_3_6].fc.freq++;
1200         } else if (count <= 10) {
1201             state.ts.bl_tree[REPZ_3_10].fc.freq++;
1202         } else {
1203             state.ts.bl_tree[REPZ_11_138].fc.freq++;
1204         }
1205         count = 0; prevlen = curlen;
1206         if (nextlen == 0) {
1207             max_count = 138, min_count = 3;
1208         } else if (curlen == nextlen) {
1209             max_count = 6, min_count = 3;
1210         } else {
1211             max_count = 7, min_count = 4;
1212         }
1213     }
1214 }
1215 
1216 /* ===========================================================================
1217  * Send a literal or distance tree in compressed form, using the codes in
1218  * bl_tree.
1219  */
1220 void send_tree (TState &state, ct_data *tree, int max_code)
1221 {
1222     int n;                     /* iterates over all tree elements */
1223     int prevlen = -1;          /* last emitted length */
1224     int curlen;                /* length of current code */
1225     int nextlen = tree[0].dl.len; /* length of next code */
1226     int count = 0;             /* repeat count of the current code */
1227     int max_count = 7;         /* max repeat count */
1228     int min_count = 4;         /* min repeat count */
1229 
1230     /* tree[max_code+1].dl.len = -1; */  /* guard already set */
1231     if (nextlen == 0) max_count = 138, min_count = 3;
1232 
1233     for (n = 0; n <= max_code; n++) {
1234         curlen = nextlen; nextlen = tree[n+1].dl.len;
1235         if (++count < max_count && curlen == nextlen) {
1236             continue;
1237         } else if (count < min_count) {
1238             do { send_code(state, curlen, state.ts.bl_tree); } while (--count != 0);
1239 
1240         } else if (curlen != 0) {
1241             if (curlen != prevlen) {
1242                 send_code(state, curlen, state.ts.bl_tree); count--;
1243             }
1244             Assert(state,count >= 3 && count <= 6, " 3_6?");
1245             send_code(state,REP_3_6, state.ts.bl_tree); send_bits(state,count-3, 2);
1246 
1247         } else if (count <= 10) {
1248             send_code(state,REPZ_3_10, state.ts.bl_tree); send_bits(state,count-3, 3);
1249 
1250         } else {
1251             send_code(state,REPZ_11_138, state.ts.bl_tree); send_bits(state,count-11, 7);
1252         }
1253         count = 0; prevlen = curlen;
1254         if (nextlen == 0) {
1255             max_count = 138, min_count = 3;
1256         } else if (curlen == nextlen) {
1257             max_count = 6, min_count = 3;
1258         } else {
1259             max_count = 7, min_count = 4;
1260         }
1261     }
1262 }
1263 
1264 /* ===========================================================================
1265  * Construct the Huffman tree for the bit lengths and return the index in
1266  * bl_order of the last bit length code to send.
1267  */
1268 int build_bl_tree(TState &state)
1269 {
1270     int max_blindex;  /* index of last bit length code of non zero freq */
1271 
1272     /* Determine the bit length frequencies for literal and distance trees */
1273     scan_tree(state,(ct_data *)state.ts.dyn_ltree, state.ts.l_desc.max_code);
1274     scan_tree(state,(ct_data *)state.ts.dyn_dtree, state.ts.d_desc.max_code);
1275 
1276     /* Build the bit length tree: */
1277     build_tree(state,(tree_desc *)(&state.ts.bl_desc));
1278     /* opt_len now includes the length of the tree representations, except
1279      * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
1280      */
1281 
1282     /* Determine the number of bit length codes to send. The pkzip format
1283      * requires that at least 4 bit length codes be sent. (appnote.txt says
1284      * 3 but the actual value used is 4.)
1285      */
1286     for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
1287         if (state.ts.bl_tree[bl_order[max_blindex]].dl.len != 0) break;
1288     }
1289     /* Update opt_len to include the bit length tree and counts */
1290     state.ts.opt_len += 3*(max_blindex+1) + 5+5+4;
1291     Trace("\ndyn trees: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
1292 
1293     return max_blindex;
1294 }
1295 
1296 /* ===========================================================================
1297  * Send the header for a block using dynamic Huffman trees: the counts, the
1298  * lengths of the bit length codes, the literal tree and the distance tree.
1299  * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
1300  */
1301 void send_all_trees(TState &state,int lcodes, int dcodes, int blcodes)
1302 {
1303     int rank;                    /* index in bl_order */
1304 
1305     Assert(state,lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
1306     Assert(state,lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
1307             "too many codes");
1308     Trace("\nbl counts: ");
1309     send_bits(state,lcodes-257, 5);
1310     /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */
1311     send_bits(state,dcodes-1,   5);
1312     send_bits(state,blcodes-4,  4); /* not -3 as stated in appnote.txt */
1313     for (rank = 0; rank < blcodes; rank++) {
1314         Trace("\nbl code %2d ", bl_order[rank]);
1315         send_bits(state,state.ts.bl_tree[bl_order[rank]].dl.len, 3);
1316     }    
1317     Trace("\nbl tree: sent %ld", state.bs.bits_sent);
1318 
1319     send_tree(state,(ct_data *)state.ts.dyn_ltree, lcodes-1); /* send the literal tree */
1320     Trace("\nlit tree: sent %ld", state.bs.bits_sent);
1321 
1322     send_tree(state,(ct_data *)state.ts.dyn_dtree, dcodes-1); /* send the distance tree */
1323     Trace("\ndist tree: sent %ld", state.bs.bits_sent);
1324 }
1325 
1326 /* ===========================================================================
1327  * Determine the best encoding for the current block: dynamic trees, static
1328  * trees or store, and output the encoded block to the zip file. This function
1329  * returns the total compressed length (in bytes) for the file so far.
1330  */
1331 ulg flush_block(TState &state,char *buf, ulg stored_len, int eof)
1332 {
1333     ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
1334     int max_blindex;  /* index of last bit length code of non zero freq */
1335 
1336     state.ts.flag_buf[state.ts.last_flags] = state.ts.flags; /* Save the flags for the last 8 items */
1337 
1338      /* Check if the file is ascii or binary */
1339     if (*state.ts.file_type == (ush)UNKNOWN) set_file_type(state);
1340 
1341     /* Construct the literal and distance trees */
1342     build_tree(state,(tree_desc *)(&state.ts.l_desc));
1343     Trace("\nlit data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
1344 
1345     build_tree(state,(tree_desc *)(&state.ts.d_desc));
1346     Trace("\ndist data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
1347     /* At this point, opt_len and static_len are the total bit lengths of
1348      * the compressed block data, excluding the tree representations.
1349      */
1350 
1351     /* Build the bit length tree for the above two trees, and get the index
1352      * in bl_order of the last bit length code to send.
1353      */
1354     max_blindex = build_bl_tree(state);
1355 
1356     /* Determine the best encoding. Compute first the block length in bytes */
1357     opt_lenb = (state.ts.opt_len+3+7)>>3;
1358     static_lenb = (state.ts.static_len+3+7)>>3;
1359     state.ts.input_len += stored_len; /* for debugging only */
1360 
1361     Trace("\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
1362             opt_lenb, state.ts.opt_len, static_lenb, state.ts.static_len, stored_len,
1363             state.ts.last_lit, state.ts.last_dist);
1364 
1365     if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
1366 
1367     // Originally, zip allowed the file to be transformed from a compressed
1368     // into a stored file in the case where compression failed, there
1369     // was only one block, and it was allowed to change. I've removed this
1370     // possibility since the code's cleaner if no changes are allowed.
1371     //if (stored_len <= opt_lenb && eof && state.ts.cmpr_bytelen == 0L
1372     //   && state.ts.cmpr_len_bits == 0L && state.seekable)
1373     //{   // && state.ts.file_method != NULL
1374     //    // Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there:
1375     //    Assert(state,buf!=NULL,"block vanished");
1376     //    copy_block(state,buf, (unsigned)stored_len, 0); // without header
1377     //    state.ts.cmpr_bytelen = stored_len;
1378     //    Assert(state,false,"unimplemented *state.ts.file_method = STORE;");
1379     //    //*state.ts.file_method = STORE;
1380     //}
1381     //else
1382     if (stored_len+4 <= opt_lenb && buf != (char*)NULL) {
1383                        /* 4: two words for the lengths */
1384         /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
1385          * Otherwise we can't have processed more than WSIZE input bytes since
1386          * the last block flush, because compression would have been
1387          * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
1388          * transform a block into a stored block.
1389          */
1390         send_bits(state,(STORED_BLOCK<<1)+eof, 3);  /* send block type */
1391         state.ts.cmpr_bytelen += ((state.ts.cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4;
1392         state.ts.cmpr_len_bits = 0L;
1393 
1394         copy_block(state,buf, (unsigned)stored_len, 1); /* with header */
1395     }
1396     else if (static_lenb == opt_lenb) {
1397         send_bits(state,(STATIC_TREES<<1)+eof, 3);
1398         compress_block(state,(ct_data *)state.ts.static_ltree, (ct_data *)state.ts.static_dtree);
1399         state.ts.cmpr_len_bits += 3 + state.ts.static_len;
1400         state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3;
1401         state.ts.cmpr_len_bits &= 7L;
1402     }
1403     else {
1404         send_bits(state,(DYN_TREES<<1)+eof, 3);
1405         send_all_trees(state,state.ts.l_desc.max_code+1, state.ts.d_desc.max_code+1, max_blindex+1);
1406         compress_block(state,(ct_data *)state.ts.dyn_ltree, (ct_data *)state.ts.dyn_dtree);
1407         state.ts.cmpr_len_bits += 3 + state.ts.opt_len;
1408         state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3;
1409         state.ts.cmpr_len_bits &= 7L;
1410     }
1411     Assert(state,((state.ts.cmpr_bytelen << 3) + state.ts.cmpr_len_bits) == state.bs.bits_sent, "bad compressed size");
1412     init_block(state);
1413 
1414     if (eof) {
1415         // Assert(state,input_len == isize, "bad input size");
1416         bi_windup(state);
1417         state.ts.cmpr_len_bits += 7;  /* align on byte boundary */
1418     }
1419     Trace("\n");
1420 
1421     return state.ts.cmpr_bytelen + (state.ts.cmpr_len_bits >> 3);
1422 }
1423 
1424 /* ===========================================================================
1425  * Save the match info and tally the frequency counts. Return true if
1426  * the current block must be flushed.
1427  */
1428 int ct_tally (TState &state,int dist, int lc)
1429 {
1430     state.ts.l_buf[state.ts.last_lit++] = (uch)lc;
1431     if (dist == 0) {
1432         /* lc is the unmatched char */
1433         state.ts.dyn_ltree[lc].fc.freq++;
1434     } else {
1435         /* Here, lc is the match length - MIN_MATCH */
1436         dist--;             /* dist = match distance - 1 */
1437         Assert(state,(ush)dist < (ush)MAX_DIST &&
1438                (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
1439                (ush)d_code(dist) < (ush)D_CODES,  "ct_tally: bad match");
1440 
1441         state.ts.dyn_ltree[state.ts.length_code[lc]+LITERALS+1].fc.freq++;
1442         state.ts.dyn_dtree[d_code(dist)].fc.freq++;
1443 
1444         state.ts.d_buf[state.ts.last_dist++] = (ush)dist;
1445         state.ts.flags |= state.ts.flag_bit;
1446     }
1447     state.ts.flag_bit <<= 1;
1448 
1449     /* Output the flags if they fill a byte: */
1450     if ((state.ts.last_lit & 7) == 0) {
1451         state.ts.flag_buf[state.ts.last_flags++] = state.ts.flags;
1452         state.ts.flags = 0, state.ts.flag_bit = 1;
1453     }
1454     /* Try to guess if it is profitable to stop the current block here */
1455     if (state.level > 2 && (state.ts.last_lit & 0xfff) == 0) {
1456         /* Compute an upper bound for the compressed length */
1457         ulg out_length = (ulg)state.ts.last_lit*8L;
1458         ulg in_length = (ulg)state.ds.strstart-state.ds.block_start;
1459         int dcode;
1460         for (dcode = 0; dcode < D_CODES; dcode++) {
1461             out_length += (ulg)state.ts.dyn_dtree[dcode].fc.freq*(5L+extra_dbits[dcode]);
1462         }
1463         out_length >>= 3;
1464         Trace("\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
1465                state.ts.last_lit, state.ts.last_dist, in_length, out_length,
1466                100L - out_length*100L/in_length);
1467         if (state.ts.last_dist < state.ts.last_lit/2 && out_length < in_length/2) return 1;
1468     }
1469     return (state.ts.last_lit == LIT_BUFSIZE-1 || state.ts.last_dist == DIST_BUFSIZE);
1470     /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
1471      * on 16 bit machines and because stored blocks are restricted to
1472      * 64K-1 bytes.
1473      */
1474 }
1475 
1476 /* ===========================================================================
1477  * Send the block data compressed using the given Huffman trees
1478  */
1479 void compress_block(TState &state,ct_data *ltree, ct_data *dtree)
1480 {
1481     unsigned dist;      /* distance of matched string */
1482     int lc;             /* match length or unmatched char (if dist == 0) */
1483     unsigned lx = 0;    /* running index in l_buf */
1484     unsigned dx = 0;    /* running index in d_buf */
1485     unsigned fx = 0;    /* running index in flag_buf */
1486     uch flag = 0;       /* current flags */
1487     unsigned code;      /* the code to send */
1488     int extra;          /* number of extra bits to send */
1489 
1490     if (state.ts.last_lit != 0) do {
1491         if ((lx & 7) == 0) flag = state.ts.flag_buf[fx++];
1492         lc = state.ts.l_buf[lx++];
1493         if ((flag & 1) == 0) {
1494             send_code(state,lc, ltree); /* send a literal byte */
1495         } else {
1496             /* Here, lc is the match length - MIN_MATCH */
1497             code = state.ts.length_code[lc];
1498             send_code(state,code+LITERALS+1, ltree); /* send the length code */
1499             extra = extra_lbits[code];
1500             if (extra != 0) {
1501                 lc -= state.ts.base_length[code];
1502                 send_bits(state,lc, extra);        /* send the extra length bits */
1503             }
1504             dist = state.ts.d_buf[dx++];
1505             /* Here, dist is the match distance - 1 */
1506             code = d_code(dist);
1507             Assert(state,code < D_CODES, "bad d_code");
1508 
1509             send_code(state,code, dtree);       /* send the distance code */
1510             extra = extra_dbits[code];
1511             if (extra != 0) {
1512                 dist -= state.ts.base_dist[code];
1513                 send_bits(state,dist, extra);   /* send the extra distance bits */
1514             }
1515         } /* literal or match pair ? */
1516         flag >>= 1;
1517     } while (lx < state.ts.last_lit);
1518 
1519     send_code(state,END_BLOCK, ltree);
1520 }
1521 
1522 /* ===========================================================================
1523  * Set the file type to ASCII or BINARY, using a crude approximation:
1524  * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
1525  * IN assertion: the fields freq of dyn_ltree are set and the total of all
1526  * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
1527  */
1528 void set_file_type(TState &state)
1529 {
1530     int n = 0;
1531     unsigned ascii_freq = 0;
1532     unsigned bin_freq = 0;
1533     while (n < 7)        bin_freq += state.ts.dyn_ltree[n++].fc.freq;
1534     while (n < 128)    ascii_freq += state.ts.dyn_ltree[n++].fc.freq;
1535     while (n < LITERALS) bin_freq += state.ts.dyn_ltree[n++].fc.freq;
1536     *state.ts.file_type = (ush)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII);
1537 }
1538 
1539 
1540 /* ===========================================================================
1541  * Initialize the bit string routines.
1542  */
1543 void bi_init (TState &state,char *tgt_buf, unsigned tgt_size, int flsh_allowed)
1544 {
1545     state.bs.out_buf = tgt_buf;
1546     state.bs.out_size = tgt_size;
1547     state.bs.out_offset = 0;
1548     state.bs.flush_flg = flsh_allowed;
1549 
1550     state.bs.bi_buf = 0;
1551     state.bs.bi_valid = 0;
1552     state.bs.bits_sent = 0L;
1553 }
1554 
1555 /* ===========================================================================
1556  * Send a value on a given number of bits.
1557  * IN assertion: length <= 16 and value fits in length bits.
1558  */
1559 void send_bits(TState &state,int value, int length)
1560 {
1561     Assert(state,length > 0 && length <= 15, "invalid length");
1562     state.bs.bits_sent += (ulg)length;
1563     /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and
1564      * (Buf_size - bi_valid) bits from value to flush the filled bi_buf,
1565      * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid))
1566      * unused bits in bi_buf.
1567      */
1568     state.bs.bi_buf |= (value << state.bs.bi_valid);
1569     state.bs.bi_valid += length;
1570     if (state.bs.bi_valid > (int)Buf_size) {
1571         PUTSHORT(state,state.bs.bi_buf);
1572         state.bs.bi_valid -= Buf_size;
1573         state.bs.bi_buf = (unsigned)value >> (length - state.bs.bi_valid);
1574     }
1575 }
1576 
1577 /* ===========================================================================
1578  * Reverse the first len bits of a code, using straightforward code (a faster
1579  * method would use a table)
1580  * IN assertion: 1 <= len <= 15
1581  */
1582 unsigned bi_reverse(unsigned code, int len)
1583 {
1584     register unsigned res = 0;
1585     do {
1586         res |= code & 1;
1587         code >>= 1, res <<= 1;
1588     } while (--len > 0);
1589     return res >> 1;
1590 }
1591 
1592 /* ===========================================================================
1593  * Write out any remaining bits in an incomplete byte.
1594  */
1595 void bi_windup(TState &state)
1596 {
1597     if (state.bs.bi_valid > 8) {
1598         PUTSHORT(state,state.bs.bi_buf);
1599     } else if (state.bs.bi_valid > 0) {
1600         PUTBYTE(state,state.bs.bi_buf);
1601     }
1602     if (state.bs.flush_flg) {
1603         state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset);
1604     }
1605     state.bs.bi_buf = 0;
1606     state.bs.bi_valid = 0;
1607     state.bs.bits_sent = (state.bs.bits_sent+7) & ~7;
1608 }
1609 
1610 /* ===========================================================================
1611  * Copy a stored block to the zip file, storing first the length and its
1612  * one's complement if requested.
1613  */
1614 void copy_block(TState &state, char *block, unsigned len, int header)
1615 {
1616     bi_windup(state);              /* align on byte boundary */
1617 
1618     if (header) {
1619         PUTSHORT(state,(ush)len);
1620         PUTSHORT(state,(ush)~len);
1621         state.bs.bits_sent += 2*16;
1622     }
1623     if (state.bs.flush_flg) {
1624         state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset);
1625         state.bs.out_offset = len;
1626         state.flush_outbuf(state.param,block, &state.bs.out_offset);
1627     } else if (state.bs.out_offset + len > state.bs.out_size) {
1628         Assert(state,false,"output buffer too small for in-memory compression");
1629     } else {
1630         memcpy(state.bs.out_buf + state.bs.out_offset, block, len);
1631         state.bs.out_offset += len;
1632     }
1633     state.bs.bits_sent += (ulg)len<<3;
1634 }
1635 
1636 
1637 
1638 
1639 
1640 
1641 
1642 
1643 /* ===========================================================================
1644  *  Prototypes for functions.
1645  */
1646 
1647 void fill_window  (TState &state);
1648 ulg deflate_fast  (TState &state);
1649 
1650 int  longest_match (TState &state,IPos cur_match);
1651 
1652 
1653 /* ===========================================================================
1654  * Update a hash value with the given input byte
1655  * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
1656  *    input characters, so that a running hash key can be computed from the
1657  *    previous key instead of complete recalculation each time.
1658  */
1659 #define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
1660 
1661 /* ===========================================================================
1662  * Insert string s in the dictionary and set match_head to the previous head
1663  * of the hash chain (the most recent string with same hash key). Return
1664  * the previous length of the hash chain.
1665  * IN  assertion: all calls to to INSERT_STRING are made with consecutive
1666  *    input characters and the first MIN_MATCH bytes of s are valid
1667  *    (except for the last MIN_MATCH-1 bytes of the input file).
1668  */
1669 #define INSERT_STRING(s, match_head) \
1670    (UPDATE_HASH(state.ds.ins_h, state.ds.window[(s) + (MIN_MATCH-1)]), \
1671     state.ds.prev[(s) & WMASK] = match_head = state.ds.head[state.ds.ins_h], \
1672     state.ds.head[state.ds.ins_h] = (s))
1673 
1674 /* ===========================================================================
1675  * Initialize the "longest match" routines for a new file
1676  *
1677  * IN assertion: window_size is > 0 if the input file is already read or
1678  *    mmap'ed in the window[] array, 0 otherwise. In the first case,
1679  *    window_size is sufficient to contain the whole input file plus
1680  *    MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end
1681  *    of window[] when looking for matches towards the end).
1682  */
1683 void lm_init (TState &state, int pack_level, ush *flags)
1684 {
1685     register unsigned j;
1686 
1687     Assert(state,pack_level>=1 && pack_level<=8,"bad pack level");
1688 
1689     /* Do not slide the window if the whole input is already in memory
1690      * (window_size > 0)
1691      */
1692     state.ds.sliding = 0;
1693     if (state.ds.window_size == 0L) {
1694         state.ds.sliding = 1;
1695         state.ds.window_size = (ulg)2L*WSIZE;
1696     }
1697 
1698     /* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
1699      * prev[] will be initialized on the fly.
1700      */
1701     state.ds.head[HASH_SIZE-1] = NIL;
1702     memset((char*)state.ds.head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*state.ds.head));
1703 
1704     /* Set the default configuration parameters:
1705      */
1706     state.ds.max_lazy_match   = configuration_table[pack_level].max_lazy;
1707     state.ds.good_match       = configuration_table[pack_level].good_length;
1708     state.ds.nice_match       = configuration_table[pack_level].nice_length;
1709     state.ds.max_chain_length = configuration_table[pack_level].max_chain;
1710     if (pack_level <= 2) {
1711        *flags |= FAST;
1712     } else if (pack_level >= 8) {
1713        *flags |= SLOW;
1714     }
1715     /* ??? reduce max_chain_length for binary files */
1716 
1717     state.ds.strstart = 0;
1718     state.ds.block_start = 0L;
1719 
1720     j = WSIZE;
1721     j <<= 1; // Can read 64K in one step
1722     state.ds.lookahead = state.readfunc(state, (char*)state.ds.window, j);
1723 
1724     if (state.ds.lookahead == 0 || state.ds.lookahead == (unsigned)EOF) {
1725        state.ds.eofile = 1, state.ds.lookahead = 0;
1726        return;
1727     }
1728     state.ds.eofile = 0;
1729     /* Make sure that we always have enough lookahead. This is important
1730      * if input comes from a device such as a tty.
1731      */
1732     if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
1733 
1734     state.ds.ins_h = 0;
1735     for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(state.ds.ins_h, state.ds.window[j]);
1736     /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
1737      * not important since only literal bytes will be emitted.
1738      */
1739 }
1740 
1741 
1742 /* ===========================================================================
1743  * Set match_start to the longest match starting at the given string and
1744  * return its length. Matches shorter or equal to prev_length are discarded,
1745  * in which case the result is equal to prev_length and match_start is
1746  * garbage.
1747  * IN assertions: cur_match is the head of the hash chain for the current
1748  *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
1749  */
1750 // For 80x86 and 680x0 and ARM, an optimized version is in match.asm or
1751 // match.S. The code is functionally equivalent, so you can use the C version
1752 // if desired. Which I do so desire!
1753 int longest_match(TState &state,IPos cur_match)
1754 {
1755     unsigned chain_length = state.ds.max_chain_length;   /* max hash chain length */
1756     register uch *scan = state.ds.window + state.ds.strstart; /* current string */
1757     register uch *match;                    /* matched string */
1758     register int len;                           /* length of current match */
1759     int best_len = state.ds.prev_length;                 /* best match length so far */
1760     IPos limit = state.ds.strstart > (IPos)MAX_DIST ? state.ds.strstart - (IPos)MAX_DIST : NIL;
1761     /* Stop when cur_match becomes <= limit. To simplify the code,
1762      * we prevent matches with the string of window index 0.
1763      */
1764 
1765   // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
1766   // It is easy to get rid of this optimization if necessary.
1767     Assert(state,HASH_BITS>=8 && MAX_MATCH==258,"Code too clever");
1768 
1769 
1770 
1771     register uch *strend = state.ds.window + state.ds.strstart + MAX_MATCH;
1772     register uch scan_end1  = scan[best_len-1];
1773     register uch scan_end   = scan[best_len];
1774 
1775     /* Do not waste too much time if we already have a good match: */
1776     if (state.ds.prev_length >= state.ds.good_match) {
1777         chain_length >>= 2;
1778     }
1779 
1780     Assert(state,state.ds.strstart <= state.ds.window_size-MIN_LOOKAHEAD, "insufficient lookahead");
1781 
1782     do {
1783         Assert(state,cur_match < state.ds.strstart, "no future");
1784         match = state.ds.window + cur_match;
1785 
1786         /* Skip to next match if the match length cannot increase
1787          * or if the match length is less than 2:
1788          */
1789         if (match[best_len]   != scan_end  ||
1790             match[best_len-1] != scan_end1 ||
1791             *match            != *scan     ||
1792             *++match          != scan[1])      continue;
1793 
1794         /* The check at best_len-1 can be removed because it will be made
1795          * again later. (This heuristic is not always a win.)
1796          * It is not necessary to compare scan[2] and match[2] since they
1797          * are always equal when the other bytes match, given that
1798          * the hash keys are equal and that HASH_BITS >= 8.
1799          */
1800         scan += 2, match++;
1801 
1802         /* We check for insufficient lookahead only every 8th comparison;
1803          * the 256th check will be made at strstart+258.
1804          */
1805         do {
1806         } while (*++scan == *++match && *++scan == *++match &&
1807                  *++scan == *++match && *++scan == *++match &&
1808                  *++scan == *++match && *++scan == *++match &&
1809                  *++scan == *++match && *++scan == *++match &&
1810                  scan < strend);
1811 
1812         Assert(state,scan <= state.ds.window+(unsigned)(state.ds.window_size-1), "wild scan");
1813                           
1814         len = MAX_MATCH - (int)(strend - scan);
1815         scan = strend - MAX_MATCH;
1816 
1817 
1818         if (len > best_len) {
1819             state.ds.match_start = cur_match;
1820             best_len = len;
1821             if (len >= state.ds.nice_match) break;
1822             scan_end1  = scan[best_len-1];
1823             scan_end   = scan[best_len];
1824         }
1825     } while ((cur_match = state.ds.prev[cur_match & WMASK]) > limit
1826              && --chain_length != 0);
1827 
1828     return best_len;
1829 }
1830 
1831 
1832 
1833 #define check_match(state,start, match, length)
1834 // or alternatively...
1835 //void check_match(TState &state,IPos start, IPos match, int length)
1836 //{ // check that the match is indeed a match
1837 //    if (memcmp((char*)state.ds.window + match,
1838 //                (char*)state.ds.window + start, length) != EQUAL) {
1839 //        fprintf(stderr,
1840 //            " start %d, match %d, length %d\n",
1841 //            start, match, length);
1842 //        error("invalid match");
1843 //    }
1844 //    if (state.verbose > 1) {
1845 //        fprintf(stderr,"\\[%d,%d]", start-match, length);
1846 //        do { fprintf(stdout,"%c",state.ds.window[start++]); } while (--length != 0);
1847 //    }
1848 //}
1849 
1850 /* ===========================================================================
1851  * Fill the window when the lookahead becomes insufficient.
1852  * Updates strstart and lookahead, and sets eofile if end of input file.
1853  *
1854  * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
1855  * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
1856  *    At least one byte has been read, or eofile is set; file reads are
1857  *    performed for at least two bytes (required for the translate_eol option).
1858  */
1859 void fill_window(TState &state)
1860 {
1861     register unsigned n, m;
1862     unsigned more;    /* Amount of free space at the end of the window. */
1863 
1864     do {
1865         more = (unsigned)(state.ds.window_size - (ulg)state.ds.lookahead - (ulg)state.ds.strstart);
1866 
1867         /* If the window is almost full and there is insufficient lookahead,
1868          * move the upper half to the lower one to make room in the upper half.
1869          */
1870         if (more == (unsigned)EOF) {
1871             /* Very unlikely, but possible on 16 bit machine if strstart == 0
1872              * and lookahead == 1 (input done one byte at time)
1873              */
1874             more--;
1875 
1876         /* For MMAP or BIG_MEM, the whole input file is already in memory so
1877          * we must not perform sliding. We must however call (*read_buf)() in
1878          * order to compute the crc, update lookahead and possibly set eofile.
1879          */
1880         } else if (state.ds.strstart >= WSIZE+MAX_DIST && state.ds.sliding) {
1881 
1882             /* By the IN assertion, the window is not empty so we can't confuse
1883              * more == 0 with more == 64K on a 16 bit machine.
1884              */
1885             memcpy((char*)state.ds.window, (char*)state.ds.window+WSIZE, (unsigned)WSIZE);
1886             state.ds.match_start -= WSIZE;
1887             state.ds.strstart    -= WSIZE; /* we now have strstart >= MAX_DIST: */
1888 
1889             state.ds.block_start -= (long) WSIZE;
1890 
1891             for (n = 0; n < HASH_SIZE; n++) {
1892                 m = state.ds.head[n];
1893                 state.ds.head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
1894             }
1895             for (n = 0; n < WSIZE; n++) {
1896                 m = state.ds.prev[n];
1897                 state.ds.prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
1898                 /* If n is not on any hash chain, prev[n] is garbage but
1899                  * its value will never be used.
1900                  */
1901             }
1902             more += WSIZE;
1903         }
1904         if (state.ds.eofile) return;
1905 
1906         /* If there was no sliding:
1907          *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
1908          *    more == window_size - lookahead - strstart
1909          * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
1910          * => more >= window_size - 2*WSIZE + 2
1911          * In the MMAP or BIG_MEM case (not yet supported in gzip),
1912          *   window_size == input_size + MIN_LOOKAHEAD  &&
1913          *   strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD.
1914          * Otherwise, window_size == 2*WSIZE so more >= 2.
1915          * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
1916          */
1917         Assert(state,more >= 2, "more < 2");
1918 
1919         n = state.readfunc(state, (char*)state.ds.window+state.ds.strstart+state.ds.lookahead, more);
1920 
1921         if (n == 0 || n == (unsigned)EOF) {
1922             state.ds.eofile = 1;
1923         } else {
1924             state.ds.lookahead += n;
1925         }
1926     } while (state.ds.lookahead < MIN_LOOKAHEAD && !state.ds.eofile);
1927 }
1928 
1929 /* ===========================================================================
1930  * Flush the current block, with given end-of-file flag.
1931  * IN assertion: strstart is set to the end of the current match.
1932  */
1933 #define FLUSH_BLOCK(state,eof) \
1934    flush_block(state,state.ds.block_start >= 0L ? (char*)&state.ds.window[(unsigned)state.ds.block_start] : \
1935                 (char*)NULL, (long)state.ds.strstart - state.ds.block_start, (eof))
1936 
1937 /* ===========================================================================
1938  * Processes a new input file and return its compressed length. This
1939  * function does not perform lazy evaluation of matches and inserts
1940  * new strings in the dictionary only for unmatched strings or for short
1941  * matches. It is used only for the fast compression options.
1942  */
1943 ulg deflate_fast(TState &state)
1944 {
1945     IPos hash_head = NIL;       /* head of the hash chain */
1946     int flush;                  /* set if current block must be flushed */
1947     unsigned match_length = 0;  /* length of best match */
1948 
1949     state.ds.prev_length = MIN_MATCH-1;
1950     while (state.ds.lookahead != 0) {
1951         /* Insert the string window[strstart .. strstart+2] in the
1952          * dictionary, and set hash_head to the head of the hash chain:
1953          */
1954         if (state.ds.lookahead >= MIN_MATCH)
1955         INSERT_STRING(state.ds.strstart, hash_head);
1956 
1957         /* Find the longest match, discarding those <= prev_length.
1958          * At this point we have always match_length < MIN_MATCH
1959          */
1960         if (hash_head != NIL && state.ds.strstart - hash_head <= MAX_DIST) {
1961             /* To simplify the code, we prevent matches with the string
1962              * of window index 0 (in particular we have to avoid a match
1963              * of the string with itself at the start of the input file).
1964              */
1965             /* Do not look for matches beyond the end of the input.
1966              * This is necessary to make deflate deterministic.
1967              */
1968             if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead;
1969             match_length = longest_match (state,hash_head);
1970             /* longest_match() sets match_start */
1971             if (match_length > state.ds.lookahead) match_length = state.ds.lookahead;
1972         }
1973         if (match_length >= MIN_MATCH) {
1974             check_match(state,state.ds.strstart, state.ds.match_start, match_length);
1975 
1976             flush = ct_tally(state,state.ds.strstart-state.ds.match_start, match_length - MIN_MATCH);
1977 
1978             state.ds.lookahead -= match_length;
1979 
1980             /* Insert new strings in the hash table only if the match length
1981              * is not too large. This saves time but degrades compression.
1982              */
1983             if (match_length <= state.ds.max_insert_length
1984                 && state.ds.lookahead >= MIN_MATCH) {
1985                 match_length--; /* string at strstart already in hash table */
1986                 do {
1987                     state.ds.strstart++;
1988                     INSERT_STRING(state.ds.strstart, hash_head);
1989                     /* strstart never exceeds WSIZE-MAX_MATCH, so there are
1990                      * always MIN_MATCH bytes ahead.
1991                      */
1992                 } while (--match_length != 0);
1993                 state.ds.strstart++;
1994             } else {
1995                 state.ds.strstart += match_length;
1996                 match_length = 0;
1997                 state.ds.ins_h = state.ds.window[state.ds.strstart];
1998                 UPDATE_HASH(state.ds.ins_h, state.ds.window[state.ds.strstart+1]);
1999                 Assert(state,MIN_MATCH==3,"Call UPDATE_HASH() MIN_MATCH-3 more times");
2000             }
2001         } else {
2002             /* No match, output a literal byte */
2003             flush = ct_tally (state,0, state.ds.window[state.ds.strstart]);
2004             state.ds.lookahead--;
2005             state.ds.strstart++;
2006         }
2007         if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart;
2008 
2009         /* Make sure that we always have enough lookahead, except
2010          * at the end of the input file. We need MAX_MATCH bytes
2011          * for the next match, plus MIN_MATCH bytes to insert the
2012          * string following the next match.
2013          */
2014         if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
2015     }
2016     return FLUSH_BLOCK(state,1); /* eof */
2017 }
2018 
2019 /* ===========================================================================
2020  * Same as above, but achieves better compression. We use a lazy
2021  * evaluation for matches: a match is finally adopted only if there is
2022  * no better match at the next window position.
2023  */
2024 ulg deflate(TState &state)
2025 {
2026     IPos hash_head = NIL;       /* head of hash chain */
2027     IPos prev_match;            /* previous match */
2028     int flush;                  /* set if current block must be flushed */
2029     int match_available = 0;    /* set if previous match exists */
2030     register unsigned match_length = MIN_MATCH-1; /* length of best match */
2031 
2032     if (state.level <= 3) return deflate_fast(state); /* optimized for speed */
2033 
2034     /* Process the input block. */
2035     while (state.ds.lookahead != 0) {
2036         /* Insert the string window[strstart .. strstart+2] in the
2037          * dictionary, and set hash_head to the head of the hash chain:
2038          */
2039         if (state.ds.lookahead >= MIN_MATCH)
2040         INSERT_STRING(state.ds.strstart, hash_head);
2041 
2042         /* Find the longest match, discarding those <= prev_length.
2043          */
2044         state.ds.prev_length = match_length, prev_match = state.ds.match_start;
2045         match_length = MIN_MATCH-1;
2046 
2047         if (hash_head != NIL && state.ds.prev_length < state.ds.max_lazy_match &&
2048             state.ds.strstart - hash_head <= MAX_DIST) {
2049             /* To simplify the code, we prevent matches with the string
2050              * of window index 0 (in particular we have to avoid a match
2051              * of the string with itself at the start of the input file).
2052              */
2053             /* Do not look for matches beyond the end of the input.
2054              * This is necessary to make deflate deterministic.
2055              */
2056             if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead;
2057             match_length = longest_match (state,hash_head);
2058             /* longest_match() sets match_start */
2059             if (match_length > state.ds.lookahead) match_length = state.ds.lookahead;
2060 
2061             /* Ignore a length 3 match if it is too distant: */
2062             if (match_length == MIN_MATCH && state.ds.strstart-state.ds.match_start > TOO_FAR){
2063                 /* If prev_match is also MIN_MATCH, match_start is garbage
2064                  * but we will ignore the current match anyway.
2065                  */
2066                 match_length = MIN_MATCH-1;
2067             }
2068         }
2069         /* If there was a match at the previous step and the current
2070          * match is not better, output the previous match:
2071          */
2072         if (state.ds.prev_length >= MIN_MATCH && match_length <= state.ds.prev_length) {
2073             unsigned max_insert = state.ds.strstart + state.ds.lookahead - MIN_MATCH;
2074             check_match(state,state.ds.strstart-1, prev_match, state.ds.prev_length);
2075             flush = ct_tally(state,state.ds.strstart-1-prev_match, state.ds.prev_length - MIN_MATCH);
2076 
2077             /* Insert in hash table all strings up to the end of the match.
2078              * strstart-1 and strstart are already inserted.
2079              */
2080             state.ds.lookahead -= state.ds.prev_length-1;
2081             state.ds.prev_length -= 2;
2082             do {
2083                 if (++state.ds.strstart <= max_insert) {
2084                     INSERT_STRING(state.ds.strstart, hash_head);
2085                     /* strstart never exceeds WSIZE-MAX_MATCH, so there are
2086                      * always MIN_MATCH bytes ahead.
2087                      */
2088                 }
2089             } while (--state.ds.prev_length != 0);
2090             state.ds.strstart++;
2091             match_available = 0;
2092             match_length = MIN_MATCH-1;
2093 
2094             if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart;
2095 
2096         } else if (match_available) {
2097             /* If there was no match at the previous position, output a
2098              * single literal. If there was a match but the current match
2099              * is longer, truncate the previous match to a single literal.
2100              */
2101             if (ct_tally (state,0, state.ds.window[state.ds.strstart-1])) {
2102                 FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart;
2103             }
2104             state.ds.strstart++;
2105             state.ds.lookahead--;
2106         } else {
2107             /* There is no previous match to compare with, wait for
2108              * the next step to decide.
2109              */
2110             match_available = 1;
2111             state.ds.strstart++;
2112             state.ds.lookahead--;
2113         }
2114 //        Assert(state,strstart <= isize && lookahead <= isize, "a bit too far");
2115 
2116         /* Make sure that we always have enough lookahead, except
2117          * at the end of the input file. We need MAX_MATCH bytes
2118          * for the next match, plus MIN_MATCH bytes to insert the
2119          * string following the next match.
2120          */
2121         if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
2122     }
2123     if (match_available) ct_tally (state,0, state.ds.window[state.ds.strstart-1]);
2124 
2125     return FLUSH_BLOCK(state,1); /* eof */
2126 }
2127 
2128 
2129 
2130 
2131 
2132 
2133 
2134 
2135 
2136 
2137 
2138 
2139 int putlocal(struct zlist *z, WRITEFUNC wfunc,void *param)
2140 { // Write a local header described by *z to file *f.  Return a ZE_ error code.
2141   PUTLG(LOCSIG, f);
2142   PUTSH(z->ver, f);
2143   PUTSH(z->lflg, f);
2144   PUTSH(z->how, f);
2145   PUTLG(z->tim, f);
2146   PUTLG(z->crc, f);
2147   PUTLG(z->siz, f);
2148   PUTLG(z->len, f);
2149   PUTSH(z->nam, f);
2150   PUTSH(z->ext, f);
2151   size_t res = (size_t)wfunc(param, z->iname, (unsigned int)z->nam);
2152   if (res!=z->nam) return ZE_TEMP;
2153   if (z->ext)
2154   { res = (size_t)wfunc(param, z->extra, (unsigned int)z->ext);
2155     if (res!=z->ext) return ZE_TEMP;
2156   }
2157   return ZE_OK;
2158 }
2159 
2160 int putextended(struct zlist *z, WRITEFUNC wfunc, void *param)
2161 { // Write an extended local header described by *z to file *f. Returns a ZE_ code
2162   PUTLG(EXTLOCSIG, f);
2163   PUTLG(z->crc, f);
2164   PUTLG(z->siz, f);
2165   PUTLG(z->len, f);
2166   return ZE_OK;
2167 }
2168 
2169 int putcentral(struct zlist *z, WRITEFUNC wfunc, void *param)
2170 { // Write a central header entry of *z to file *f. Returns a ZE_ code.
2171   PUTLG(CENSIG, f);
2172   PUTSH(z->vem, f);
2173   PUTSH(z->ver, f);
2174   PUTSH(z->flg, f);
2175   PUTSH(z->how, f);
2176   PUTLG(z->tim, f);
2177   PUTLG(z->crc, f);
2178   PUTLG(z->siz, f);
2179   PUTLG(z->len, f);
2180   PUTSH(z->nam, f);
2181   PUTSH(z->cext, f);
2182   PUTSH(z->com, f);
2183   PUTSH(z->dsk, f);
2184   PUTSH(z->att, f);
2185   PUTLG(z->atx, f);
2186   PUTLG(z->off, f);
2187   if ((size_t)wfunc(param, z->iname, (unsigned int)z->nam) != z->nam ||
2188       (z->cext && (size_t)wfunc(param, z->cextra, (unsigned int)z->cext) != z->cext) ||
2189       (z->com && (size_t)wfunc(param, z->comment, (unsigned int)z->com) != z->com))
2190     return ZE_TEMP;
2191   return ZE_OK;
2192 }
2193 
2194 
2195 int putend(int n, ulg s, ulg c, extent m, char *z, WRITEFUNC wfunc, void *param)
2196 { // write the end of the central-directory-data to file *f.
2197   PUTLG(ENDSIG, f);
2198   PUTSH(0, f);
2199   PUTSH(0, f);
2200   PUTSH(n, f);
2201   PUTSH(n, f);
2202   PUTLG(s, f);
2203   PUTLG(c, f);
2204   PUTSH(m, f);
2205   // Write the comment, if any
2206   if (m && wfunc(param, z, (unsigned int)m) != m) return ZE_TEMP;
2207   return ZE_OK;
2208 }
2209 
2210 
2211 
2212 
2213 
2214 
2215 const ulg crc_table[256] = {
2216   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
2217   0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
2218   0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
2219   0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
2220   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
2221   0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
2222   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
2223   0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
2224   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
2225   0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
2226   0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
2227   0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
2228   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
2229   0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
2230   0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
2231   0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
2232   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
2233   0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
2234   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
2235   0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
2236   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
2237   0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
2238   0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
2239   0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
2240   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
2241   0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
2242   0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
2243   0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
2244   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
2245   0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
2246   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
2247   0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
2248   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
2249   0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
2250   0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
2251   0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
2252   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
2253   0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
2254   0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
2255   0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
2256   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
2257   0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
2258   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
2259   0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
2260   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
2261   0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
2262   0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
2263   0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
2264   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
2265   0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
2266   0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
2267   0x2d02ef8dL
2268 };
2269 
2270 #define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
2271 #define DO1(buf)  crc = CRC32(crc, *buf++)
2272 #define DO2(buf)  DO1(buf); DO1(buf)
2273 #define DO4(buf)  DO2(buf); DO2(buf)
2274 #define DO8(buf)  DO4(buf); DO4(buf)
2275 
2276 ulg crc32(ulg crc, const uch *buf, extent len)
2277 { if (buf==NULL) return 0L;
2278   crc = crc ^ 0xffffffffL;
2279   while (len >= 8) {DO8(buf); len -= 8;}
2280   if (len) do {DO1(buf);} while (--len);
2281   return crc ^ 0xffffffffL;  // (instead of ~c for 64-bit machines)
2282 }
2283 
2284 
2285 void update_keys(unsigned long *keys, char c)
2286 { keys[0] = CRC32(keys[0],c);
2287   keys[1] += keys[0] & 0xFF;
2288   keys[1] = keys[1]*134775813L +1;
2289   keys[2] = CRC32(keys[2], keys[1] >> 24);
2290 }
2291 char decrypt_byte(unsigned long *keys)
2292 { unsigned temp = ((unsigned)keys[2] & 0xffff) | 2;
2293   return (char)(((temp * (temp ^ 1)) >> 8) & 0xff);
2294 }
2295 char zencode(unsigned long *keys, char c)
2296 { int t=decrypt_byte(keys);
2297   update_keys(keys,c);
2298   return (char)(t^c);
2299 }
2300 
2301 
2302 
2303 
2304 
2305 
2306 
2307 int lustricmp(const TCHAR *sa, const TCHAR *sb)
2308 { for (const TCHAR *ca=sa, *cb=sb; ; ca++, cb++)
2309   { int ia=tolower(*ca), ib=tolower(*cb);
2310     if (ia==ib && ia==0) return 0;
2311     if (ia==ib) continue;
2312     if (ia<ib) return -1;
2313     if (ia>ib) return 1;
2314   }
2315 }
2316 
2317 
2318 bool HasZipSuffix(const TCHAR *fn)
2319 { const TCHAR *ext = fn+_tcslen(fn);
2320   while (ext>fn && *ext!='.') ext--;
2321   if (ext==fn && *ext!='.') return false;
2322   if (lustricmp(ext,_T(".Z"))==0) return true;
2323   if (lustricmp(ext,_T(".zip"))==0) return true;
2324   if (lustricmp(ext,_T(".zoo"))==0) return true;
2325   if (lustricmp(ext,_T(".arc"))==0) return true;
2326   if (lustricmp(ext,_T(".lzh"))==0) return true;
2327   if (lustricmp(ext,_T(".arj"))==0) return true;
2328   if (lustricmp(ext,_T(".gz"))==0) return true;
2329   if (lustricmp(ext,_T(".tgz"))==0) return true;
2330   return false;
2331 }
2332 
2333 
2334 
2335 
2336 
2337 
2338 
2339 
2340 class TZip
2341 { public:
2342   TZip(const char *pwd) : hfout(0),mustclosehfout(false),hmapout(0),zfis(0),obuf(0),hfin(0),writ(0),oerr(false),hasputcen(false),ooffset(0),encwriting(false),encbuf(0),password(0), state(0) {if (pwd!=0 && *pwd!=0) {password=new char[strlen(pwd)+1]; strcpy(password,pwd);}}
2343   ~TZip() {if (state!=0) delete state; state=0; if (encbuf!=0) delete[] encbuf; encbuf=0; if (password!=0) delete[] password; password=0;}
2344 
2345   // These variables say about the file we're writing into
2346   // We can write to pipe, file-by-handle, file-by-name, memory-to-memmapfile
2347   char *password;           // keep a copy of the password
2348   HANDLE hfout;             // if valid, we'll write here (for files or pipes)
2349   bool mustclosehfout;      // if true, we are responsible for closing hfout
2350   HANDLE hmapout;           // otherwise, we'll write here (for memmap)
2351   unsigned ooffset;         // for hfout, this is where the pointer was initially
2352   ZRESULT oerr;             // did a write operation give rise to an error?
2353   unsigned writ;            // how far have we written. This is maintained by Add, not write(), to avoid confusion over seeks
2354   bool ocanseek;            // can we seek?
2355   char *obuf;               // this is where we've locked mmap to view.
2356   unsigned int opos;        // current pos in the mmap
2357   unsigned int mapsize;     // the size of the map we created
2358   bool hasputcen;           // have we yet placed the central directory?
2359   bool encwriting;          // if true, then we'll encrypt stuff using 'keys' before we write it to disk
2360   unsigned long keys[3];    // keys are initialised inside Add()
2361   char *encbuf;             // if encrypting, then this is a temporary workspace for encrypting the data
2362   unsigned int encbufsize;  // (to be used and resized inside write(), and deleted in the destructor)
2363   //
2364   TZipFileInfo *zfis;       // each file gets added onto this list, for writing the table at the end
2365   TState *state;            // we use just one state object per zip, because it's big (500k)
2366 
2367   ZRESULT Create(void *z,unsigned int len,DWORD flags);
2368   static unsigned sflush(void *param,const char *buf, unsigned *size);
2369   static unsigned swrite(void *param,const char *buf, unsigned size);
2370   unsigned int write(const char *buf,unsigned int size);
2371   bool oseek(unsigned int pos);
2372   ZRESULT GetMemory(void **pbuf, unsigned long *plen);
2373   ZRESULT Close();
2374 
2375   // some variables to do with the file currently being read:
2376   // I haven't done it object-orientedly here, just put them all
2377   // together, since OO didn't seem to make the design any clearer.
2378   ulg attr; iztimes times; ulg timestamp;  // all open_* methods set these
2379   bool iseekable; long isize,ired;         // size is not set until close() on pips
2380   ulg crc;                                 // crc is not set until close(). iwrit is cumulative
2381   HANDLE hfin; bool selfclosehf;           // for input files and pipes
2382   const char *bufin; unsigned int lenin,posin; // for memory
2383   // and a variable for what we've done with the input: (i.e. compressed it!)
2384   ulg csize;                               // compressed size, set by the compression routines
2385   // and this is used by some of the compression routines
2386   char buf[16384];
2387 
2388 
2389   ZRESULT open_file(const TCHAR *fn);
2390   ZRESULT open_handle(HANDLE hf,unsigned int len);
2391   ZRESULT open_mem(void *src,unsigned int len);
2392   ZRESULT open_dir();
2393   static unsigned sread(TState &s,char *buf,unsigned size);
2394   unsigned read(char *buf, unsigned size);
2395   ZRESULT iclose();
2396 
2397   ZRESULT ideflate(TZipFileInfo *zfi);
2398   ZRESULT istore();
2399 
2400   ZRESULT Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags);
2401   ZRESULT AddCentral();
2402 
2403 };
2404 
2405 
2406 
2407 ZRESULT TZip::Create(void *z,unsigned int len,DWORD flags)
2408 { if (hfout!=0 || hmapout!=0 || obuf!=0 || writ!=0 || oerr!=ZR_OK || hasputcen) return ZR_NOTINITED;
2409   //
2410   if (flags==ZIP_HANDLE)
2411   { HANDLE hf = (HANDLE)z;
2412     hfout=hf; mustclosehfout=false;
2413 #ifdef DuplicateHandle
2414     BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&hfout,0,FALSE,DUPLICATE_SAME_ACCESS);
2415     if (res) mustclosehandle=true;
2416 #endif
2417     // now we have hfout. Either we duplicated the handle and we close it ourselves
2418     // (while the caller closes h themselves), or we couldn't duplicate it.
2419     DWORD res=GetFilePosZ(hfout);
2420     ocanseek = (res!=0xFFFFFFFF);
2421     ooffset = ocanseek ? res : 0;
2422     return ZR_OK;
2423   }
2424   else if (flags==ZIP_FILENAME)
2425   { const TCHAR *fn = (const TCHAR*)z;
2426 #ifdef ZIP_STD
2427     hfout = fopen(fn,"wb");
2428     if (hfout==0) return ZR_NOFILE;
2429 #else
2430     hfout = CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
2431     if (hfout==INVALID_HANDLE_VALUE) {hfout=0; return ZR_NOFILE;}
2432 #endif
2433     ocanseek=true;
2434     ooffset=0;
2435     mustclosehfout=true;
2436     return ZR_OK;
2437   }
2438   else if (flags==ZIP_MEMORY)
2439   { unsigned int size = len;
2440     if (size==0) return ZR_MEMSIZE;
2441 #ifdef ZIP_STD
2442     if (z!=0) obuf=(char*)z;
2443     else return ZR_ARGS;
2444 #else
2445     if (z!=0) obuf=(char*)z;
2446     else
2447     { hmapout = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,size,NULL);
2448       if (hmapout==NULL) return ZR_NOALLOC;
2449       obuf = (char*)MapViewOfFile(hmapout,FILE_MAP_ALL_ACCESS,0,0,size);
2450       if (obuf==0) {CloseHandle(hmapout); hmapout=0; return ZR_NOALLOC;}
2451     }
2452 #endif
2453     ocanseek=true;
2454     opos=0; mapsize=size;
2455     return ZR_OK;
2456   }
2457   else return ZR_ARGS;
2458 }
2459 
2460 unsigned TZip::sflush(void *param,const char *buf, unsigned *size)
2461 { // static
2462   if (*size==0) return 0;
2463   TZip *zip = (TZip*)param;
2464   unsigned int writ = zip->write(buf,*size);
2465   if (writ!=0) *size=0;
2466   return writ;
2467 }
2468 unsigned TZip::swrite(void *param,const char *buf, unsigned size)
2469 { // static
2470   if (size==0) return 0;
2471   TZip *zip=(TZip*)param; return zip->write(buf,size);
2472 }
2473 unsigned int TZip::write(const char *buf,unsigned int size)
2474 { const char *srcbuf=buf;
2475   if (encwriting)
2476   { if (encbuf!=0 && encbufsize<size) {delete[] encbuf; encbuf=0;}
2477     if (encbuf==0) {encbuf=new char[size*2]; encbufsize=size;}
2478     memcpy(encbuf,buf,size);
2479     for (unsigned int i=0; i<size; i++) encbuf[i]=zencode(keys,encbuf[i]);
2480     srcbuf=encbuf;
2481   }
2482   if (obuf!=0)
2483   { if (opos+size>=mapsize) {oerr=ZR_MEMSIZE; return 0;}
2484     memcpy(obuf+opos, srcbuf, size);
2485     opos+=size;
2486     return size;
2487   }
2488   else if (hfout!=0)
2489   {
2490 #ifdef ZIP_STD
2491     DWORD writ=(DWORD)fwrite(srcbuf,1,size,hfout);
2492 #else
2493     DWORD writ; WriteFile(hfout,srcbuf,size,&writ,NULL);
2494 #endif
2495     return writ;
2496   }
2497   oerr=ZR_NOTINITED; return 0;
2498 }
2499 
2500 bool TZip::oseek(unsigned int pos)
2501 { if (!ocanseek) {oerr=ZR_SEEK; return false;}
2502   if (obuf!=0)
2503   { if (pos>=mapsize) {oerr=ZR_MEMSIZE; return false;}
2504     opos=pos;
2505     return true;
2506   }
2507   else if (hfout!=0)
2508   { 
2509 #ifdef ZIP_STD
2510     fseek(hfout,pos+ooffset,SEEK_SET);
2511 #else
2512     SetFilePointer(hfout,pos+ooffset,NULL,FILE_BEGIN);
2513 #endif
2514     return true;
2515   }
2516   oerr=ZR_NOTINITED; return 0;
2517 }
2518 
2519 ZRESULT TZip::GetMemory(void **pbuf, unsigned long *plen)
2520 { // When the user calls GetMemory, they're presumably at the end
2521   // of all their adding. In any case, we have to add the central
2522   // directory now, otherwise the memory we tell them won't be complete.
2523   if (!hasputcen) AddCentral(); hasputcen=true;
2524   if (pbuf!=NULL) *pbuf=(void*)obuf;
2525   if (plen!=NULL) *plen=writ;
2526   if (obuf==NULL) return ZR_NOTMMAP;
2527   return ZR_OK;
2528 }
2529 
2530 ZRESULT TZip::Close()
2531 { // if the directory hadn't already been added through a call to GetMemory,
2532   // then we do it now
2533   ZRESULT res=ZR_OK; if (!hasputcen) res=AddCentral(); hasputcen=true;
2534 #ifdef ZIP_STD
2535   if (hfout!=0 && mustclosehfout) fclose(hfout); hfout=0; mustclosehfout=false;
2536 #else
2537   if (obuf!=0 && hmapout!=0) UnmapViewOfFile(obuf); obuf=0;
2538   if (hmapout!=0) CloseHandle(hmapout); hmapout=0;
2539   if (hfout!=0 && mustclosehfout) CloseHandle(hfout); hfout=0; mustclosehfout=false;
2540 #endif
2541   return res;
2542 }
2543 
2544 
2545 
2546 
2547 ZRESULT TZip::open_file(const TCHAR *fn)
2548 { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0;
2549   if (fn==0) return ZR_ARGS;
2550 #ifdef ZIP_STD
2551   HANDLE hf = fopen(fn,"rb");
2552   if (hf==0) return ZR_NOFILE;
2553   ZRESULT res = open_handle(hf,0);
2554   if (res!=ZR_OK) {fclose(hf); return res;}
2555 #else
2556   HANDLE hf = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
2557   if (hf==INVALID_HANDLE_VALUE) return ZR_NOFILE;
2558   ZRESULT res = open_handle(hf,0);
2559   if (res!=ZR_OK) {CloseHandle(hf); return res;}
2560 #endif
2561   selfclosehf=true;
2562   return ZR_OK;
2563 }
2564 ZRESULT TZip::open_handle(HANDLE hf,unsigned int len)
2565 { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0;
2566   if (hf==0 || hf==INVALID_HANDLE_VALUE) return ZR_ARGS;
2567   bool canseek;
2568 #ifdef ZIP_STD
2569     struct stat st; fstat(fileno(hf),&st); canseek = S_ISREG(st.st_mode);
2570 #else
2571   DWORD res = SetFilePointer(hfout,0,0,FILE_CURRENT);
2572   canseek = (res!=0xFFFFFFFF);
2573 #endif
2574   if (canseek)
2575   { ZRESULT res = GetFileInfo(hf,&attr,&isize,&times,&timestamp);
2576     if (res!=ZR_OK) return res;
2577 #ifdef ZIP_STD
2578     fseek(hf,0,SEEK_SET);
2579 #else
2580     SetFilePointer(hf,0,NULL,FILE_BEGIN); // because GetFileInfo will have screwed it up
2581 #endif
2582     iseekable=true; hfin=hf;
2583     return ZR_OK;
2584   }
2585   else
2586   { attr= 0x80000000;      // just a normal file
2587     isize = -1;            // can't know size until at the end
2588     if (len!=0) isize=len; // unless we were told explicitly!
2589     iseekable=false;
2590     WORD dosdate, dostime; GetNow(&times.atime, &dosdate, &dostime);
2591     times.mtime=times.atime;
2592     times.ctime=times.atime;
2593     timestamp = (WORD)dostime | (((DWORD)dosdate)<<16);
2594     hfin=hf;
2595     return ZR_OK;
2596   }
2597 }
2598 ZRESULT TZip::open_mem(void *src,unsigned int len)
2599 { hfin=0; bufin=(const char*)src; selfclosehf=false; crc=CRCVAL_INITIAL; ired=0; csize=0; ired=0;
2600   lenin=len; posin=0;
2601   if (src==0 || len==0) return ZR_ARGS;
2602   attr= 0x80000000; // just a normal file
2603   isize = len;
2604   iseekable=true;
2605   WORD dosdate, dostime; GetNow(&times.atime, &dosdate, &dostime);
2606   times.mtime=times.atime;
2607   times.ctime=times.atime;
2608   timestamp = (WORD)dostime | (((DWORD)dosdate)<<16);
2609   return ZR_OK;
2610 }
2611 ZRESULT TZip::open_dir()
2612 { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0;
2613   attr= 0x41C00010; // a readable writable directory, and again directory
2614   isize = 0;
2615   iseekable=false;
2616   WORD dosdate, dostime; GetNow(&times.atime, &dosdate, &dostime);
2617   times.mtime=times.atime;
2618   times.ctime=times.atime;
2619   timestamp = (WORD)dostime | (((DWORD)dosdate)<<16);
2620   return ZR_OK;
2621 }
2622 
2623 unsigned TZip::sread(TState &s,char *buf,unsigned size)
2624 { // static
2625   TZip *zip = (TZip*)s.param;
2626   return zip->read(buf,size);
2627 }
2628 
2629 unsigned TZip::read(char *buf, unsigned size)
2630 { if (bufin!=0)
2631   { if (posin>=lenin) return 0; // end of input
2632     ulg red = lenin-posin;
2633     if (red>size) red=size;
2634     memcpy(buf, bufin+posin, red);
2635     posin += red;
2636     ired += red;
2637     crc = crc32(crc, (uch*)buf, red);
2638     return red;
2639   }
2640   else if (hfin!=0)
2641   { DWORD red;
2642 #ifdef ZIP_STD
2643     red = (DWORD)fread(buf,1,size,hfin);
2644     if (red==0) return 0;
2645 #else
2646     BOOL ok = ReadFile(hfin,buf,size,&red,NULL);
2647     if (!ok) return 0;
2648 #endif
2649     ired += red;
2650     crc = crc32(crc, (uch*)buf, red);
2651     return red;
2652   }
2653   else {oerr=ZR_NOTINITED; return 0;}
2654 }
2655 
2656 ZRESULT TZip::iclose()
2657 { 
2658 #ifdef ZIP_STD
2659   if (selfclosehf && hfin!=0) fclose(hfin); hfin=0;
2660 #else
2661   if (selfclosehf && hfin!=0) CloseHandle(hfin); hfin=0;
2662 #endif
2663   bool mismatch = (isize!=-1 && isize!=ired);
2664   isize=ired; // and crc has been being updated anyway
2665   if (mismatch) return ZR_MISSIZE;
2666   else return ZR_OK;
2667 }
2668 
2669 
2670 
2671 ZRESULT TZip::ideflate(TZipFileInfo *zfi)
2672 { if (state==0) state=new TState();
2673   // It's a very big object! 500k! We allocate it on the heap, because PocketPC's
2674   // stack breaks if we try to put it all on the stack. It will be deleted lazily
2675   state->err=0;
2676   state->readfunc=sread; state->flush_outbuf=sflush;
2677   state->param=this; state->level=8; state->seekable=iseekable; state->err=NULL;
2678   // the following line will make ct_init realise it has to perform the init
2679   state->ts.static_dtree[0].dl.len = 0;
2680   // Thanks to Alvin77 for this crucial fix:
2681   state->ds.window_size=0;
2682   //  I think that covers everything that needs to be initted.
2683   //
2684   bi_init(*state,buf, sizeof(buf), 1); // it used to be just 1024-size, not 16384 as here
2685   ct_init(*state,&zfi->att);
2686   lm_init(*state,state->level, &zfi->flg);
2687   ulg sz = deflate(*state);
2688   csize=sz;
2689   ZRESULT r=ZR_OK; if (state->err!=NULL) r=ZR_FLATE;
2690   return r;
2691 }
2692 
2693 ZRESULT TZip::istore()
2694 { ulg size=0;
2695   for (;;)
2696   { unsigned int cin=read(buf,16384); if (cin<=0 || cin==(unsigned int)EOF) break;
2697     unsigned int cout = write(buf,cin); if (cout!=cin) return ZR_MISSIZE;
2698     size += cin;
2699   }
2700   csize=size;
2701   return ZR_OK;
2702 }
2703 
2704 
2705 
2706 
2707 
2708 bool has_seeded=false;
2709 ZRESULT TZip::Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags)
2710 { if (oerr) return ZR_FAILED;
2711   if (hasputcen) return ZR_ENDED;
2712 
2713   // if we use password encryption, then every isize and csize is 12 bytes bigger
2714   int passex=0; if (password!=0 && flags!=ZIP_FOLDER) passex=12;
2715 
2716   // zip has its own notion of what its names should look like: i.e. dir/file.stuff
2717   TCHAR dstzn[MAX_PATH]; _tcsncpy(dstzn,odstzn,MAX_PATH); dstzn[MAX_PATH-1]=0;
2718   if (*dstzn==0) return ZR_ARGS;
2719   TCHAR *d=dstzn; while (*d!=0) {if (*d=='\\') *d='/'; d++;}
2720   bool isdir = (flags==ZIP_FOLDER);
2721   bool needs_trailing_slash = (isdir && dstzn[_tcslen(dstzn)-1]!='/');
2722   int method=DEFLATE; if (isdir || HasZipSuffix(dstzn)) method=STORE;
2723 
2724   // now open whatever was our input source:
2725   ZRESULT openres;
2726   if (flags==ZIP_FILENAME) openres=open_file((const TCHAR*)src);
2727   else if (flags==ZIP_HANDLE) openres=open_handle((HANDLE)src,len);
2728   else if (flags==ZIP_MEMORY) openres=open_mem(src,len);
2729   else if (flags==ZIP_FOLDER) openres=open_dir();
2730   else return ZR_ARGS;
2731   if (openres!=ZR_OK) return openres;
2732 
2733   // A zip "entry" consists of a local header (which includes the file name),
2734   // then the compressed data, and possibly an extended local header.
2735 
2736   // Initialize the local header
2737   TZipFileInfo zfi; zfi.nxt=NULL;
2738   strcpy(zfi.name,"");
2739 #ifdef UNICODE
2740   WideCharToMultiByte(CP_UTF8,0,dstzn,-1,zfi.iname,MAX_PATH,0,0);
2741 #else
2742   strncpy(zfi.iname,dstzn,MAX_PATH); zfi.iname[MAX_PATH-1]=0;
2743 #endif
2744   zfi.nam=strlen(zfi.iname);
2745   if (needs_trailing_slash) {strcat(zfi.iname,"/"); zfi.nam++;}
2746   strcpy(zfi.zname,"");
2747   zfi.extra=NULL; zfi.ext=0;   // extra header to go after this compressed data, and its length
2748   zfi.cextra=NULL; zfi.cext=0; // extra header to go in the central end-of-zip directory, and its length
2749   zfi.comment=NULL; zfi.com=0; // comment, and its length
2750   zfi.mark = 1;
2751   zfi.dosflag = 0;
2752   zfi.att = (ush)BINARY;
2753   zfi.vem = (ush)0xB17; // 0xB00 is win32 os-code. 0x17 is 23 in decimal: zip 2.3
2754   zfi.ver = (ush)20;    // Needs PKUNZIP 2.0 to unzip it
2755   zfi.tim = timestamp;
2756   // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc.
2757   zfi.crc = 0;            // to be updated later
2758   zfi.flg = 8;            // 8 means 'there is an extra header'. Assume for the moment that we need it.
2759   if (password!=0 && !isdir) zfi.flg=9;  // and 1 means 'password-encrypted'
2760   zfi.lflg = zfi.flg;     // to be updated later
2761   zfi.how = (ush)method;  // to be updated later
2762   zfi.siz = (ulg)(method==STORE && isize>=0 ? isize+passex : 0); // to be updated later
2763   zfi.len = (ulg)(isize);  // to be updated later
2764   zfi.dsk = 0;
2765   zfi.atx = attr;
2766   zfi.off = writ+ooffset;         // offset within file of the start of this local record
2767   // stuff the 'times' structure into zfi.extra
2768 
2769   // nb. apparently there's a problem with PocketPC CE(zip)->CE(unzip) fails. And removing the following block fixes it up.
2770   char xloc[EB_L_UT_SIZE]; zfi.extra=xloc;  zfi.ext=EB_L_UT_SIZE;
2771   char xcen[EB_C_UT_SIZE]; zfi.cextra=xcen; zfi.cext=EB_C_UT_SIZE;
2772   xloc[0]  = 'U';
2773   xloc[1]  = 'T';
2774   xloc[2]  = EB_UT_LEN(3);       // length of data part of e.f.
2775   xloc[3]  = 0;
2776   xloc[4]  = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
2777   xloc[5]  = (char)(times.mtime);
2778   xloc[6]  = (char)(times.mtime >> 8);
2779   xloc[7]  = (char)(times.mtime >> 16);
2780   xloc[8]  = (char)(times.mtime >> 24);
2781   xloc[9]  = (char)(times.atime);
2782   xloc[10] = (char)(times.atime >> 8);
2783   xloc[11] = (char)(times.atime >> 16);
2784   xloc[12] = (char)(times.atime >> 24);
2785   xloc[13] = (char)(times.ctime);
2786   xloc[14] = (char)(times.ctime >> 8);
2787   xloc[15] = (char)(times.ctime >> 16);
2788   xloc[16] = (char)(times.ctime >> 24);
2789   memcpy(zfi.cextra,zfi.extra,EB_C_UT_SIZE);
2790   zfi.cextra[EB_LEN] = EB_UT_LEN(1);
2791 
2792 
2793   // (1) Start by writing the local header:
2794   int r = putlocal(&zfi,swrite,this);
2795   if (r!=ZE_OK) {iclose(); return ZR_WRITE;}
2796   writ += 4 + LOCHEAD + (unsigned int)zfi.nam + (unsigned int)zfi.ext;
2797   if (oerr!=ZR_OK) {iclose(); return oerr;}
2798 
2799   // (1.5) if necessary, write the encryption header
2800   keys[0]=305419896L;
2801   keys[1]=591751049L;
2802   keys[2]=878082192L;
2803   for (const char *cp=password; cp!=0 && *cp!=0; cp++) update_keys(keys,*cp);
2804   // generate some random bytes
2805 #ifdef ZIP_STD
2806   if (!has_seeded) srand((unsigned)time(0));
2807 #else
2808   if (!has_seeded) srand(GetTickCount()^(unsigned long)GetDesktopWindow());
2809 #endif
2810   char encbuf[12]; for (int i=0; i<12; i++) encbuf[i]=(char)((rand()>>7)&0xff);
2811   encbuf[11] = (char)((zfi.tim>>8)&0xff);
2812   for (int ei=0; ei<12; ei++) encbuf[ei]=zencode(keys,encbuf[ei]);
2813   if (password!=0 && !isdir) {swrite(this,encbuf,12); writ+=12;}
2814 
2815   //(2) Write deflated/stored file to zip file
2816   ZRESULT writeres=ZR_OK;
2817   encwriting = (password!=0 && !isdir);  // an object member variable to say whether we write to disk encrypted
2818   if (!isdir && method==DEFLATE) writeres=ideflate(&zfi);
2819   else if (!isdir && method==STORE) writeres=istore();
2820   else if (isdir) csize=0;
2821   encwriting = false;
2822   iclose();
2823   writ += csize;
2824   if (oerr!=ZR_OK) return oerr;
2825   if (writeres!=ZR_OK) return ZR_WRITE;
2826 
2827   // (3) Either rewrite the local header with correct information...
2828   bool first_header_has_size_right = (zfi.siz==csize+passex);
2829   zfi.crc = crc;
2830   zfi.siz = csize+passex;
2831   zfi.len = isize;
2832   if (ocanseek && (password==0 || isdir))
2833   { zfi.how = (ush)method;
2834     if ((zfi.flg & 1) == 0) zfi.flg &= ~8; // clear the extended local header flag
2835     zfi.lflg = zfi.flg;
2836     // rewrite the local header:
2837     if (!oseek(zfi.off-ooffset)) return ZR_SEEK;
2838     if ((r = putlocal(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE;
2839     if (!oseek(writ)) return ZR_SEEK;
2840   }
2841   else
2842   { // (4) ... or put an updated header at the end
2843     if (zfi.how != (ush) method) return ZR_NOCHANGE;
2844     if (method==STORE && !first_header_has_size_right) return ZR_NOCHANGE;
2845     if ((r = putextended(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE;
2846     writ += 16L;
2847     zfi.flg = zfi.lflg; // if flg modified by inflate, for the central index
2848   }
2849   if (oerr!=ZR_OK) return oerr;
2850 
2851   // Keep a copy of the zipfileinfo, for our end-of-zip directory
2852   char *cextra = new char[zfi.cext]; memcpy(cextra,zfi.cextra,zfi.cext); zfi.cextra=cextra;
2853   TZipFileInfo *pzfi = new TZipFileInfo; memcpy(pzfi,&zfi,sizeof(zfi));
2854   if (zfis==NULL) zfis=pzfi;
2855   else {TZipFileInfo *z=zfis; while (z->nxt!=NULL) z=z->nxt; z->nxt=pzfi;}
2856   return ZR_OK;
2857 }
2858 
2859 ZRESULT TZip::AddCentral()
2860 { // write central directory
2861   int numentries = 0;
2862   ulg pos_at_start_of_central = writ;
2863   //ulg tot_unc_size=0, tot_compressed_size=0;
2864   bool okay=true;
2865   for (TZipFileInfo *zfi=zfis; zfi!=NULL; )
2866   { if (okay)
2867     { int res = putcentral(zfi, swrite,this);
2868       if (res!=ZE_OK) okay=false;
2869     }
2870     writ += 4 + CENHEAD + (unsigned int)zfi->nam + (unsigned int)zfi->cext + (unsigned int)zfi->com;
2871     //tot_unc_size += zfi->len;
2872     //tot_compressed_size += zfi->siz;
2873     numentries++;
2874     //
2875     TZipFileInfo *zfinext = zfi->nxt;
2876     if (zfi->cextra!=0) delete[] zfi->cextra;
2877     delete zfi;
2878     zfi = zfinext;
2879   }
2880   ulg center_size = writ - pos_at_start_of_central;
2881   if (okay)
2882   { int res = putend(numentries, center_size, pos_at_start_of_central+ooffset, 0, NULL, swrite,this);
2883     if (res!=ZE_OK) okay=false;
2884     writ += 4 + ENDHEAD + 0;
2885   }
2886   if (!okay) return ZR_WRITE;
2887   return ZR_OK;
2888 }
2889 
2890 
2891 
2892 
2893 
2894 ZRESULT lasterrorZ=ZR_OK;
2895 
2896 unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len)
2897 { if (code==ZR_RECENT) code=lasterrorZ;
2898   const char *msg="unknown zip result code";
2899   switch (code)
2900   { case ZR_OK: msg="Success"; break;
2901     case ZR_NODUPH: msg="Culdn't duplicate handle"; break;
2902     case ZR_NOFILE: msg="Couldn't create/open file"; break;
2903     case ZR_NOALLOC: msg="Failed to allocate memory"; break;
2904     case ZR_WRITE: msg="Error writing to file"; break;
2905     case ZR_NOTFOUND: msg="File not found in the zipfile"; break;
2906     case ZR_MORE: msg="Still more data to unzip"; break;
2907     case ZR_CORRUPT: msg="Zipfile is corrupt or not a zipfile"; break;
2908     case ZR_READ: msg="Error reading file"; break;
2909     case ZR_ARGS: msg="Caller: faulty arguments"; break;
2910     case ZR_PARTIALUNZ: msg="Caller: the file had already been partially unzipped"; break;
2911     case ZR_NOTMMAP: msg="Caller: can only get memory of a memory zipfile"; break;
2912     case ZR_MEMSIZE: msg="Caller: not enough space allocated for memory zipfile"; break;
2913     case ZR_FAILED: msg="Caller: there was a previous error"; break;
2914     case ZR_ENDED: msg="Caller: additions to the zip have already been ended"; break;
2915     case ZR_ZMODE: msg="Caller: mixing creation and opening of zip"; break;
2916     case ZR_NOTINITED: msg="Zip-bug: internal initialisation not completed"; break;
2917     case ZR_SEEK: msg="Zip-bug: trying to seek the unseekable"; break;
2918     case ZR_MISSIZE: msg="Zip-bug: the anticipated size turned out wrong"; break;
2919     case ZR_NOCHANGE: msg="Zip-bug: tried to change mind, but not allowed"; break;
2920     case ZR_FLATE: msg="Zip-bug: an internal error during flation"; break;
2921   }
2922   unsigned int mlen=(unsigned int)strlen(msg);
2923   if (buf==0 || len==0) return mlen;
2924   unsigned int n=mlen; if (n+1>len) n=len-1;
2925   strncpy(buf,msg,n); buf[n]=0;
2926   return mlen;
2927 }
2928 
2929 
2930 
2931 typedef struct
2932 { DWORD flag;
2933   TZip *zip;
2934 } TZipHandleData;
2935 
2936 
2937 HZIP CreateZipInternal(void *z,unsigned int len,DWORD flags, const char *password)
2938 { TZip *zip = new TZip(password);
2939   lasterrorZ = zip->Create(z,len,flags);
2940   if (lasterrorZ!=ZR_OK) {delete zip; return 0;}
2941   TZipHandleData *han = new TZipHandleData;
2942   han->flag=2; han->zip=zip; return (HZIP)han;
2943 }
2944 HZIP CreateZipHandle(HANDLE h, const char *password) {return CreateZipInternal(h,0,ZIP_HANDLE,password);}
2945 HZIP CreateZip(const TCHAR *fn, const char *password) {return CreateZipInternal((void*)fn,0,ZIP_FILENAME,password);}
2946 HZIP CreateZip(void *z,unsigned int len, const char *password) {return CreateZipInternal(z,len,ZIP_MEMORY,password);}
2947 
2948 
2949 ZRESULT ZipAddInternal(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len, DWORD flags)
2950 { if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;}
2951   TZipHandleData *han = (TZipHandleData*)hz;
2952   if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;}
2953   TZip *zip = han->zip;
2954   lasterrorZ = zip->Add(dstzn,src,len,flags);
2955   return lasterrorZ;
2956 }
2957 ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn) {return ZipAddInternal(hz,dstzn,(void*)fn,0,ZIP_FILENAME);}
2958 ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len) {return ZipAddInternal(hz,dstzn,src,len,ZIP_MEMORY);}
2959 ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h) {return ZipAddInternal(hz,dstzn,h,0,ZIP_HANDLE);}
2960 ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len) {return ZipAddInternal(hz,dstzn,h,len,ZIP_HANDLE);}
2961 ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn) {return ZipAddInternal(hz,dstzn,0,0,ZIP_FOLDER);}
2962 
2963 
2964 
2965 ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len)
2966 { if (hz==0) {if (buf!=0) *buf=0; if (len!=0) *len=0; lasterrorZ=ZR_ARGS;return ZR_ARGS;}
2967   TZipHandleData *han = (TZipHandleData*)hz;
2968   if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;}
2969   TZip *zip = han->zip;
2970   lasterrorZ = zip->GetMemory(buf,len);
2971   return lasterrorZ;
2972 }
2973 
2974 ZRESULT CloseZipZ(HZIP hz)
2975 { if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;}
2976   TZipHandleData *han = (TZipHandleData*)hz;
2977   if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;}
2978   TZip *zip = han->zip;
2979   lasterrorZ = zip->Close();
2980   delete zip;
2981   delete han;
2982   return lasterrorZ;
2983 }
2984 
2985 bool IsZipHandleZ(HZIP hz)
2986 { if (hz==0) return false;
2987   TZipHandleData *han = (TZipHandleData*)hz;
2988   return (han->flag==2);
2989 }
View Code

 

posted on 2015-12-10 15:51  可笑痴狂  阅读(19254)  评论(0编辑  收藏  举报