package com.rs.tools;

/* 
 * CRC-32 forcer
 * 
 * Copyright (c) 2014 Project Nayuki
 * All rights reserved. Contact Nayuki for licensing.
 * http://www.nayuki.io/page/forcing-a-files-crc-to-any-value
 */

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;


public class ForceCRC {
	

	
	
	public static void main(String[] args) {
		// Handle arguments
		long offset = 0;
		int newCrc;
		long temp = 1169742478;
		if ((temp & 0xFFFFFFFFL) != temp)
			return;
		newCrc = 1169742478;//Integer.reverse((int)temp);
		
		// Process the file

				
				// Read entire file and calculate original CRC-32 value
				int crc = -970787043;
				System.out.printf("Original CRC-32: %08X%n", Integer.reverse(crc));
				
				// Compute the change to make
				int delta = crc ^ newCrc;
				delta = (int)multiplyMod(reciprocalMod(powMod(2, (0 - offset) * 8)), delta & 0xFFFFFFFFL);
				
				// Patch 4 bytes in the file
		
				byte[] bytes4 = new byte[4];

				for (int i = 0; i < bytes4.length; i++)
					bytes4[i] ^= Integer.reverse(delta) >>> (i * 8);
				System.out.println("Computed and wrote patch "+Arrays.toString(bytes4));


	}
	
	
	/* Utilities */
	
	private static long POLYNOMIAL = 0x104C11DB7L;  // Generator polynomial. Do not modify, because there are many dependencies
	
	
	private static int getCrc32(RandomAccessFile raf) throws IOException {
		raf.seek(0);
		int crc = 0xFFFFFFFF;
		byte[] buffer = new byte[32 * 1024];
		while (true) {
			int n = raf.read(buffer);
			if (n == -1)
				return ~crc;
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < 8; j++) {
					crc ^= (buffer[i] >>> j) << 31;
					if ((crc & (1 << 31)) != 0)
						crc = (crc << 1) ^ (int)POLYNOMIAL;
					else
						crc <<= 1;
				}
			}
		}
	}
	
	
	/* Polynomial arithmetic */
	
	// Returns polynomial x multiplied by polynomial y modulo the generator polynomial.
	private static long multiplyMod(long x, long y) {
		// Russian peasant multiplication algorithm
		long z = 0;
		while (y != 0) {
			z ^= x * (y & 1);
			y >>>= 1;
			x <<= 1;
			if ((x & (1L << 32)) != 0)
				x ^= POLYNOMIAL;
		}
		return z;
	}
	
	
	// Returns polynomial x to the power of natural number y modulo the generator polynomial.
	private static long powMod(long x, long y) {
		// Exponentiation by squaring
		long z = 1;
		while (y != 0) {
			if ((y & 1) != 0)
				z = multiplyMod(z, x);
			x = multiplyMod(x, x);
			y >>>= 1;
		}
		return z;
	}
	
	
	// Computes polynomial x divided by polynomial y, returning the quotient and remainder.
	private static long[] divideAndRemainder(long x, long y) {
		if (y == 0)
			throw new IllegalArgumentException("Division by zero");
		if (x == 0)
			return new long[]{0, 0};
		
		int ydeg = getDegree(y);
		long z = 0;
		for (int i = getDegree(x) - ydeg; i >= 0; i--) {
			if ((x & (1 << (i + ydeg))) != 0) {
				x ^= y << i;
				z |= 1 << i;
			}
		}
		return new long[]{z, x};
	}
	
	
	// Returns the reciprocal of polynomial x with respect to the generator polynomial.
	private static long reciprocalMod(long x) {
		// Based on a simplification of the extended Euclidean algorithm
		long y = x;
		x = POLYNOMIAL;
		long a = 0;
		long b = 1;
		while (y != 0) {
			long[] divRem = divideAndRemainder(x, y);
			long c = a ^ multiplyMod(divRem[0], b);
			x = y;
			y = divRem[1];
			a = b;
			b = c;
		}
		if (x == 1)
			return a;
		else
			throw new IllegalArgumentException("Reciprocal does not exist");
	}
	
	
	private static int getDegree(long x) {
		return 63 - Long.numberOfLeadingZeros(x);
	}
	
}