• FTP客户端上传下载Demo实现


    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,"
    cd %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("
    bit length overflow
    ");
    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
    ", 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("
    gen_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, "
    n %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("
    dyn 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("
    bl 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("
    bl code %2d ", bl_order[rank]);
    1315         send_bits(state,state.ts.bl_tree[bl_order[rank]].dl.len, 3);
    1316     }    
    1317     Trace("
    bl 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("
    lit 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("
    dist 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("
    lit 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("
    dist 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("
    opt %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("
    ");
    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("
    last_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
    ",
    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
  • 相关阅读:
    spring scope 属性的取值
    DefaultTransactionStatus源码
    Spring事务管理接口PlatformTransactionManager的实现类DataSourceTransactionManager
    Spring 框架简介
    PL/SQL游标
    [BC冠军赛(online)]小结
    [hdu5164]ac自动机
    [hdu2222]ac自动机(模板)
    上浮法或漂浮法
    [hdu5213]容斥原理+莫队算法
  • 原文地址:https://www.cnblogs.com/dongsheng/p/5029561.html
Copyright © 2020-2023  润新知