Beispiel #1
0
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;
}
Beispiel #2
0
int CheckRevision(const char *formula, const char *files[], int numFiles, int mpqNumber, uint32_t *checksum) {
	uint32_t values[4], ovd[4], ovs1[4], ovs2[4];
	char ops[4];
	const char *token;
	int curFormula, i, k, variable;
	unsigned char *file_buffer, *pad_dest, pad;
	uint32_t *dwBuf, *current;
	unsigned int file_len, remainder, rounded_size, buffer_size, j;
	#ifdef _WIN32
		HANDLE hFile;
		HANDLE hFileMapping;
	#else
		FILE *f;
	#endif


	if (mpqNumber > 7 || mpqNumber < 0) 
		return 1;
	
	curFormula = 0;
	token = formula;
	while (token && *token) {
		if (*(token + 1) == '=') {
			variable = BUCR_GETNUM(*token);
			if (variable < 0 || variable > 3)
				return 2;
			token += 2;
			if (BUCR_ISNUM(*token)) {
				values[variable] = strtoul(token, NULL, 10);
			} else {
				if (curFormula > 3)
					return 3;
				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;
			}
		}
	}
	
	values[0] ^= checksumseeds[mpqNumber];
	
	for (i = 0; i < numFiles; i++) {
		#ifdef _WIN32
			hFile = CreateFile(files[i], GENERIC_READ, FILE_SHARE_READ,
				NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
			if (!hFile)
				return 4;
			file_len = GetFileSize(hFile, NULL);
			hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
			if (!hFileMapping)
				return 5;
			file_buffer = (unsigned char *)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
		#else
			f = fopen(files[i], "rb");
			if (!f)
				return 4;
			fseek(f, 0, SEEK_END);
			file_len = ftell(f);
			rewind(f);
			file_buffer = (unsigned char *)mmap(NULL, file_len, PROT_READ, MAP_SHARED, fileno(f), 0);
		#endif

		if (!file_buffer) {
			#ifdef _WIN32
				CloseHandle(hFile);
			#else
				fclose(f);
			#endif
			return 5;
		}

		remainder = file_len & 0x3FF;
		rounded_size = file_len - remainder;
		if (!remainder) {
			dwBuf = (uint32_t *)file_buffer;
			buffer_size = file_len;
		} else {
			size_t extra = 1024 - remainder;
			pad = (unsigned char)0xFF;
			
			buffer_size = file_len + extra;
			dwBuf = malloc(buffer_size);
			
			memcpy(dwBuf, file_buffer, file_len);
			
			#ifdef _WIN32
				UnmapViewOfFile(file_buffer);
				CloseHandle(hFileMapping);
			#else
				munmap(file_buffer, file_len);
			#endif
			file_buffer = NULL;
			
			pad_dest = ((unsigned char *)dwBuf) + file_len;
			for (j = file_len; j < buffer_size; j++)
				*pad_dest++ = pad--;
		}

		current = dwBuf;
		for (j = 0; j < (buffer_size / sizeof(uint32_t)); j++) {
			values[3] = current[j];
			for (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;
					default:
						#ifdef _WIN32
							UnmapViewOfFile(dwBuf);
							CloseHandle(hFileMapping);
							CloseHandle(hFile);
						#else
							munmap(dwBuf, file_len);
							fclose(f);
						#endif
						return 6;
				}
			}
		}

		if (file_buffer) {
			#ifdef _WIN32
				UnmapViewOfFile(file_buffer);
				CloseHandle(hFileMapping);
			#else
				munmap(file_buffer, file_len);
			#endif
		} else if (dwBuf && !file_buffer) {
			free(dwBuf);
		}
		#ifdef _WIN32
			CloseHandle(hFile);
		#else
			fclose(f);
		#endif
	}

	*checksum = values[2];
	return 0;
}