#!/bin/env python
#coding:utf-8
#
# th7 replay parser module.
# 
# Original sources:
#	http://touhou.csie.org/replay/ptsrply.php?source
#	piaip''s Touhou Series Replay Management system
#	Replay File Parser Module
# 
# Modified by dl.
# 
# License under Creative Commons License
# http://creativecommons.org/licenses/by-nc-sa/2.5/
# 
# Thanks to Chikei Lee and Piaip.
#

import os, sys, string, binascii, struct

# get th7 replay info.
#
# param: 
#	[replay-filepath]
# return: 
#	array[date, player, char, score, rank, version. drop]
#	  kind of chars:
#	   ("ReimuA", "ReimuB", "MarisaA", "MarisaB", "SakuyaA", "SakuyaB")
#	  kind of ranks: 
#	   ("Easy","Normal","Hard","Lunatic","Extra","Phantasm")
def TH7Replay_getReplayFileInfo(filepath):
	# for ms-windows
	try:
		import msvcrt
		msvcrt.setmode(0, os.O_BINARY)
		msvcrt.setmode(1, os.O_BINARY)
	except ImportError:
		pass
	
	# [date, player, char, score, rank, version, drop]
	retArray = ["", "", "", "", "", "", ""]
	
	fin = None
	dat = None
	try:
		fin = open(filepath, "rb")
		dat = fin.read()
	finally:
		if fin:
			fin.close()
	
	if len(dat) <= 4:
		return retArray
	
	if dat[0:4] != "T7RP":
		return retArray
	
	
	# format and decode method provided to Chikei Lee 2004/9/10
	# rewritten as php by piaip
	# rewritten as perl by dl
	# rewritten as python by dl
	dat2 = dat[0:0x10]
	min_info = 0x100

	# decrypt
	mask = ord(dat[0x0d])
	for i in range(0x10, len(dat)):
		dat2 += chr((ord(dat[i]) - mask) & 0xff)
		mask = (mask + 7) & 0xff
	
	if( len(dat) < 1 or \
			(ord(dat2[len(dat)-1]) != 0x80 and ord(dat2[len(dat)-1]) != 0x00)):
		return retArray
	
	dat = dat2
	dat2 = ''
	# decompress
	# -- vars
	v04 = 0 
	v1c = 0 
	v30 = 0 
	v0c = 0 
	v24 = 0 
	v10 = 0 
	v2c = 0 
	v28 = 0 
	v34 = 1 
	v11 = 0x80 
	v20 = 0
	# reinit v20
	for i in range(0,4):
		v20 = v20 * 0x100 + ord(dat[0x17-i])
	
	v3c = v20
	v4b = []
	for i in range(0,2048):
		v4b.append(0)
	

	# not compressed until 0x54
	ibase = 0x54
	i	= ibase	# input
	dat2 = dat[0:ibase]

	while(len(dat2) < min_info):
		flStopDoLoop = 0
		while(len(dat2) < min_info):
			flFirstRun = 1
			tmpFirst = True
			while(v30!=0 or tmpFirst):
				tmpFirst = False
				if(v11==0x80):
					v04=ord(dat[i])
					if(i-ibase < v20):
						i += 1
					else:
						v04 = 0
					v28 += v04
				if(flFirstRun == 1):
					v1c = v04 & v11
					v11 = v11 >> 1

					if (v11 == 0):
						v11=0x80
					if (v1c == 0):
						flStopDoLoop = 1
						break
					v30 = 0x80
					v1c = 0
					flFirstRun = 0
				else:
					if ((v11 & v04)!=0):
						v1c=v1c | v30
					v30=v30 >> 1
					v11=v11 >> 1
					if(v11==0):
						v11=0x80
			
			
			if(flStopDoLoop == 1):
				break
			dat2 += chr(v1c)
			v4b[v34] = chr(v1c & 0xff)
			v34 = (v34+1) & 0x1FFF
		
		if (len(dat2) > min_info):
			break
		v30 = 0x1000
		v1c = 0

		while(v30!=0):
			if(v11==0x80):
				v04=ord(dat[i])
				if(i-ibase < v20):
					i += 1
				else:
					v04 = 0
				v28 += v04

			if((v11 & v04)!=0):
				v1c = v1c | v30
			v30 = v30>>1
			v11 = v11>>1
			if(v11==0):
				v11 = 0x80

		v0c = v1c
		if(v0c==0):
			break

		v30=8
		v1c=0
		while (v30 != 0):
			if (v11 == 0x80):
				v04=ord(dat[i])
				if(i-ibase < v20):
					i += 1
				else:
					v04 = 0
				v28 += v04
			
			if((v11 & v04)!=0):
				v1c=v1c|v30

			v30=v30>>1
			v11=v11>>1 
			if(v11==0):
				v11=0x80
		
		
		v24 = v1c+2
		v10=0
		while(v10<=v24 and len(dat2) < min_info):
			v2c=v4b[(v0c+v10)&0x1FFF]
			dat2 += v2c
			v4b[v34]=chr(ord(v2c) & 0xff)
			v34=(v34+1) & 0x1FFF
			v10 += 1
	
	# raplay info
	date = dat2[0x58:0x58+5]
	name = dat2[0x5e:0x5e+8]
	char = ord(dat2[0x56])
	rank = ord(dat2[0x57])
	myver= dat2[0xe0:0xe0+5] # '0100a' etc
	myver = myver[0:2] + '.' + myver[2:]
	if myver[0] == '0':
		myver = myver[1:]
	score = struct.unpack("L", dat2[0x6c:0x6c+4])[0] * 10
	drop = struct.unpack("f", dat2[0xcc:0xcc+4])[0]

	# [date, player, char, score, rank, version, drop]
	retArray[0] = trimNull(date)
	retArray[1] = trimNull(name)
	chars = ("ReimuA", "ReimuB", "MarisaA", "MarisaB", "SakuyaA", "SakuyaB")
	retArray[2] = chars[char]
	retArray[3] = str(score)
	levels = ("Easy","Normal","Hard","Lunatic","Extra","Phantasm")
	retArray[4] = levels[rank]
	retArray[5] = str(myver)
	retArray[6] = "%5.3f" % drop
	return retArray

def pow(v1, v2):
	return v1 ** v2

def trimNull(s):
	while(True):
		if(len(s) > 0):
			if(s[-1] == "\x00"):
				s = s[:-1]
			else:
				break
		else:
			break
	return s
# end
