[ create a new paste ] login | about

Link: http://codepad.org/2Q8STDPz    [ raw code | fork ]

C++, pasted on Oct 22:
// ObjectMergerFixer.cpp
// VERSION 4 [2016_10_22]
// BY SourceSeeker

// THANKS TO:
// - PitzerMike (AUTHOR OF GRIMEX) FOR PUBLISHING HIS SOURCE CODE
// - Barade (http://www.hiveworkshop.com/members/barade.125524/) FOR HELPFUL TIPS ON MPQ API



#include "sfmpq/SFmpqapi_no-lib.h" // HEADER FOR: MpqOpenArchiveForUpdate, ...
//#include <windows.h>	// ALREADY INCLUDED IN: "sfmpq/SFmpqapi_no-lib.h"

#include <iostream>		// SYSTEM HEADER FOR: cout
#include <fstream>		// SYSTEM HEADER FOR: ofstream
#include <vector>		// SYSTEM HEADER FOR: vector
#include <algorithm>	// SYSTEM HEADER FOR: search

#include <sstream>		// SYSTEM HEADER FOR: stringstream (TO CONCAT STRINGS)

using namespace std;



// MORE USEFUL STL FUNCTIONS & COMMENTS FOR "function_getOutputVector" IN MY VERSION 3:
// D:\Privat\Anwendung\Programm\CODING\C\dev-cpp\c_warcraft\ver3_readFileBinary,HexEdit,NewFile.cpp

// C++ DLL (= Dynamic Linked Library) TUTORIAL:
// http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855/DLL-Tutorial-For-Beginners.htm



