STDCALL int merc_inventory_mpq_load(void) { char path[MAX_PATH], *game_path; if (!merc_load_image_mpq) return 1; if (merc_mpq) return 1; if (SFileOpenArchive(MPQ_NAME, 6100, 2, &merc_mpq)) { LOG("Loaded \""MPQ_NAME"\" from current directory"); return 1; } game_path = util_game_path(); snprintf(path, sizeof(path), "%s/%s", game_path, MPQ_NAME); if (SFileOpenArchive(path, 6100, 2, &merc_mpq)) { LOG("Loaded \""MPQ_NAME"\" from \"%s\"", game_path); return 1; } LOG("Unable to load \""MPQ_NAME"\" or \"%s\".", path); return 1; }
void LoadLocaleMPQFiles(int const locale) { char filename[512]; //Locale-xxXX.MPQ sprintf(filename,"%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &localeMPQ[0])) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } for(int i = 0; i < PATCH_REV_COUNT; ++i) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[i]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); if (!SFileOpenPatchArchive(localeMPQ[0], filename, langs[locale], MPQ_OPEN_READ_ONLY)) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } if (!SFileIsPatchedArchive(localeMPQ[0])) assert(false && "An error occured"); //Others for(int i = 0; i < PATCH_REV_COUNT; ++i) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[i]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &localeMPQ[i+1])) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ failed"); } for(int j = i; j < PATCH_REV_COUNT; ++j) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[j]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); if (!SFileOpenPatchArchive(localeMPQ[i+1], filename, langs[locale], MPQ_OPEN_READ_ONLY)) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } if (!SFileIsPatchedArchive(localeMPQ[i+1])) assert(false && "An error occured"); } }
uint32 ReadMapDBC(int const locale) { HANDLE localeFile; char localMPQ[512]; sprintf(localMPQ, "%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]); if (!SFileOpenArchive(localMPQ, 0, MPQ_OPEN_READ_ONLY, &localeFile)) exit(1); printf("Read Map.dbc file... "); HANDLE dbcFile; if (!SFileOpenFileEx(localeFile, "DBFilesClient\\Map.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile)) { printf("Fatal error: Cannot find Map.dbc in archive!\n"); exit(1); } DBCFile dbc(dbcFile); if(!dbc.open()) { printf("Fatal error: Invalid Map.dbc file format!\n"); exit(1); } size_t map_count = dbc.getRecordCount(); map_ids = new map_id[map_count]; for(uint32 x = 0; x < map_count; ++x) { map_ids[x].id = dbc.getRecord(x).getUInt(0); strcpy(map_ids[x].name, dbc.getRecord(x).getString(1)); } printf("Done! (%u maps loaded)\n", map_count); return map_count; }
int getFileType(const char *szFileName) { if ( !szFileName ) return 0; int rVal = 0; HANDLE hMPQ; HANDLE hFile; // Open archive for map checking if ( SFileOpenArchive(szFileName, 0, 0, &hMPQ) && hMPQ ) { // Open scenario.chk file if ( SFileOpenFileEx(hMPQ, "staredit\\scenario.chk", SFILE_FROM_MPQ, &hFile) && hFile ) { rVal = 1; SFileCloseFile(hFile); } // Close archive SFileCloseArchive(hMPQ); } else if ( SFileOpenFileEx(NULL, szFileName, SFILE_FROM_ABSOLUTE, &hFile) && hFile ) { DWORD dwRead = 0; char tbuff[16]; DWORD dwSize = SFileGetFileSize(hFile, 0); // Read file data to check if it's a replay if ( dwSize > 16 && SFileReadFile(hFile, &tbuff, 16, &dwRead, 0) && dwRead == 16 && *(DWORD*)&tbuff[12] == 'SRer' ) rVal = 2; // Close file SFileCloseFile(hFile); } return rVal; }
void ReadLiquidTypeTableDBC(int const locale) { HANDLE localeFile; char localMPQ[512]; sprintf(localMPQ, "%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]); if (!SFileOpenArchive(localMPQ, 0, MPQ_OPEN_READ_ONLY, &localeFile)) exit(1); printf("Read LiquidType.dbc file..."); HANDLE dbcFile; if (!SFileOpenFileEx(localeFile, "DBFilesClient\\LiquidType.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile)) { printf("Fatal error: Cannot find LiquidType.dbc in archive!\n"); exit(1); } DBCFile dbc(dbcFile); if(!dbc.open()) { printf("Fatal error: Invalid LiquidType.dbc file format!\n"); exit(1); } size_t LiqType_count = dbc.getRecordCount(); size_t LiqType_maxid = dbc.getMaxId(); LiqType = new uint16[LiqType_maxid + 1]; memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16)); for(uint32 x = 0; x < LiqType_count; ++x) LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); printf("Done! (%u LiqTypes loaded)\n", LiqType_count); }
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx MPQArchive::MPQArchive(const char* filename) { BOOL succ = SFileOpenArchive(filename, 0, 0,&hMPQ); if (succ) printf("Opening %s\n", filename); else printf("Error!!!Not open archive %s\n", filename); }
void LoadCommonMPQFiles(uint32 build) { TCHAR filename[512]; _stprintf(filename, _T("%s/Data/world.MPQ"), input_path); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &WorldMpq)) { if (GetLastError() != ERROR_PATH_NOT_FOUND) _tprintf(_T("Cannot open archive %s\n"), filename); return; } int count = sizeof(CONF_mpq_list) / sizeof(char*); for (int i = 1; i < count; ++i) { if (build < 15211 && !strcmp("world2.MPQ", CONF_mpq_list[i])) // 4.3.2 and higher MPQ continue; _stprintf(filename, _T("%s/Data/%s"), input_path, CONF_mpq_list[i]); if (!SFileOpenPatchArchive(WorldMpq, filename, "", 0)) { if (GetLastError() != ERROR_PATH_NOT_FOUND) _tprintf(_T("Cannot open archive %s\n"), filename); else _tprintf(_T("Not found %s\n"), filename); } else _tprintf(_T("Loaded %s\n"), filename); } char const* prefix = NULL; for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i) { memset(filename, 0, sizeof(filename)); if (Builds[i] > LAST_DBC_IN_DATA_BUILD) { prefix = ""; _stprintf(filename, _T("%s/Data/wow-update-base-%u.MPQ"), input_path, Builds[i]); } else { prefix = "base"; _stprintf(filename, _T("%s/Data/wow-update-%u.MPQ"), input_path, Builds[i]); } if (!SFileOpenPatchArchive(WorldMpq, filename, prefix, 0)) { if (GetLastError() != ERROR_PATH_NOT_FOUND) _tprintf(_T("Cannot open patch archive %s\n"), filename); else _tprintf(_T("Not found %s\n"), filename); continue; } else _tprintf(_T("Loaded %s\n"), filename); } }
bool OpenArchive(const char* directory, const char* fileName, MPQHANDLE &hMpq, std::string &outPath) { BOOL success = FALSE; char filePath[MAX_PATH], locateError[MAX_PATH + 60], retryError[MAX_PATH + 76]; std::string separator = GetSystemFileSeparator(); std::snprintf(filePath, MAX_PATH, "%s%s%s", directory, separator.c_str(), fileName); std::snprintf(locateError, MAX_PATH+60, "Could not find %s!\n\nWould you like to locate it manually?", fileName); std::snprintf(retryError, MAX_PATH+76, "Failed to open %s! The file may be in use.\n\nWould you like to try again?", fileName); if ( FindFile(filePath) ) // File found { do { success = SFileOpenArchive((LPCSTR)filePath, 0, 0, &hMpq); } while ( success == FALSE && MessageBox(NULL, retryError, "Error!", MB_YESNO|MB_ICONEXCLAMATION) == IDYES ); if ( success == TRUE ) outPath = filePath; } else // File not found { if ( MessageBox(NULL, locateError, "Error!", MB_YESNO|MB_ICONEXCLAMATION) == IDYES ) { OPENFILENAME ofn; memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFilter = "MPQ Files\0*.mpq\0All Files\0*.*\0"; ofn.lpstrFile = filePath; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if ( GetOpenFileName(&ofn) ) { do { success = SFileOpenArchive(filePath, 0, 0, &hMpq); } while ( success == FALSE && MessageBox(NULL, retryError, "Error!", MB_YESNO|MB_ICONEXCLAMATION) == IDYES ); if ( success == TRUE ) outPath = filePath; } else return OpenArchive(directory, fileName, hMpq, outPath); } } return success == TRUE; }
BOOL WINAPI SFileOpenArchive_stub(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ) { LoadSFMpqDll(); if (hSFMpq) { *(FARPROC *)&SFileOpenArchive = GetProcAddress(hSFMpq,"SFileOpenArchive"); if (SFileOpenArchive) return SFileOpenArchive(lpFileName,dwPriority,dwFlags,hMPQ); } return FALSE; }
FAFile* FAfopen(const std::string& filename) { bfs::path path(filename); path.make_preferred(); if(!bfs::exists(filename)) { int nError = ERROR_SUCCESS; if(diabdat == NULL && !SFileOpenArchive(getMPQFileName().c_str(), 0, STREAM_FLAG_READ_ONLY, &diabdat)) nError = GetLastError(); if(nError != ERROR_SUCCESS) { std::cerr << "Failed to open " << DIABDAT_MPQ << std::endl; return NULL; } std::string stormPath = getStormLibPath(path); if(!SFileHasFile(diabdat, stormPath.c_str())) { std::cerr << "File " << path << " not found" << std::endl; return NULL; } FAFile* file = new FAFile(); file->data.mpqFile = malloc(sizeof(HANDLE)); if(!SFileOpenFileEx(diabdat, stormPath.c_str(), 0, (HANDLE*)file->data.mpqFile)) { std::cerr << "Failed to open " << filename << " in " << DIABDAT_MPQ; delete file; return NULL; } file->mode = FAFile::MPQFile; return file; } else { FILE* plainFile = fopen(filename.c_str(), "rb"); if(plainFile == NULL) return NULL; FAFile* file = new FAFile(); file->mode = FAFile::PlainFile; file->data.plainFile.file = plainFile; file->data.plainFile.filename = new std::string(filename); return file; } }
bool OpenArchive(const char* mpqPath, MPQHANDLE &mpq) { BOOL success = FALSE; char lpStrMpqPath[MAX_PATH + 100], locateError[MAX_PATH + 60], retryError[MAX_PATH + 76]; strncpy(lpStrMpqPath, mpqPath, strlen(mpqPath)); std::snprintf(locateError, MAX_PATH + 60, "Could not find %s!\n\nWould you like to locate it manually?", mpqPath); std::snprintf(retryError, MAX_PATH + 76, "Failed to open %s! The file may be in use.\n\nWould you like to try again?", mpqPath); if ( FindFile(mpqPath) ) // File found { do { success = SFileOpenArchive((LPCSTR)mpqPath, 0, 0, &mpq); } while ( success == FALSE && MessageBox(NULL, retryError, "Error!", MB_YESNO | MB_ICONEXCLAMATION) == IDYES ); } else // File not found { if ( MessageBox(NULL, locateError, "Error!", MB_YESNO | MB_ICONEXCLAMATION) == IDYES ) { OPENFILENAME ofn; memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFilter = "MPQ Files\0*.mpq\0All Files\0*.*\0"; ofn.lpstrFile = lpStrMpqPath; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if ( GetOpenFileName(&ofn) ) { do { success = SFileOpenArchive(mpqPath, 0, 0, &mpq); } while ( success == FALSE && MessageBox(NULL, retryError, "Error!", MB_YESNO | MB_ICONEXCLAMATION) == IDYES ); } else return OpenArchive(mpqPath, mpq); } } return success == TRUE; }
void LoadCommonMPQFiles(uint32 build) { TCHAR filename[512]; _stprintf(filename, _T("%s/Data/world.MPQ"), input_path); _tprintf(_T("Loading common MPQ files\n")); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &WorldMpq)) { if (GetLastError() != ERROR_PATH_NOT_FOUND) _tprintf(_T("Cannot open archive %s\n"), filename); return; } int count = sizeof(CONF_mpq_list) / sizeof(char*); for (int i = 1; i < count; ++i) { _stprintf(filename, _T("%s/Data/%s"), input_path, CONF_mpq_list[i]); if (!SFileOpenPatchArchive(WorldMpq, filename, "", 0)) { if (GetLastError() != ERROR_PATH_NOT_FOUND) _tprintf(_T("Cannot open archive %s\n"), filename); else _tprintf(_T("Not found %s\n"), filename); } else _tprintf(_T("Loaded %s\n"), filename); } for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i) { // Do not attempt to read older MPQ patch archives past this build, they were merged with base // and trying to read them together with new base will not end well if (CONF_TargetBuild >= NEW_BASE_SET_BUILD && Builds[i] < NEW_BASE_SET_BUILD) continue; memset(filename, 0, sizeof(filename)); _stprintf(filename, _T("%s/Data/wow-update-base-%u.MPQ"), input_path, Builds[i]); if (!SFileOpenPatchArchive(WorldMpq, filename, "base", 0)) { if (GetLastError() != ERROR_PATH_NOT_FOUND) _tprintf(_T("Cannot open patch archive %s\n"), filename); else _tprintf(_T("Not found %s\n"), filename); continue; } else _tprintf(_T("Loaded %s\n"), filename); } printf("\n"); }
void LoadLocaleMPQFiles(int const locale) { char filename[512]; // Locale-xxXX.MPQ sprintf(filename, "%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &localeMPQ[0])) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } }
void LoadMapMPQFiles() { char filename[512]; // Locale-xxXX.MPQ sprintf(filename, "%s/Data/world2.MPQ", input_path); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &WorldMPQ)) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } }
bool OpenArchive(char const* mpqFileName, HANDLE* mpqHandlePtr /*= NULL*/) { HANDLE mpqHandle; if (!SFileOpenArchive(mpqFileName, 0, MPQ_OPEN_READ_ONLY, &mpqHandle)) return false; gOpenArchives.push_back(mpqHandle); if (mpqHandlePtr) *mpqHandlePtr = mpqHandle; return true; }
bool LoadLocaleMPQFile(int locale) { TCHAR buff[512]; memset(buff, 0, sizeof(buff)); _stprintf(buff, _T("%s/Data/%s/locale-%s.MPQ"), input_path, LocalesT[locale], LocalesT[locale]); if (!SFileOpenArchive(buff, 0, MPQ_OPEN_READ_ONLY, &LocaleMpq)) { if (GetLastError() != ERROR_PATH_NOT_FOUND) { _tprintf(_T("\nLoading %s locale MPQs\n"), LocalesT[locale]); _tprintf(_T("Cannot open archive %s\n"), buff); } return false; } _tprintf(_T("\nLoading %s locale MPQs\n"), LocalesT[locale]); char const* prefix = NULL; for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i) { // Do not attempt to read older MPQ patch archives past this build, they were merged with base // and trying to read them together with new base will not end well if (CONF_TargetBuild >= NEW_BASE_SET_BUILD && Builds[i] < NEW_BASE_SET_BUILD) continue; memset(buff, 0, sizeof(buff)); if (Builds[i] > LAST_DBC_IN_DATA_BUILD) { prefix = ""; _stprintf(buff, _T("%s/Data/%s/wow-update-%s-%u.MPQ"), input_path, LocalesT[locale], LocalesT[locale], Builds[i]); } else { prefix = Locales[locale]; _stprintf(buff, _T("%s/Data/wow-update-%u.MPQ"), input_path, Builds[i]); } if (!SFileOpenPatchArchive(LocaleMpq, buff, prefix, 0)) { if (GetLastError() != ERROR_FILE_NOT_FOUND) _tprintf(_T("Cannot open patch archive %s\n"), buff); continue; } else _tprintf(_T("Loaded %s\n"), buff); } printf("\n"); return true; }
HANDLE getHandle(const QString &mpq) { static QHash<QString, HANDLE> archives; if (archives.contains(mpq)) return archives[mpq]; else { HANDLE hMPQ; if (!SFileOpenArchive(mpq.toUtf8().constData(), 0, STREAM_FLAG_READ_ONLY, &hMPQ)) { qCritical("Cannot open archive '%s'", qPrintable(mpq)); hMPQ = 0; } return (archives[mpq] = hMPQ); } }
// copied from contrib/extractor/System.cpp void ReadLiquidTypeTableDBC() { HANDLE localeFile; char localMPQ[1024]; snprintf(localMPQ, sizeof(localMPQ), "%smisc.MPQ", input_path); if (FileExists(localMPQ)==false) { // Use misc.mpq printf(localMPQ, "%s/Data/%s/locale-%s.MPQ", input_path); } if (!SFileOpenArchive(localMPQ, 0, MPQ_OPEN_READ_ONLY, &localeFile)) { exit(1); } printf("Read LiquidType.dbc file..."); HANDLE dbcFile; if (!SFileOpenFileEx(localeFile, "DBFilesClient\\LiquidType.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile)) { if (!SFileOpenFileEx(localeFile, "DBFilesClient\\LiquidType.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile)) { printf("Fatal error: Cannot find LiquidType.dbc in archive!\n"); exit(1); } } DBCFile dbc(localeFile, "DBFilesClient\\LiquidType.dbc"); if (!dbc.open()) { printf("Fatal error: Invalid LiquidType.dbc file format!\n"); exit(1); } size_t LiqType_count = dbc.getRecordCount(); size_t LiqType_maxid = dbc.getMaxId(); LiqType = new uint16[LiqType_maxid + 1]; memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16)); for (size_t x = 0; x < LiqType_count; ++x) LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); printf("Done! (%zu LiqTypes loaded)\n", LiqType_count); }
bool init(const std::string pathMPQ, const std::string listFile) { if(pathMPQ.empty()) { std::cout << "skipping stormlib init - won't be able to read files in MPQ archives" << std::endl; return true; } const bool success = SFileOpenArchive(pathMPQ.c_str(), 0, STREAM_FLAG_READ_ONLY, &diabdat); if (!success) { std::cerr << "Failed to open " << pathMPQ.c_str() << " with error " << GetLastError() << std::endl; } if(!listFile.empty()) SFileAddListFile(diabdat, listFile.c_str()); return success; }
bool MainWindow::openMPQ() { mFilename = ui->lineEdit->text(); mListfile = ui->lineEdit_2->text(); if (mListfile.isEmpty() || mFilename.isEmpty()) { QMessageBox::critical(0, "Error", "Select MPQ archive and file list!"); return false; } if (!fileExists(mFilename)) { QMessageBox::critical(0, "Error", "MPQ archive does not exist!"); return false; } if (!fileExists(mListfile)) { QMessageBox::critical(0, "Error", "Listfile does not exist!"); return false; } const bool success = SFileOpenArchive(mFilename.toStdString().c_str(), 0, STREAM_FLAG_READ_ONLY, &mDiabdat); if (!success) { QMessageBox::critical(0, "Error", "Cannot open file \"" + mFilename + "\""); return false; } std::string fileList = ui->lineEdit_2->text().toStdString(); SFileAddListFile(mDiabdat, fileList.c_str()); FAIO::init(mFilename.toStdString().c_str()); return true; }
bool LoadLocaleMPQFile(int locale) { TCHAR buff[512]; memset(buff, 0, sizeof(buff)); _stprintf(buff, _T("%s/Data/%s/locale-%s.MPQ"), input_path, LocalesT[locale], LocalesT[locale]); if (!SFileOpenArchive(buff, 0, MPQ_OPEN_READ_ONLY, &LocaleMpq)) { if (GetLastError() != ERROR_PATH_NOT_FOUND) _tprintf(_T("Cannot open archive %s\n"), buff); return false; } char const* prefix = NULL; for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i) { memset(buff, 0, sizeof(buff)); if (Builds[i] > LAST_DBC_IN_DATA_BUILD) { prefix = ""; _stprintf(buff, _T("%s/Data/%s/wow-update-%s-%u.MPQ"), input_path, LocalesT[locale], LocalesT[locale], Builds[i]); } else { prefix = Locales[locale]; _stprintf(buff, _T("%s/Data/wow-update-%u.MPQ"), input_path, Builds[i]); } if (!SFileOpenPatchArchive(LocaleMpq, buff, prefix, 0)) { if (GetLastError() != ERROR_FILE_NOT_FOUND) _tprintf(_T("Cannot open patch archive %s\n"), buff); continue; } } return true; }
void CMpqArchive::Load() { int nLen = strlen(m_szName.c_str()) + 1; int nwLen = MultiByteToWideChar(CP_ACP, 0, m_szName.c_str(), nLen, NULL, 0); TCHAR lpszFile[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, m_szName.c_str(), nLen, lpszFile, nwLen); SFileOpenArchive(lpszFile, 0, MPQ_OPEN_FORCE_MPQ_V1 | MPQ_OPEN_READ_ONLY, &m_hMpq); m_szDir = CStringUtil::Combine(m_szName, "", false); SFILE_FIND_DATA data; bool bFind = true; HANDLE hFindFile = SFileFindFirstFile(m_hMpq, "*.*", &data, NULL); while (hFindFile != NULL && bFind) { CFileInfo info; info.m_szName = data.cFileName; info.m_nSize = data.dwFileSize; info.m_nCompSize = data.dwCompSize; m_vecFile.push_back(info); bFind = SFileFindNextFile(hFindFile, &data); } SFileFindClose(hFindFile); }
static void *MPQ_openArchive(PHYSFS_Io *io, const char *name, int forWriting, int *claimed) { HANDLE hMpq = NULL; DWORD dwFlags = MPQ_OPEN_READ_ONLY; MPQHandle *handle = NULL; assert(io != NULL); /* shouldn't ever happen. */ BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL); if (!SFileOpenArchive(name, 0, dwFlags, &hMpq)) return NULL; *claimed = 1; handle = (MPQHandle *)allocator.Malloc(sizeof(MPQHandle)); if (handle) { handle->io = io; handle->mpqHandle = hMpq; } return handle; }
bool WINAPI SFileCreateArchive(const char * szMpqName, DWORD dwFlags, DWORD dwMaxFileCount, HANDLE * phMpq) { TFileStream * pStream = NULL; // File stream TMPQArchive * ha = NULL; // MPQ archive handle ULONGLONG MpqPos = 0; // Position of MPQ header in the file HANDLE hMpq = NULL; USHORT wFormatVersion = MPQ_FORMAT_VERSION_1; DWORD dwBlockTableSize = 0; // Initial block table size DWORD dwHashTableSize = 0; int nError = ERROR_SUCCESS; // Check the parameters, if they are valid if(szMpqName == NULL || *szMpqName == 0 || phMpq == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return false; } // One time initialization of MPQ cryptography InitializeMpqCryptography(); // We verify if the file already exists and if it's a MPQ archive. // If yes, we won't allow to overwrite it. if(SFileOpenArchive(szMpqName, 0, dwFlags, &hMpq)) { SFileCloseArchive(hMpq); SetLastError(ERROR_ALREADY_EXISTS); return false; } // // At this point, we have to create the archive. // - If the file exists, convert it to MPQ archive. // - If the file doesn't exist, create new empty file // pStream = FileStream_OpenFile(szMpqName, true); if(pStream == NULL) { pStream = FileStream_CreateFile(szMpqName); if(pStream == NULL) return false; } // Decide what format to use wFormatVersion = (USHORT)((dwFlags & MPQ_CREATE_ARCHIVE_VMASK) >> 16); if(wFormatVersion > MPQ_FORMAT_VERSION_4) { SetLastError(ERROR_INVALID_PARAMETER); return false; } // Increment the maximum amount of files to have space // for listfile and attributes file if(dwFlags & MPQ_CREATE_ATTRIBUTES) dwMaxFileCount++; dwMaxFileCount++; // If file count is not zero, initialize the hash table size dwHashTableSize = GetHashTableSizeForFileCount(dwMaxFileCount); // Retrieve the file size and round it up to 0x200 bytes FileStream_GetSize(pStream, MpqPos); MpqPos = (MpqPos + 0x1FF) & (ULONGLONG)0xFFFFFFFFFFFFFE00ULL; if(!FileStream_SetSize(pStream, MpqPos)) nError = GetLastError(); #ifdef _DEBUG // Debug code, used for testing StormLib // dwBlockTableSize = dwHashTableSize * 2; #endif // Create the archive handle if(nError == ERROR_SUCCESS) { if((ha = ALLOCMEM(TMPQArchive, 1)) == NULL) nError = ERROR_NOT_ENOUGH_MEMORY; } // Fill the MPQ archive handle structure if(nError == ERROR_SUCCESS) { memset(ha, 0, sizeof(TMPQArchive)); ha->pStream = pStream; ha->dwSectorSize = (wFormatVersion >= MPQ_FORMAT_VERSION_3) ? 0x4000 : 0x1000; ha->UserDataPos = MpqPos; ha->MpqPos = MpqPos; ha->pHeader = (TMPQHeader *)ha->HeaderData; ha->dwMaxFileCount = dwMaxFileCount; ha->dwFileTableSize = 0; ha->dwFileFlags1 = MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS | MPQ_FILE_REPLACEEXISTING; ha->dwFileFlags2 = MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS | MPQ_FILE_REPLACEEXISTING; ha->dwFlags = 0; // Setup the attributes if(dwFlags & MPQ_CREATE_ATTRIBUTES) ha->dwAttrFlags = MPQ_ATTRIBUTE_CRC32 | MPQ_ATTRIBUTE_FILETIME | MPQ_ATTRIBUTE_MD5; pStream = NULL; } // Fill the MPQ header if(nError == ERROR_SUCCESS) { TMPQHeader * pHeader = ha->pHeader; // Fill the MPQ header memset(pHeader, 0, sizeof(ha->HeaderData)); pHeader->dwID = ID_MPQ; pHeader->dwHeaderSize = MpqHeaderSizes[wFormatVersion]; pHeader->dwArchiveSize = pHeader->dwHeaderSize + dwHashTableSize * sizeof(TMPQHash); pHeader->wFormatVersion = wFormatVersion; pHeader->wSectorSize = GetSectorSizeShift(ha->dwSectorSize); pHeader->dwHashTablePos = pHeader->dwHeaderSize; pHeader->dwHashTableSize = dwHashTableSize; pHeader->dwBlockTablePos = pHeader->dwHashTablePos + dwHashTableSize * sizeof(TMPQHash); pHeader->dwBlockTableSize = dwBlockTableSize; // For MPQs version 4 and higher, we set the size of raw data block // for calculating MD5 if(wFormatVersion >= MPQ_FORMAT_VERSION_4) pHeader->dwRawChunkSize = 0x4000; // Write the naked MPQ header nError = WriteNakedMPQHeader(ha); // // Note: Don't recalculate position of MPQ tables at this point. // We merely set a flag that indicates that the MPQ tables // have been changed, and SaveMpqTables will do the work when closing the archive. // ha->dwFlags |= MPQ_FLAG_CHANGED; } // Create initial hash table if(nError == ERROR_SUCCESS) { nError = CreateHashTable(ha, dwHashTableSize); } // Create initial HET table, if the caller required an MPQ format 3.0 or newer if(nError == ERROR_SUCCESS && wFormatVersion >= MPQ_FORMAT_VERSION_3) { ha->pHetTable = CreateHetTable(ha->dwMaxFileCount, 0x40, true); if(ha->pHetTable == NULL) nError = ERROR_NOT_ENOUGH_MEMORY; } // Create initial file table if(nError == ERROR_SUCCESS) { ha->pFileTable = ALLOCMEM(TFileEntry, dwMaxFileCount); if(ha->pFileTable != NULL) memset(ha->pFileTable, 0x00, sizeof(TFileEntry) * dwMaxFileCount); else nError = ERROR_NOT_ENOUGH_MEMORY; } // Cleanup : If an error, delete all buffers and return if(nError != ERROR_SUCCESS) { FileStream_Close(pStream); FreeMPQArchive(ha); SetLastError(nError); ha = NULL; } // Return the values *phMpq = (HANDLE)ha; return (nError == ERROR_SUCCESS); }
int main(int argc, char** argv) { if (argc < 2) { help(argv); return 0; } // Open MPQ HANDLE handle; SFileOpenArchive(argv[1], 0, STREAM_FLAG_READ_ONLY, &handle); FAIO::init(argv[1]); // For now only smaltext.cel Cel::CelDecoder cel("ctrlpan/smaltext.cel"); // Prepare ascii vector according to order in cel file std::vector<int> ascii; for (int i = 'a'; i <= 'z'; i++) ascii.push_back(i); for (int i = '1'; i <= '9'; i++) ascii.push_back(i); ascii.push_back('0'); // I can't find mapping in ascii table for one signs so // I marked it as 255 std::vector<int> asciiSigns = {'-', '=', '+', '(', ')', '[', ']', '"', 255, '`', '\'', ':', ';', ',', '.', '/', '?', '!', '&', '%', '#', '$', '*', '<', '>', '@', '\\', '^', '_', '|', '~'}; ascii.insert(ascii.end(), asciiSigns.begin(), asciiSigns.end()); std::map<int, std::string> mapping; int positionX = 0; for (int32_t i = 0; i < cel.numFrames(); i++) { Cel::CelFrame& frame = cel[i]; int32_t maximumVisibleX = 0; for (int32_t x = 0; x < frame.width(); x++) { for (int32_t y = 0; y < frame.height(); y++) { if (frame.get(x, y).visible) if (x > maximumVisibleX) maximumVisibleX = x; } } std::string asciiStr, positionXStr, maximumVisibleXStr; int asciiIdx = ascii[i]; // Additional 2 pixels for every letter maximumVisibleX += 2; if (maximumVisibleX > frame.width()) maximumVisibleX = frame.width(); // Convert values to string char buffer[10]; sprintf(buffer, "%d", asciiIdx); asciiStr = buffer; sprintf(buffer, "%d", maximumVisibleX); maximumVisibleXStr = buffer; sprintf(buffer, "%d", positionX); positionXStr = buffer; // Create output std::string out = "<char id=\"" + asciiStr + "\" x=\"" + positionXStr + "\" y=\"0\" width=\"" + maximumVisibleXStr + "\" height=\"11\" xoffset=\"0\" yoffset=\"0\" xadvance=\"" + maximumVisibleXStr + "\" />"; mapping[asciiIdx] = out; // Move further positionX += 13; } // Sort by ascii std::sort(ascii.begin(), ascii.end()); for (int i : ascii) { std::cout << mapping[i] << std::endl; } FAIO::FAFileObject::quit(); }
void LoadCommonMPQFiles(uint32 build) { TCHAR filename[512]; _stprintf(filename, _T("%sworld.MPQ"), input_path); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &WorldMpq)) { if (GetLastError() != ERROR_FILE_NOT_FOUND) _tprintf(_T("Cannot open archive %s\n"), filename); return; } int count = sizeof(CONF_mpq_list) / sizeof(char*); for (int i = 1; i < count; ++i) { if (build < 15211 && !strcmp("world2.MPQ", CONF_mpq_list[i])) // 4.3.2 and higher MPQ continue; _stprintf(filename, _T("%s%s"), input_path, CONF_mpq_list[i]); if (!SFileOpenPatchArchive(WorldMpq, filename, "", 0)) { if (GetLastError() != ERROR_FILE_NOT_FOUND) _tprintf(_T("Cannot open archive %s\n"), filename); else _tprintf(_T("Not found %s\n"), filename); } else { _tprintf(_T("Loaded %s\n"), filename); bool found = false; int count = 0; SFILE_FIND_DATA data; HANDLE find = SFileFindFirstFile(WorldMpq, "*.*", &data, NULL); if (find != NULL) { do { ++count; if (data.dwFileFlags & MPQ_FILE_PATCH_FILE) { found = true; break; } } while (SFileFindNextFile(find, &data)); } SFileFindClose(find); printf("Scanned %d files, found patch = %d\n", count, found); } } char const* prefix = NULL; for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i) { memset(filename, 0, sizeof(filename)); if (Builds[i] > LAST_DBC_IN_DATA_BUILD) { prefix = ""; _stprintf(filename, _T("%swow-update-base-%u.MPQ"), input_path, Builds[i]); } else { prefix = "base"; _stprintf(filename, _T("%swow-update-%u.MPQ"), input_path, Builds[i]); } if (!SFileOpenPatchArchive(WorldMpq, filename, prefix, 0)) { if (GetLastError() != ERROR_FILE_NOT_FOUND) _tprintf(_T("Cannot open patch archive %s\n"), filename); else _tprintf(_T("Not found %s\n"), filename); continue; } else { _tprintf(_T("Loaded %s\n"), filename); bool found = false; int count = 0; SFILE_FIND_DATA data; HANDLE find = SFileFindFirstFile(WorldMpq, "*.*", &data, NULL); if (find != NULL) { do { ++count; if (data.dwFileFlags & MPQ_FILE_PATCH_FILE) { found = true; break; } } while (SFileFindNextFile(find, &data)); } SFileFindClose(find); printf("Scanned %d files, found patch = %d\n", count, found); } } }
bool WINAPI SFileOpenPatchArchive( HANDLE hMpq, const char * szPatchMpqName, const char * szPatchPathPrefix, DWORD dwFlags) { TMPQArchive * haPatch; TMPQArchive * ha = (TMPQArchive *)hMpq; HANDLE hPatchMpq = NULL; size_t nLength = 0; int nError = ERROR_SUCCESS; // Keep compiler happy dwFlags = dwFlags; // Verify input parameters if(!IsValidMpqHandle(ha)) nError = ERROR_INVALID_HANDLE; if(szPatchMpqName == NULL || *szPatchMpqName == 0) nError = ERROR_INVALID_PARAMETER; // Check the path prefix for patches if(szPatchPathPrefix != NULL) { nLength = strlen(szPatchPathPrefix); if(nLength > MPQ_PATCH_PREFIX_LEN - 2) nError = ERROR_INVALID_PARAMETER; } // // We don't allow adding patches to archives that have been open for write // // Error scenario: // // 1) Open archive for writing // 2) Modify or replace a file // 3) Add patch archive to the opened MPQ // 4) Read patched file // 5) Now what ? // if(nError == ERROR_SUCCESS) { if((ha->pStream->StreamFlags & STREAM_FLAG_READ_ONLY) == 0) { printf("omg"); nError = ERROR_ACCESS_DENIED; } } // Open the archive like it is normal archive if(nError == ERROR_SUCCESS) { if(!SFileOpenArchive(szPatchMpqName, 0, MPQ_OPEN_READ_ONLY, &hPatchMpq)) return false; haPatch = (TMPQArchive *)hPatchMpq; // Save the prefix for patch file names. // Make sure that there is backslash after it if(nLength > 0) { strcpy(haPatch->szPatchPrefix, szPatchPathPrefix); if(haPatch->szPatchPrefix[nLength - 1] != '\\') { haPatch->szPatchPrefix[nLength++] = '\\'; haPatch->szPatchPrefix[nLength] = 0; } } // Now add the patch archive to the list of patches to the original MPQ while(ha != NULL) { if(ha->haPatch == NULL) { ha->haPatch = haPatch; return true; } // Move to the next archive ha = ha->haPatch; } // Should never happen nError = ERROR_CAN_NOT_COMPLETE; } SetLastError(nError); return false; }
void LoadMapMPQFiles() { char filename[512]; //Locale-xxXX.MPQ sprintf(filename,"%s/Data/world.MPQ", input_path); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &WorldMPQ)) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } for(int i = 0; i < PATCH_REV_COUNT; ++i) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[i]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); printf(" -%i\n", patchRev[i]); if (!SFileOpenPatchArchive(WorldMPQ, filename, "base", MPQ_OPEN_READ_ONLY)) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } if (!SFileIsPatchedArchive(WorldMPQ)) assert(false && "An error occured"); for(int j = 0; j < 3; j++) { sprintf(filename, "%s/Data/expansion%u.MPQ", input_path, j+1); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &ExpansionsMPQ[j])) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } if (!IsValidMpqHandle((TMPQArchive*)ExpansionsMPQ[j])) { printf("Load of Expansion%u.MPQ Failed!\n", j+1); printf("\nPlease verify you downloaded all the MPQs. You should replace\n'SET accountType \"xx\"'\nin your WTF/config.wtf and WTF/launcher.wtf by\n'SET accountType \"CT\"'\nand then restart your launcher\n"); exit(1); } for(int i = 0; i < PATCH_REV_COUNT; ++i) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[i]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); printf(" -%i\n", patchRev[i]); if (!SFileOpenPatchArchive(ExpansionsMPQ[j], filename, "base", MPQ_OPEN_READ_ONLY)) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } } }
bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCreateInfo, HANDLE * phMpq) { TFileStream * pStream = NULL; // File stream TMPQArchive * ha = NULL; // MPQ archive handle ULONGLONG MpqPos = 0; // Position of MPQ header in the file HANDLE hMpq = NULL; DWORD dwBlockTableSize = 0; // Initial block table size DWORD dwHashTableSize = 0; DWORD dwMaxFileCount; int nError = ERROR_SUCCESS; // Check the parameters, if they are valid if(szMpqName == NULL || *szMpqName == 0 || pCreateInfo == NULL || phMpq == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return false; } // Verify if all variables in SFILE_CREATE_MPQ are correct if((pCreateInfo->cbSize == 0 || pCreateInfo->cbSize > sizeof(SFILE_CREATE_MPQ)) || (pCreateInfo->dwMpqVersion > MPQ_FORMAT_VERSION_4) || (pCreateInfo->pvUserData != NULL || pCreateInfo->cbUserData != 0) || (pCreateInfo->dwAttrFlags & ~MPQ_ATTRIBUTE_ALL) || (pCreateInfo->dwSectorSize & (pCreateInfo->dwSectorSize - 1)) || (pCreateInfo->dwRawChunkSize & (pCreateInfo->dwRawChunkSize - 1)) || (pCreateInfo->dwMaxFileCount < 4)) { SetLastError(ERROR_INVALID_PARAMETER); return false; } // One time initialization of MPQ cryptography InitializeMpqCryptography(); // We verify if the file already exists and if it's a MPQ archive. // If yes, we won't allow to overwrite it. if(SFileOpenArchive(szMpqName, 0, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE | MPQ_OPEN_NO_ATTRIBUTES | MPQ_OPEN_NO_LISTFILE, &hMpq)) { SFileCloseArchive(hMpq); SetLastError(ERROR_ALREADY_EXISTS); return false; } // // At this point, we have to create the archive. // - If the file exists, convert it to MPQ archive. // - If the file doesn't exist, create new empty file // pStream = FileStream_OpenFile(szMpqName, pCreateInfo->dwStreamFlags); if(pStream == NULL) { pStream = FileStream_CreateFile(szMpqName, pCreateInfo->dwStreamFlags); if(pStream == NULL) return false; } // Increment the maximum amount of files to have space // for listfile and attributes file dwMaxFileCount = pCreateInfo->dwMaxFileCount; if(pCreateInfo->dwAttrFlags != 0) dwMaxFileCount++; dwMaxFileCount++; // If file count is not zero, initialize the hash table size dwHashTableSize = GetHashTableSizeForFileCount(dwMaxFileCount); // Retrieve the file size and round it up to 0x200 bytes FileStream_GetSize(pStream, MpqPos); MpqPos = (MpqPos + 0x1FF) & (ULONGLONG)0xFFFFFFFFFFFFFE00ULL; if(!FileStream_SetSize(pStream, MpqPos)) nError = GetLastError(); #ifdef _DEBUG // Debug code, used for testing StormLib // dwBlockTableSize = dwHashTableSize * 2; #endif // Create the archive handle if(nError == ERROR_SUCCESS) { if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL) nError = ERROR_NOT_ENOUGH_MEMORY; } // Fill the MPQ archive handle structure if(nError == ERROR_SUCCESS) { memset(ha, 0, sizeof(TMPQArchive)); ha->pStream = pStream; ha->dwSectorSize = pCreateInfo->dwSectorSize; ha->UserDataPos = MpqPos; ha->MpqPos = MpqPos; ha->pHeader = (TMPQHeader *)ha->HeaderData; ha->dwMaxFileCount = dwMaxFileCount; ha->dwFileTableSize = 0; ha->dwFileFlags1 = pCreateInfo->dwFileFlags1; ha->dwFileFlags2 = pCreateInfo->dwFileFlags2; ha->dwFlags = 0; // Setup the attributes ha->dwAttrFlags = pCreateInfo->dwAttrFlags; pStream = NULL; } // Fill the MPQ header if(nError == ERROR_SUCCESS) { TMPQHeader * pHeader = ha->pHeader; // Fill the MPQ header memset(pHeader, 0, sizeof(ha->HeaderData)); pHeader->dwID = ID_MPQ; pHeader->dwHeaderSize = MpqHeaderSizes[pCreateInfo->dwMpqVersion]; pHeader->dwArchiveSize = pHeader->dwHeaderSize + dwHashTableSize * sizeof(TMPQHash); pHeader->wFormatVersion = (USHORT)pCreateInfo->dwMpqVersion; pHeader->wSectorSize = GetSectorSizeShift(ha->dwSectorSize); pHeader->dwHashTablePos = pHeader->dwHeaderSize; pHeader->dwHashTableSize = dwHashTableSize; pHeader->dwBlockTablePos = pHeader->dwHashTablePos + dwHashTableSize * sizeof(TMPQHash); pHeader->dwBlockTableSize = dwBlockTableSize; // For MPQs version 4 and higher, we set the size of raw data block // for calculating MD5 if(pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_4) pHeader->dwRawChunkSize = pCreateInfo->dwRawChunkSize; // Write the naked MPQ header nError = WriteNakedMPQHeader(ha); // Remember that the (listfile) and (attributes) need to be saved ha->dwFlags |= MPQ_FLAG_CHANGED | MPQ_FLAG_INV_LISTFILE | MPQ_FLAG_INV_ATTRIBUTES; } // Create initial HET table, if the caller required an MPQ format 3.0 or newer if(nError == ERROR_SUCCESS && pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_3) { ha->pHetTable = CreateHetTable(ha->dwMaxFileCount, 0x40, true); if(ha->pHetTable == NULL) nError = ERROR_NOT_ENOUGH_MEMORY; } // Create initial hash table if(nError == ERROR_SUCCESS) { nError = CreateHashTable(ha, dwHashTableSize); } // Create initial file table if(nError == ERROR_SUCCESS) { ha->pFileTable = STORM_ALLOC(TFileEntry, ha->dwMaxFileCount); if(ha->pFileTable != NULL) memset(ha->pFileTable, 0x00, sizeof(TFileEntry) * ha->dwMaxFileCount); else nError = ERROR_NOT_ENOUGH_MEMORY; } // Cleanup : If an error, delete all buffers and return if(nError != ERROR_SUCCESS) { FileStream_Close(pStream); FreeMPQArchive(ha); SetLastError(nError); ha = NULL; } // Return the values *phMpq = (HANDLE)ha; return (nError == ERROR_SUCCESS); }
void CMap :: Load( CConfig *CFG, string nCFGFile ) { m_Valid = true; m_CFGFile = nCFGFile; // load the map data m_MapLocalPath = CFG->GetString( "map_localpath", string( ) ); m_MapData.clear( ); if( !m_MapLocalPath.empty( ) ) m_MapData = UTIL_FileRead( m_GHost->m_MapPath + m_MapLocalPath ); // load the map MPQ string MapMPQFileName = m_GHost->m_MapPath + m_MapLocalPath; HANDLE MapMPQ; bool MapMPQReady = false; if( SFileOpenArchive( MapMPQFileName.c_str( ), 0, MPQ_OPEN_FORCE_MPQ_V1, &MapMPQ ) ) { CONSOLE_Print( "[MAP] loading MPQ file [" + MapMPQFileName + "]" ); MapMPQReady = true; } else CONSOLE_Print( "[MAP] warning - unable to load MPQ file [" + MapMPQFileName + "]" ); // try to calculate map_size, map_info, map_crc, map_sha1 BYTEARRAY MapSize; BYTEARRAY MapInfo; BYTEARRAY MapCRC; BYTEARRAY MapSHA1; if( !m_MapData.empty( ) ) { m_GHost->m_SHA->Reset( ); // calculate map_size MapSize = UTIL_CreateByteArray( (uint32_t)m_MapData.size( ), false ); CONSOLE_Print( "[MAP] calculated map_size = " + UTIL_ByteArrayToDecString( MapSize ) ); // calculate map_info (this is actually the CRC) MapInfo = UTIL_CreateByteArray( (uint32_t)m_GHost->m_CRC->FullCRC( (unsigned char *)m_MapData.c_str( ), m_MapData.size( ) ), false ); CONSOLE_Print( "[MAP] calculated map_info = " + UTIL_ByteArrayToDecString( MapInfo ) ); // calculate map_crc (this is not the CRC) and map_sha1 // a big thank you to Strilanc for figuring the map_crc algorithm out string CommonJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "common.j" ); if( CommonJ.empty( ) ) CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - unable to read file [" + m_GHost->m_MapCFGPath + "common.j]" ); else { string BlizzardJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "blizzard.j" ); if( BlizzardJ.empty( ) ) CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - unable to read file [" + m_GHost->m_MapCFGPath + "blizzard.j]" ); else { uint32_t Val = 0; // update: it's possible for maps to include their own copies of common.j and/or blizzard.j // this code now overrides the default copies if required bool OverrodeCommonJ = false; bool OverrodeBlizzardJ = false; if( MapMPQReady ) { HANDLE SubFile; // override common.j if( SFileOpenFileEx( MapMPQ, "Scripts\\common.j", 0, &SubFile ) ) { uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { char *SubFileData = new char[FileLength]; DWORD BytesRead = 0; if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) { CONSOLE_Print( "[MAP] overriding default common.j with map copy while calculating map_crc/sha1" ); OverrodeCommonJ = true; Val = Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead ); m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead ); } delete [] SubFileData; } SFileCloseFile( SubFile ); } } if( !OverrodeCommonJ ) { Val = Val ^ XORRotateLeft( (unsigned char *)CommonJ.c_str( ), CommonJ.size( ) ); m_GHost->m_SHA->Update( (unsigned char *)CommonJ.c_str( ), CommonJ.size( ) ); } if( MapMPQReady ) { HANDLE SubFile; // override blizzard.j if( SFileOpenFileEx( MapMPQ, "Scripts\\blizzard.j", 0, &SubFile ) ) { uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { char *SubFileData = new char[FileLength]; DWORD BytesRead = 0; if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) { CONSOLE_Print( "[MAP] overriding default blizzard.j with map copy while calculating map_crc/sha1" ); OverrodeBlizzardJ = true; Val = Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead ); m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead ); } delete [] SubFileData; } SFileCloseFile( SubFile ); } } if( !OverrodeBlizzardJ ) { Val = Val ^ XORRotateLeft( (unsigned char *)BlizzardJ.c_str( ), BlizzardJ.size( ) ); m_GHost->m_SHA->Update( (unsigned char *)BlizzardJ.c_str( ), BlizzardJ.size( ) ); } Val = ROTL( Val, 3 ); Val = ROTL( Val ^ 0x03F1379E, 3 ); m_GHost->m_SHA->Update( (unsigned char *)"\x9E\x37\xF1\x03", 4 ); if( MapMPQReady ) { vector<string> FileList; FileList.push_back( "war3map.j" ); FileList.push_back( "scripts\\war3map.j" ); FileList.push_back( "war3map.w3e" ); FileList.push_back( "war3map.wpm" ); FileList.push_back( "war3map.doo" ); FileList.push_back( "war3map.w3u" ); FileList.push_back( "war3map.w3b" ); FileList.push_back( "war3map.w3d" ); FileList.push_back( "war3map.w3a" ); FileList.push_back( "war3map.w3q" ); bool FoundScript = false; for( vector<string> :: iterator i = FileList.begin( ); i != FileList.end( ); i++ ) { // don't use scripts\war3map.j if we've already used war3map.j (yes, some maps have both but only war3map.j is used) if( FoundScript && *i == "scripts\\war3map.j" ) continue; HANDLE SubFile; if( SFileOpenFileEx( MapMPQ, (*i).c_str( ), 0, &SubFile ) ) { uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { char *SubFileData = new char[FileLength]; DWORD BytesRead = 0; if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) { if( *i == "war3map.j" || *i == "scripts\\war3map.j" ) FoundScript = true; Val = ROTL( Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead ), 3 ); m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead ); // DEBUG_Print( "*** found: " + *i ); } delete [] SubFileData; } SFileCloseFile( SubFile ); } else { // DEBUG_Print( "*** not found: " + *i ); } } if( !FoundScript ) CONSOLE_Print( "[MAP] couldn't find war3map.j or scripts\\war3map.j in MPQ file, calculated map_crc/sha1 is probably wrong" ); MapCRC = UTIL_CreateByteArray( Val, false ); CONSOLE_Print( "[MAP] calculated map_crc = " + UTIL_ByteArrayToDecString( MapCRC ) ); m_GHost->m_SHA->Final( ); unsigned char SHA1[20]; memset( SHA1, 0, sizeof( unsigned char ) * 20 ); m_GHost->m_SHA->GetHash( SHA1 ); MapSHA1 = UTIL_CreateByteArray( SHA1, 20 ); CONSOLE_Print( "[MAP] calculated map_sha1 = " + UTIL_ByteArrayToDecString( MapSHA1 ) ); } else CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - map MPQ file not loaded" ); } } } else CONSOLE_Print( "[MAP] no map data available, using config file for map_size, map_info, map_crc, map_sha1" ); // try to calculate map_width, map_height, map_slot<x>, map_numplayers, map_numteams uint32_t MapOptions = 0; BYTEARRAY MapWidth; BYTEARRAY MapHeight; uint32_t MapNumPlayers = 0; uint32_t MapNumTeams = 0; vector<CGameSlot> Slots; if( !m_MapData.empty( ) ) { if( MapMPQReady ) { HANDLE SubFile; if( SFileOpenFileEx( MapMPQ, "war3map.w3i", 0, &SubFile ) ) { uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { char *SubFileData = new char[FileLength]; DWORD BytesRead = 0; if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) { istringstream ISS( string( SubFileData, BytesRead ) ); // war3map.w3i format found at http://www.wc3campaigns.net/tools/specs/index.html by Zepir/PitzerMike string GarbageString; uint32_t FileFormat; uint32_t RawMapWidth; uint32_t RawMapHeight; uint32_t RawMapFlags; uint32_t RawMapNumPlayers; uint32_t RawMapNumTeams; ISS.read( (char *)&FileFormat, 4 ); // file format (18 = ROC, 25 = TFT) if( FileFormat == 18 || FileFormat == 25 ) { ISS.seekg( 4, ios :: cur ); // number of saves ISS.seekg( 4, ios :: cur ); // editor version getline( ISS, GarbageString, '\0' ); // map name getline( ISS, GarbageString, '\0' ); // map author getline( ISS, GarbageString, '\0' ); // map description getline( ISS, GarbageString, '\0' ); // players recommended ISS.seekg( 32, ios :: cur ); // camera bounds ISS.seekg( 16, ios :: cur ); // camera bounds complements ISS.read( (char *)&RawMapWidth, 4 ); // map width ISS.read( (char *)&RawMapHeight, 4 ); // map height ISS.read( (char *)&RawMapFlags, 4 ); // flags ISS.seekg( 1, ios :: cur ); // map main ground type if( FileFormat == 18 ) ISS.seekg( 4, ios :: cur ); // campaign background number else if( FileFormat == 25 ) { ISS.seekg( 4, ios :: cur ); // loading screen background number getline( ISS, GarbageString, '\0' ); // path of custom loading screen model } getline( ISS, GarbageString, '\0' ); // map loading screen text getline( ISS, GarbageString, '\0' ); // map loading screen title getline( ISS, GarbageString, '\0' ); // map loading screen subtitle if( FileFormat == 18 ) ISS.seekg( 4, ios :: cur ); // map loading screen number else if( FileFormat == 25 ) { ISS.seekg( 4, ios :: cur ); // used game data set getline( ISS, GarbageString, '\0' ); // prologue screen path } getline( ISS, GarbageString, '\0' ); // prologue screen text getline( ISS, GarbageString, '\0' ); // prologue screen title getline( ISS, GarbageString, '\0' ); // prologue screen subtitle if( FileFormat == 25 ) { ISS.seekg( 4, ios :: cur ); // uses terrain fog ISS.seekg( 4, ios :: cur ); // fog start z height ISS.seekg( 4, ios :: cur ); // fog end z height ISS.seekg( 4, ios :: cur ); // fog density ISS.seekg( 1, ios :: cur ); // fog red value ISS.seekg( 1, ios :: cur ); // fog green value ISS.seekg( 1, ios :: cur ); // fog blue value ISS.seekg( 1, ios :: cur ); // fog alpha value ISS.seekg( 4, ios :: cur ); // global weather id getline( ISS, GarbageString, '\0' ); // custom sound environment ISS.seekg( 1, ios :: cur ); // tileset id of the used custom light environment ISS.seekg( 1, ios :: cur ); // custom water tinting red value ISS.seekg( 1, ios :: cur ); // custom water tinting green value ISS.seekg( 1, ios :: cur ); // custom water tinting blue value ISS.seekg( 1, ios :: cur ); // custom water tinting alpha value } ISS.read( (char *)&RawMapNumPlayers, 4 ); // number of players uint32_t ClosedSlots = 0; for( uint32_t i = 0; i < RawMapNumPlayers; i++ ) { CGameSlot Slot( 0, 255, SLOTSTATUS_OPEN, 0, 0, 1, SLOTRACE_RANDOM ); uint32_t Colour; uint32_t Status; uint32_t Race; ISS.read( (char *)&Colour, 4 ); // colour Slot.SetColour( Colour ); ISS.read( (char *)&Status, 4 ); // status if( Status == 1 ) Slot.SetSlotStatus( SLOTSTATUS_OPEN ); else if( Status == 2 ) { Slot.SetSlotStatus( SLOTSTATUS_OCCUPIED ); Slot.SetComputer( 1 ); Slot.SetComputerType( SLOTCOMP_NORMAL ); } else { Slot.SetSlotStatus( SLOTSTATUS_CLOSED ); ClosedSlots++; } ISS.read( (char *)&Race, 4 ); // race if( Race == 1 ) Slot.SetRace( SLOTRACE_HUMAN ); else if( Race == 2 ) Slot.SetRace( SLOTRACE_ORC ); else if( Race == 3 ) Slot.SetRace( SLOTRACE_UNDEAD ); else if( Race == 4 ) Slot.SetRace( SLOTRACE_NIGHTELF ); else Slot.SetRace( SLOTRACE_RANDOM ); ISS.seekg( 4, ios :: cur ); // fixed start position getline( ISS, GarbageString, '\0' ); // player name ISS.seekg( 4, ios :: cur ); // start position x ISS.seekg( 4, ios :: cur ); // start position y ISS.seekg( 4, ios :: cur ); // ally low priorities ISS.seekg( 4, ios :: cur ); // ally high priorities if( Slot.GetSlotStatus( ) != SLOTSTATUS_CLOSED ) Slots.push_back( Slot ); } ISS.read( (char *)&RawMapNumTeams, 4 ); // number of teams for( uint32_t i = 0; i < RawMapNumTeams; i++ ) { uint32_t Flags; uint32_t PlayerMask; ISS.read( (char *)&Flags, 4 ); // flags ISS.read( (char *)&PlayerMask, 4 ); // player mask for( unsigned char j = 0; j < 12; j++ ) { if( PlayerMask & 1 ) { for( vector<CGameSlot> :: iterator k = Slots.begin( ); k != Slots.end( ); k++ ) { if( (*k).GetColour( ) == j ) (*k).SetTeam( i ); } } PlayerMask >>= 1; } getline( ISS, GarbageString, '\0' ); // team name } // the bot only cares about the following options: melee, fixed player settings, custom forces // let's not confuse the user by displaying erroneous map options so zero them out now MapOptions = RawMapFlags & ( MAPOPT_MELEE | MAPOPT_FIXEDPLAYERSETTINGS | MAPOPT_CUSTOMFORCES ); CONSOLE_Print( "[MAP] calculated map_options = " + UTIL_ToString( MapOptions ) ); MapWidth = UTIL_CreateByteArray( (uint16_t)RawMapWidth, false ); CONSOLE_Print( "[MAP] calculated map_width = " + UTIL_ByteArrayToDecString( MapWidth ) ); MapHeight = UTIL_CreateByteArray( (uint16_t)RawMapHeight, false ); CONSOLE_Print( "[MAP] calculated map_height = " + UTIL_ByteArrayToDecString( MapHeight ) ); MapNumPlayers = RawMapNumPlayers - ClosedSlots; CONSOLE_Print( "[MAP] calculated map_numplayers = " + UTIL_ToString( MapNumPlayers ) ); MapNumTeams = RawMapNumTeams; CONSOLE_Print( "[MAP] calculated map_numteams = " + UTIL_ToString( MapNumTeams ) ); uint32_t SlotNum = 1; for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) { CONSOLE_Print( "[MAP] calculated map_slot" + UTIL_ToString( SlotNum ) + " = " + UTIL_ByteArrayToDecString( (*i).GetByteArray( ) ) ); SlotNum++; } if( MapOptions & MAPOPT_MELEE ) { CONSOLE_Print( "[MAP] found melee map, initializing slots" ); // give each slot a different team and set the race to random unsigned char Team = 0; for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) { (*i).SetTeam( Team++ ); (*i).SetRace( SLOTRACE_RANDOM ); } } if( !( MapOptions & MAPOPT_FIXEDPLAYERSETTINGS ) ) { // make races selectable for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) (*i).SetRace( (*i).GetRace( ) | SLOTRACE_SELECTABLE ); } } } else