MEXP(void) bncsutil_debug_message_a(const char* message, ...) { char buf[4092]; va_list args; va_start(args, message); vsprintf(buf, message, args); va_end(args); bncsutil_debug_message(buf); }
const char* sys_error_msg() { const char* buffer; DWORD res; res = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, (const void*) 0, (DWORD) 0, (DWORD) 0, (LPTSTR) &buffer, (DWORD) 0, (va_list*) 0); if (!res) { bncsutil_debug_message("error: Failed to get Windows error message."); return default_err_msg; } return buffer; }
MEXP(int) getExeInfo(const char* file_name, char* exe_info, size_t exe_info_size, uint32_t* version, int platform) { const char* base = (char*) 0; unsigned long file_size; FILE* f = (FILE*) 0; int ret; #ifdef MOS_WINDOWS HANDLE hFile; FILETIME ft; SYSTEMTIME st; LPBYTE buf; VS_FIXEDFILEINFO* ffi; DWORD infoSize, bytesRead; #else cm_pe_t pe; cm_pe_resdir_t* root; cm_pe_resdir_t* dir; cm_pe_version_t ffi; size_t i; struct stat st; struct tm* time; #endif if (!file_name || !exe_info || !exe_info_size || !version) return 0; base = basename(file_name); switch (platform) { case BNCSUTIL_PLATFORM_X86: #ifdef MOS_WINDOWS infoSize = GetFileVersionInfoSize(file_name, &bytesRead); if (infoSize == 0) return 0; buf = (LPBYTE) VirtualAlloc(NULL, infoSize, MEM_COMMIT, PAGE_READWRITE); if (buf == NULL) return 0; if (GetFileVersionInfo(file_name, NULL, infoSize, buf) == FALSE) return 0; if (!VerQueryValue(buf, "\\", (LPVOID*) &ffi, (PUINT) &infoSize)) return 0; *version = ((HIWORD(ffi->dwProductVersionMS) & 0xFF) << 24) | ((LOWORD(ffi->dwProductVersionMS) & 0xFF) << 16) | ((HIWORD(ffi->dwProductVersionLS) & 0xFF) << 8) | (LOWORD(ffi->dwProductVersionLS) & 0xFF); #if DEBUG bncsutil_debug_message_a("%s version = %d.%d.%d.%d (0x%08X)", base, (HIWORD(ffi->dwProductVersionMS) & 0xFF), (LOWORD(ffi->dwProductVersionMS) & 0xFF), (HIWORD(ffi->dwProductVersionLS) & 0xFF), (LOWORD(ffi->dwProductVersionLS) & 0xFF), *version); #endif VirtualFree(buf, 0lu, MEM_RELEASE); #else pe = cm_pe_load(file_name); if (!pe) return 0; root = cm_pe_load_resources(pe); if (!root) { cm_pe_unload(pe); return 0; } for (i = 0; i < root->subdir_count; i++) { dir = (root->subdirs + i); if (dir->name == 16) { if (!cm_pe_fixed_version(pe, dir->subdirs->resources, &ffi)) { cm_pe_unload_resources(root); cm_pe_unload(pe); return 0; } break; } } *version = ((HIWORD(ffi.dwProductVersionMS) & 0xFF) << 24) | ((LOWORD(ffi.dwProductVersionMS) & 0xFF) << 16) | ((HIWORD(ffi.dwProductVersionLS) & 0xFF) << 8) | (LOWORD(ffi.dwProductVersionLS) & 0xFF); #if DEBUG bncsutil_debug_message_a("%s version = %d.%d.%d.%d (0x%08X)", base, (HIWORD(ffi.dwProductVersionMS) & 0xFF), (LOWORD(ffi.dwProductVersionMS) & 0xFF), (HIWORD(ffi.dwProductVersionLS) & 0xFF), (LOWORD(ffi.dwProductVersionLS) & 0xFF), *version); #endif cm_pe_unload_resources(root); cm_pe_unload(pe); #endif break; case BNCSUTIL_PLATFORM_MAC: case BNCSUTIL_PLATFORM_OSX: f = fopen(file_name, "r"); if (!f) return 0; if (fseek(f, -4, SEEK_END) != 0) { fclose(f); return 0; } if (fread(version, 4, 1, f) != 1) { fclose(f); return 0; } #ifdef MOS_WINDOWS fclose(f); #endif } #ifdef MOS_WINDOWS hFile = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; file_size = GetFileSize(hFile, NULL); if (!GetFileTime(hFile, &ft, NULL, NULL)) { CloseHandle(hFile); return 0; } if (!FileTimeToSystemTime(&ft, &st)) { CloseHandle(hFile); return 0; } CloseHandle(hFile); ret = snprintf(exe_info, exe_info_size, "%s %02u/%02u/%02u %02u:%02u:%02u %lu", base, st.wMonth, st.wDay, (st.wYear % 100), st.wHour, st.wMinute, st.wSecond, file_size); #else if (!f) f = fopen(file_name, "r"); if (!f) return 0; if (fseek(f, 0, SEEK_END) == -1) { fclose(f); return 0; } file_size = ftell(f); fclose(f); if (stat(file_name, &st) != 0) return 0; time = gmtime(&st.st_mtime); if (!time) return 0; switch (platform) { case BNCSUTIL_PLATFORM_MAC: case BNCSUTIL_PLATFORM_OSX: if (time->tm_year >= 100) // y2k time->tm_year -= 100; break; } ret = (int) snprintf(exe_info, exe_info_size, "%s %02u/%02u/%02u %02u:%02u:%02u %lu", base, (time->tm_mon+1), time->tm_mday, time->tm_year, time->tm_hour, time->tm_min, time->tm_sec, file_size); #endif #if DEBUG bncsutil_debug_message(exe_info); #endif return ret; }
MEXP(int) checkRevision(const char* formula, const char* files[], int numFiles, int mpqNumber, unsigned long* checksum) { long values[4], ovd[4], ovs1[4], ovs2[4]; char ops[4]; const char* token; int curFormula = 0; file_t f; uint8_t* file_buffer; uint32_t* dwBuf; uint32_t* current; size_t seed_count; #if DEBUG int i; bncsutil_debug_message_a("checkRevision(\"%s\", {", formula); for (i = 0; i < numFiles; i++) { bncsutil_debug_message_a("\t\"%s\",", files[i]); } bncsutil_debug_message_a("}, %d, %d, %p);", numFiles, mpqNumber, checksum); #endif if (!formula || !files || numFiles == 0 || mpqNumber <= 0 || !checksum) { bncsutil_debug_message("error: checkRevision() parameter sanity check " "failed"); return 0; } seed_count = checkrevision_seeds.size(); if (seed_count == 0) { initialize_checkrevision_seeds(); seed_count = checkrevision_seeds.size(); } if (seed_count <= (size_t) mpqNumber) { bncsutil_debug_message_a("error: no revision check seed value defined " "for MPQ number %d", mpqNumber); return 0; } token = formula; while (token && *token) { if (*(token + 1) == '=') { int variable = BUCR_GETNUM(*token); if (variable < 0 || variable > 3) { bncsutil_debug_message_a("error: Unknown revision check formula" " variable %c", *token); return 0; } token += 2; // skip over equals sign if (BUCR_ISNUM(*token)) { values[variable] = atol(token); } else { if (curFormula > 3) { // more than 4 operations? bloody hell. bncsutil_debug_message("error: Revision check formula" " contains more than 4 operations; unsupported."); return 0; } ovd[curFormula] = variable; ovs1[curFormula] = BUCR_GETNUM(*token); ops[curFormula] = *(token + 1); ovs2[curFormula] = BUCR_GETNUM(*(token + 2)); curFormula++; } } for (; *token != 0; token++) { if (*token == ' ') { token++; break; } } } // Actual hashing (yay!) // "hash A by the hashcode" values[0] ^= checkrevision_seeds[mpqNumber]; for (int i = 0; i < numFiles; i++) { size_t file_len, remainder, rounded_size, buffer_size; f = file_open(files[i], FILE_READ); if (!f) { bncsutil_debug_message_a("error: Failed to open file %s", files[i]); return 0; } file_len = file_size(f); remainder = file_len % 1024; rounded_size = file_len - remainder; file_buffer = (uint8_t*) file_map(f, file_len, 0); if (!file_buffer) { file_close(f); bncsutil_debug_message_a("error: Failed to map file %s into memory", files[i]); return 0; } if (remainder == 0) { // Mapped buffer may be used directly, without padding. dwBuf = (uint32_t*) file_buffer; buffer_size = file_len; } else { // Must be padded to nearest KB. size_t extra = 1024 - remainder; uint8_t pad = (uint8_t) 0xFF; uint8_t* pad_dest; buffer_size = file_len + extra; dwBuf = (uint32_t*) malloc(buffer_size); if (!dwBuf) { bncsutil_debug_message_a("error: Failed to allocate %d bytes " "of memory as a temporary buffer", buffer_size); file_unmap(f, file_buffer); file_close(f); return 0; } memcpy(dwBuf, file_buffer, file_len); file_unmap(f, file_buffer); file_buffer = (uint8_t*) 0; pad_dest = ((uint8_t*) dwBuf) + file_len; for (size_t j = file_len; j < buffer_size; j++) { *pad_dest++ = pad--; } } current = dwBuf; for (size_t j = 0; j < buffer_size; j += 4) { values[3] = LSB4(*(current++)); for (int k = 0; k < curFormula; k++) { switch (ops[k]) { case '+': values[ovd[k]] = values[ovs1[k]] + values[ovs2[k]]; break; case '-': values[ovd[k]] = values[ovs1[k]] - values[ovs2[k]]; break; case '^': values[ovd[k]] = values[ovs1[k]] ^ values[ovs2[k]]; break; case '*': // well, you never know values[ovd[k]] = values[ovs1[k]] * values[ovs2[k]]; break; case '/': // well, you never know values[ovd[k]] = values[ovs1[k]] / values[ovs2[k]]; break; default: // unrecognized operation // shit file_unmap(f, dwBuf); file_close(f); return 0; } } } if (file_buffer) file_unmap(f, file_buffer); else if (dwBuf && file_buffer == 0) free(dwBuf); // padded buffer file_close(f); } *checksum = (unsigned long) LSB4(values[2]); #if DEBUG bncsutil_debug_message_a("\tChecksum = %lu", *checksum); #endif return 1; }