vector<char> function_getOutputVector( char * c_buf, int size ) {
	// copies all data into buffer:
	vector<char> v_buffer( c_buf, c_buf +size );
	// How to convert char* to std::vector:
		// http://stackoverflow.com/questions/4272445/how-to-convert-char-to-stdvector
	// TUTORIAL:
		// http://www.cprogramming.com/tutorial/stl/vector.html
	// std::vector<int> vec_five(aList.begin(), aList.end());
		// A vector can also be initialized using elements from another collection, by means of a beginning and ending iterator pair.
		// The arguments can be any form of iterator; thus collections can be initialized with values drawn from any of the container classes in the C++ Standard Library that support iterators.
		// http://stdcxx.apache.org/doc/stdlibug/5-2.html
	
	vector<char> v_output;
	vector<char>::iterator it_counter;
	
	const char c_uaenId[9] = { 0x75, 0x61, 0x65, 0x6E, 0x03, 0x00, 0x00, 0x00 }; // { 0x75, 0x61, 0x65, 0x6E, ... } = { u, a, e, n, ... }
	int i_uaen_getValue;
	
	int i_distance;
	int i_distance2 = 0;
	
	
	
	// SEARCH FOR "uaen" IN BINARY STREAM AS HEX SEQUENCE: { 0x75, 0x61, 0x65, 0x6E, 0x03, 0x00, 0x00, 0x00 }
		// OBJECT MERGER ERROR 1:
		// THOSE LAST 4 BYTES SHOULD BE { 0x00, 0x00, 0x00, 0x00 }
	// FOR EACH MATCH RETRIEVE THE FOLLOWING BYTE WHICH CAN BE 0x48, 0x49, 0x50 OR 0x51 (0, 1, 2 OR 3)
		// OBJECT MERGER ERROR 2:
		// THIS BYTE SHOULD BE 0x00, 0x01, 0x02 OR 0x03, FOLLOWED BY 3 NULL BYTES,
		// INSTEAD THE BYTE IS 0x48, 0x49, 0x50 OR 0x51, FOLLOWED BY 1 NULL BYTE!
	// PUT CORRECT BYTES INTO OUTPUT VECTOR
	it_counter = search( v_buffer.begin(), v_buffer.end(), c_uaenId, c_uaenId + 8 );
		// http://stackoverflow.com/questions/16465087/is-there-a-function-that-is-to-stdsearch-what-stdcount-is-to-stdfind
	
	// IF W3U DOESN'T CONTAIN "uaen....", EXIT:
	if ( it_counter == v_buffer.end() ) {
		return vector<char>();
		//return {};
			// COMPILER: [Warning] extended initializer lists only available with -std=c++11 or -std=gnu++11
			// return an empty vector
			// EITHER USE: return {};
			// OR: return vector<char>();
			// http://stackoverflow.com/questions/24175507/return-an-empty-vector-c
		//return 0;
			// USED THIS WHEN IN FUNCTION main
	
	// IF W3U CONTAINS "uaen....", INSPECT FURTHER:
	} else {
		while ( it_counter != v_buffer.end() ) {
		//if ( find(buffer.begin(), buffer.end(), 0x03) != buffer.end() ) {
			// find(vector.begin(), vector.end(), item)
			// http://www.cplusplus.com/reference/algorithm/find/
			// http://stackoverflow.com/questions/571394/how-to-find-if-an-item-is-present-in-a-stdvector
			// http://gamedev.stackexchange.com/questions/114201/check-if-a-vector-element-exists-using-stdfind
			
			i_distance = it_counter - v_buffer.begin();
				// Effective way to get the index of an iterator?
				// INSTEAD OF: distance(vec.begin(), it)
				// USE: it - vec.begin()
				// http://stackoverflow.com/questions/2152986/effective-way-to-get-the-index-of-an-iterator
			//i_distance = distance( v_buffer.begin(), it_counter );
				// How do I find an element position in std::vector
				// http://stackoverflow.com/questions/1425349/how-do-i-find-an-element-position-in-stdvector
			
			
			
			// APPEND PART OF INPUT VECTOR buffer TO OUTPUT VECTOR v_output:
			// http://stackoverflow.com/questions/2551775/appending-a-vector-to-a-vector
			v_output.insert( v_output.end(), v_buffer.begin() +i_distance2, v_buffer.begin() +i_distance +4 );
				// insert (iterator position, InputIterator first, InputIterator last);
					// http://www.cplusplus.com/reference/vector/vector/insert/
				// .insert VS .at VS []
					// If we now print out   vec.insert(vec.begin()+2, 10);   we will get:
					// 1 2 10 3 4 5 0 0 
					// If, instead, we did   vec.at(2) = 10   , or   vec[2]=10   , we would get
					// 1 2 10 4 5 0 0 0
					// http://stackoverflow.com/questions/6726805/insert-an-element-into-a-specific-position-of-a-vector
				// + i + 4
					// http://stackoverflow.com/questions/421573/best-way-to-extract-a-subvector-from-a-vector
			
			i_distance2 = i_distance +4;
				// = EVERYTHING UNTIL (INLCUDING) ...uaen
			
			
			
			// GET uaen VALUE:
				// CAN BE: 0, 1, 2 OR 3
				// - 0 = NOTHING
				// - 1 = ONLY ATTACK 1
				// - 2 = ONLY ATTACK 2
				// - 3 = BOTH
			// GET CHAR VALUE AT INDEX OF VECTOR:
				// SOLUTION (JUST CAST TO int):
				// http://www.cplusplus.com/reference/vector/vector/operator%5B%5D/
				// http://cplusplusio0.blogspot.de/2015/03/convert-element-of-vector-into-type-t-c.html
				// http://stackoverflow.com/questions/6660145/convert-ascii-number-to-ascii-character-in-c
			i_uaen_getValue = (int)v_buffer[i_distance +8];
				// WRONG ATTEMPTS:
				//c_uaen_getValue = v_buffer[i_distance+8];
				//c_uaen_getValue = v_buffer.at(i_distance+8);
				//c_uaen_getValue = static_cast<char>(v_buffer[i_distance+8]);
			
			// int CONVERSION: ASCII VALUE OF NUMBER TO NUMBER:
			i_uaen_getValue = i_uaen_getValue - '0';
				// EXAMPLE:
				// '0' -> 0, '1' -> 1, ...
				// http://stackoverflow.com/questions/5029840/convert-char-to-int-in-c-and-c
			
			
			
			// ADD CHAR ARRAY AT END OF VECTOR:
			// ANSWER FROM "MattyT":
			// http://stackoverflow.com/questions/259297/how-do-you-copy-the-contents-of-an-array-to-a-stdvector-in-c-without-looping
			int dataArray[8] = { 0, 0, 0, 0, i_uaen_getValue, 0, 0, 0 };
			v_output.insert( v_output.end(), &dataArray[0], &dataArray[8] );
				// INSTEAD OF USING SEVERAL VECTOR.push_back() LIKE:
				//v_output.push_back('0');
			
			i_distance2 = i_distance2 +6;
			
			
			
			it_counter = search( v_buffer.begin() +i_distance+4, v_buffer.end(), c_uaenId, c_uaenId +4 );
		}
		
		
		
		// APPEND END OF INPUT VECTOR buffer TO OUTPUT VECTOR v_output:
		v_output.insert( v_output.end(), v_buffer.begin() +i_distance2, v_buffer.end() );
		
		return v_output;
	}
	
	return vector<char>();
	//return {};
		// COMPILER: [Warning] extended initializer lists only available with -std=c++11 or -std=gnu++11
		// return an empty vector
		// EITHER USE: return {};
		// OR: return vector<char>();
		// http://stackoverflow.com/questions/24175507/return-an-empty-vector-c
}



