#include <stdio.h>
#include <memory.h>

int myrand(int *seed){
	int tmp;
	tmp = ((*seed * 257 >> 8) + *seed * 97) + 23 ^ -1496474763;
	*seed = tmp >> 16 & 65535 | tmp << 16;
	return *seed & 32767;
}

//           0 : success!
// -2147483647 : wrong header
// -2147483646 : wrong checksum
int decrypt(char *a) {
	int r, counter, ret;
	char *a_header, *a_body;
	int flags[64], seed, i, s;
	char *target;
	int check_sum,check_xor;
	ret = -2147483647;
	a_header = a;
	a_body = a + 16;
	if (strcmp(a_header + 0, "BSE 1.0")) return ret;
	if (*(short *)(a_header + 8) != 256) return ret;
	memset(flags, 0, 64 * 4);
	seed = *(long *)(a_header + 12);
	counter = 0;
	do {
		r = myrand(&seed);
		i = r & 64 - 1;
		while (flags[i]){
			i = i + 1 & 64 - 1;
		}
		r = myrand(&seed);
		s = r & 7;
		target = (a_body + 0) + i;
		r = myrand(&seed);
		switch(r & 1){
		case 0:
			r = myrand(&seed);
			r = (*target & 255) - r & 255;
			*target = r >> s | r << 8 - s;  // rotate shift right
			break;
		case 1:
			r = myrand(&seed);
			r = (*target & 255) - r & 255;
			*target = r << s | r >> 8 - s;  // rotate shift left
			break;
		}
		flags[i] = 1;  // done
		counter = counter + 1;
	} while (counter < 64);
	check_sum = 0;
	check_xor = 0;
	target = a_body + 0;
	counter = 0;
	do {
		check_sum = check_sum + (target[counter] & 255);
		check_xor = check_xor ^ (target[counter] & 255);
		counter = counter + 1;
	} while (counter < 64);
	ret =
		(a_header[10] & 255) == (check_sum & 255) &&
		(a_header[11] & 255) == (check_xor & 255) ?
			0 : -2147483646;
	return ret;
}

int main(void) {
	int ret, i;
	unsigned char a[] = {
		0x42, 0x53, 0x45, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x00, 0x01, 0xe0, 0xda,
		0xc9, 0xa5, 0x6d, 0x70, 0x20, 0xed, 0x53, 0x38, 0x7d, 0x95, 0xe3, 0x03,
		0x2c, 0xbe, 0x10, 0xd9, 0x42, 0x70, 0x09, 0x16, 0xa6, 0x77, 0xcd, 0x8f,
		0x80, 0x18, 0xdc, 0x3b, 0xd8, 0xf4, 0x22, 0x9e, 0xa5, 0x87, 0x03, 0x18,
		0xac, 0x3c, 0x71, 0x1f, 0xa0, 0xd5, 0x1f, 0x68, 0x1e, 0x06, 0x95, 0x46,
		0x4e, 0xc0, 0x18, 0x17, 0x53, 0x78, 0xd7, 0x3a, 0x53, 0x70, 0x9b, 0x52,
		0x82, 0x81, 0xe5, 0x01, 0xe9, 0xa8, 0xe0, 0x79, 0xce, 0x43, 0x74, 0xa4,
		0x01, 0xce, 0x15, 0x91, 0x4e, 0x20, 0xd5, 0xa3, 0x7c, 0x83, 0x09, 0x1a,
	};
	ret = decrypt((char *)a);
	if (ret == 0) {
		for (i = 0x10; i < 0x80; ++i) printf("%02x ", a[i]);
		printf("\n", ret);
	} else {
		printf("%08x\n", ret);
	}
	return 0;
}