int main(int argc, char **argv) {
	
	funcMpqOpenArchiveForUpdate MpqOpenArchiveForUpdate = 0;
	funcMpqCloseUpdatedArchive MpqCloseUpdatedArchive = 0;
	funcMpqAddFileToArchive MpqAddFileToArchive = 0;
	//MpqAddFileToArchiveEx = 0;
	funcMpqAddFileFromBufferEx MpqAddFileFromBufferEx = 0;
	funcMpqAddFileFromBuffer MpqAddFileFromBuffer = 0;
	funcMpqCompactArchive MpqCompactArchive = 0;
	
	funcSFileOpenFileEx SFileOpenFileEx = 0;
	funcSFileGetFileSize SFileGetFileSize = 0;
	funcSFileReadFile SFileReadFile = 0;
	funcSFileCloseFile SFileCloseFile = 0;
	
	
	
	
	// SHOW MESSAGE BOX WITH ALL argv ARGUMENTS:
	
	// CONCAT STRINGS:
	// http://stackoverflow.com/questions/662918/how-do-i-concatenate-multiple-c-strings-on-one-line
	std::stringstream ss;
	//ss << "argc = " << argc << "\nargv[0] = " << argv[0] << "\nargv[1] = " << argv[1] << "\nargv[2] = " << argv[2];
	//std::string s = ss.str();
	
	// STEP THROUGH ARRAY argv & PRINT ALL COMMAND-LINE ARGUMENTS:
	// http://www.site.uottawa.ca/~lucia/courses/2131-05/labs/Lab3/CommandLineArguments.html
	for(int i=0; i<argc; i++)
		ss << "argv[" << i << "] = " << argv[i] << "\n"; 
	std::string s = ss.str();
	
	// CREATE A MESSAGE BOX VIA WINDOWS API:
	// https://social.msdn.microsoft.com/Forums/de-DE/d70a77b7-1508-4884-a5bc-106cf068b1be/how-can-i-show-messagebox-in-visual-c?forum=vcgeneral
	//MessageBox(0, "And text here", "MessageBox caption", MB_OK);
	//MessageBox(0, s.c_str(), "MessageBox caption", MB_OK);
		// RETURNS:
		// argv[0] = grimext\ObjectMergerFixer.exe
		// argv[1] = C:\Spiele\Warcraft III\Maps\_SourceSeeker\test_objectMergerW3u.w3m
		// argv[2] = ./jass/
	
	
	
	HINSTANCE hSFMpq = 0;
	hSFMpq = LoadLibrary("SFMpq.dll");
		// "SFMpq.dll" FROM PitzerMike WAS BUILD AS 32-BIT DLL!
		// IF YOU WANT TO USE THIS DLL, YOUR PROJECT HAS TO BE COMPILED AS 32-BIT TOO, OTHERWISE THE DLL ISN'T LOADED!
		// SEE: "_dev-c++_setting & sfmpq.png"
	
	if (hSFMpq!=0) {
		
		// DEBUG:
		//cout << "ok: DLL loaded\n" << "HIT ENTER TO CONTINUE!\n";
		//getchar();
		
		MpqOpenArchiveForUpdate = (funcMpqOpenArchiveForUpdate)GetProcAddress(hSFMpq,"MpqOpenArchiveForUpdate");
		MpqCloseUpdatedArchive = (funcMpqCloseUpdatedArchive)GetProcAddress(hSFMpq,"MpqCloseUpdatedArchive");
		MpqAddFileToArchive = (funcMpqAddFileToArchive)GetProcAddress(hSFMpq,"MpqAddFileToArchive");
		//MpqAddFileToArchiveEx = (funcMpqAddFileToArchiveEx)GetProcAddress(hSFMpq,"MpqAddFileToArchiveEx");
		MpqAddFileFromBufferEx = (funcMpqAddFileFromBufferEx)GetProcAddress(hSFMpq,"MpqAddFileFromBufferEx");
		MpqAddFileFromBuffer = (funcMpqAddFileFromBuffer)GetProcAddress(hSFMpq,"MpqAddFileFromBuffer");
		MpqCompactArchive = (funcMpqCompactArchive)GetProcAddress(hSFMpq,"MpqCompactArchive");
		
		SFileOpenFileEx = (funcSFileOpenFileEx)GetProcAddress(hSFMpq,"SFileOpenFileEx");
		SFileGetFileSize = (funcSFileGetFileSize)GetProcAddress(hSFMpq,"SFileGetFileSize");
		SFileReadFile = (funcSFileReadFile)GetProcAddress(hSFMpq,"SFileReadFile");
		SFileCloseFile = (funcSFileCloseFile)GetProcAddress(hSFMpq,"SFileCloseFile");
		
		
		
		HANDLE mpq = MpqOpenArchiveForUpdate(argv[1], MOAU_OPEN_EXISTING | MOAU_MAINTAIN_LISTFILE, 1024);
		//HANDLE mpq = MpqOpenArchiveForUpdate("C:\\Spiele\\Warcraft III\\Maps\\_SourceSeeker\\test_objectMergerW3u.w3m", MOAU_OPEN_EXISTING | MOAU_MAINTAIN_LISTFILE, 1024);
			// HANDLE
				// = typdef LPVOID HANDLE
				// DEFINED IN: "sfmpq/SFmpqapi_no-lib.h", DEFINED IN: <windows.h>
			// MpqOpenArchiveForUpdate
				// USED IN: PitzerMike TOOLS IN "ObjectMerger/main.cpp":
					//HANDLE mpq = MpqOpenArchiveForUpdate(argv[1], MOAU_OPEN_EXISTING | MOAU_MAINTAIN_LISTFILE, 1024);
				// = typedef MPQHANDLE (WINAPI* funcMpqOpenArchiveForUpdate)(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive);
				// DEFINED IN: "sfmpq/SFmpqapi_no-lib.h"
				// DEFINED IN: "sfmpq/SFmpqapi_no-lib.cpp"
				// = MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive)
				// DEFINED IN:
					// https://github.com/ShadowFlare/SFmpqapi/blob/master/SFmpqapi.cpp
			// argv[1]
				// = ABSOLUTE PATH TO WARCRAFT MAP
				// EXAMPLE: C:\Spiele\Warcraft III\Maps\_SourceSeeker\test_objectMergerW3u.w3m
			// MOAU_OPEN_EXISTING
				// = #define MOAU_OPEN_EXISTING     0x04
				// DEFINED IN: "sfmpq/SFmpqapi_no-lib.h"
			// MOAU_MAINTAIN_LISTFILE
				// = #define MOAU_MAINTAIN_LISTFILE 0x01
				// DEFINED IN: "sfmpq/SFmpqapi_no-lib.h"
		
		HANDLE file;
			// DEFINED IN: "sfmpq/SFmpqapi_no-lib.h"
			// AS: #include <windows.h> // = HEADER FOR: HANDLE = typdef LPVOID HANDLE
		
		if(!SFileOpenFileEx(mpq, "war3map.w3u", 0, &file)) {
			// DEBUG:
			MessageBox(0, "fail: could not open 'war3map.w3u'", "error", MB_OK);
			cout << "fail: could not open 'war3map.w3u'\n" << "HIT ENTER TO CONTINUE!\n";
			getchar();
			return 0;
		}
		
		DWORD size = SFileGetFileSize(file, 0);
			// Retrieves a size of the file within archive
			// http://www.zezula.net/en/mpq/stormlib.html
		
		char * c_buf = new char[size];
		
		SFileReadFile(file, c_buf, size, &size, NULL);
			// Reads data from the file
			// http://www.zezula.net/en/mpq/stormlib.html
			// CONTENT FROM FILE file IS SAVED TO buf.buf
		
		SFileCloseFile(file);
		
		
		
		// FIX W3U uaen FIELDS:
		vector<char> v_output = function_getOutputVector(c_buf, size);
		
		// DEBUG:
		//if ( v_output.empty() ) {
		//	cout << "map's W3U not touched; no wrong 'uaen....' found!\n" << "HIT ENTER TO CONTINUE!\n";
		//	getchar();
		//}
		
		
		
		// ADD FIXED W3U BACK TO W3M/W3X:
		
		if ( !MpqAddFileFromBufferEx(mpq, (LPVOID)&v_output[0], v_output.size(), "war3map.w3u", MAFA_REPLACE_EXISTING | MAFA_COMPRESS, MAFA_COMPRESS_DEFLATE, Z_BEST_COMPRESSION) ) {
			// DEBUG:
			MessageBox(0, "fail: could not write 'war3map.w3u'", "error", MB_OK);
			cout << "fail: could not write 'war3map.w3u'\n" << "HIT ENTER TO CONTINUE!\n";
			getchar();
		}
			// USED IN: PitzerMike TOOLS IN "common/io.cpp":
				// result = MpqAddFileFromBufferEx(mpq, (LPVOID)buf, length, filename, MAFA_REPLACE_EXISTING | MAFA_COMPRESS, MAFA_COMPRESS_DEFLATE, Z_BEST_COMPRESSION);
			// API:
				// BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
				// https://github.com/ShadowFlare/SFmpqapi/blob/master/SFmpqapi.cpp
		//MpqAddFileFromBufferEx(mpq, (LPVOID)c_buf, size, "war3map.w3u", MAFA_REPLACE_EXISTING | MAFA_COMPRESS, MAFA_COMPRESS_DEFLATE, Z_BEST_COMPRESSION);
		
		//MpqAddFileToArchive(mpq, c_buf, "war3map.w3u", MAFA_REPLACE_EXISTING | MAFA_COMPRESS);
			// MpqAddFileToArchive(...)
			// USED IN: PitzerMike TOOLS IN "common/io.cpp":
				// bool filetoarchive(const char *source, HANDLE &mpq, const char* filename) {
					// ...
					// result = MpqAddFileToArchiveEx(mpq, source, filename, MAFA_REPLACE_EXISTING | MAFA_COMPRESS, MAFA_COMPRESS_DEFLATE, Z_BEST_COMPRESSION);
			// API:
				// BOOL SFMPQAPI WINAPI MpqAddFileToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags)
				// {
				// return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x08,0);
				// }
				// https://github.com/ShadowFlare/SFmpqapi/blob/master/SFmpqapi.cpp
			// MAFA_REPLACE_EXISTING | MAFA_COMPRESS
			// MAFA
				// = Mpq Add File to Archive
		//MpqAddFileToArchive(mpq, &v_output[0], "war3map.w3u", MAFA_REPLACE_EXISTING | MAFA_COMPRESS);
			// How to convert vector to array C++:
				//std::vector<double> v;
				//double* a = &v[0];
				// http://stackoverflow.com/questions/2923272/how-to-convert-vector-to-array-c
		
		
		
		// DEBUG:
		ofstream ofs_file1( "_out1.txt", ios::out | ios::binary );
		ofstream ofs_file2( "_out2.txt", ios::out | ios::binary );
		ofs_file1.write( c_buf, size );
		ofs_file2.write( &v_output[0], v_output.size() );
			// write (const char* s, streamsize n);
			// Inserts the first n characters of the array pointed by s into the stream
			// http://www.cplusplus.com/reference/ostream/ostream/write/
		
		
		
		//MpqCompactArchive(mpq);
		if ( !MpqCloseUpdatedArchive(mpq, 0) ) {
			// DEBUG:
			MessageBox(0, "fail: could not update MPQ", "error", MB_OK);
			cout << "fail: could not update MPQ\n" << "HIT ENTER TO CONTINUE!\n";
			getchar();
		}
	} else {
		// DEBUG:
		MessageBox(0, "fail: could not load 'SFMpq.dll'", "error", MB_OK);
		cout << "fail: could not load 'SFMpq.dll'\n" << "HIT ENTER TO CONTINUE!\n";
		getchar();
	}
	
	
	
	// DEBUG:
	MessageBox(0, "reached end of code of ObjectMergerFixer", "debug", MB_OK);
	
	return 0;
}


Create a new paste based on this one


Comments: