Created
March 13, 2014 06:06
-
-
Save admalledd/9522639 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'''Read SValue object streams and convert to XML''' | |
import struct | |
class SValueType: | |
Array =1 | |
Object =2 | |
Boolean =3 | |
Double =4 | |
Float =5 | |
Integer =6 | |
String =7 | |
IntegerArray =8 | |
Vector2 =9 | |
Null =0 | |
class Vector2(object): | |
"""docstring for Vector2""" | |
def __init__(self, x,y): | |
self.x=x | |
self.y=y | |
class SValue(object): | |
def __init__(self,val,typ): | |
'''called from the classmethods, should never be called by hand! | |
SValues are a complex tree in memory, exportable as XML or .bin | |
All of the @staticmethod Read* methods advance the file object. | |
''' | |
self.val=val | |
self.type=typ | |
@staticmethod | |
def ReadInt32(f): | |
'''read 4 bytes and convert to an int (from int32)''' | |
i=struct.unpack("<i",f.read(4))[0] | |
#print "reading int of size '%s'"%i | |
return i | |
@staticmethod | |
def ReadSingle(f): | |
'''read 4 byte float''' | |
i = struct.unpack("<f",f.read(4))[0] | |
return i | |
@staticmethod | |
def ReadDouble(f): | |
'''read 8 byte float (double)''' | |
i = struct.unpack("<d",f.read(8))[0] | |
return i | |
@staticmethod | |
def ReadBoolean(f): | |
'''read one byte, true if non-zero''' | |
i = f.read(1) | |
return i!='\x00' | |
@staticmethod | |
def ReadString(f): | |
'''Read a LEB128 string''' | |
strlen=SValue.leb128_decode(f) | |
#print "reading string of len(%s)"%strlen | |
s=f.read(strlen) | |
#print "string: %r"%s | |
return s | |
@staticmethod | |
def leb128_decode(f): | |
'decode LEB128 numbers, see http://en.wikipedia.org/wiki/LEB128' | |
result = 0 | |
shift = 0 | |
size = 0 | |
buff = f.read(1) | |
while True: | |
b = ord(buff[size:size+1]) | |
size += 1 | |
result |= (b & 0x7f) << shift | |
if b & 0x80 == 0: | |
break | |
shift += 7 | |
print "looped in leb128_decode" | |
buff=buff+f.read(1) | |
#print "LEB128 buffer: '0x%s'"%buff.encode('hex') | |
return result#, size | |
@classmethod | |
def FromArray(cls,val): | |
return cls(val, SValueType.Array) | |
@classmethod | |
def FromObject(cls,val): | |
return cls(val, SValueType.Object) | |
@classmethod | |
def FromBoolean(cls,val): | |
return cls(val, SValueType.Boolean) | |
@classmethod | |
def FromDouble(cls,val): | |
return cls(val, SValueType.Double) | |
@classmethod | |
def FromFloat(cls,val): | |
return cls(val, SValueType.Float) | |
@classmethod | |
def FromInteger(cls,val): | |
return cls(val, SValueType.Integer) | |
@classmethod | |
def FromString(cls,val): | |
return cls(val, SValueType.String) | |
@classmethod | |
def FromIntegerArray(cls,val): | |
return cls(val, SValueType.IntegerArray) | |
@classmethod | |
def FromVector2(cls,val): | |
return cls(val, SValueType.Vector2) | |
@classmethod | |
def LoadStream(cls,f): | |
b=struct.unpack('<b',f.read(1))[0]#read one and switch! | |
#print "loading Stream with type '%s'"%(hex(b)) | |
if b == SValueType.Array: | |
arr=[] | |
arr_len = cls.ReadInt32(f) | |
for i in range(arr_len): | |
arr.append(cls.LoadStream(f)) | |
return cls.FromArray(arr) | |
elif b == SValueType.Object: | |
val={} | |
for i in range(cls.ReadInt32(f)): | |
key=cls.ReadString(f) | |
val[key]=cls.LoadStream(f) | |
return SValue.FromObject(val) | |
elif b == SValueType.Boolean: | |
return SValue.FromBoolean(cls.ReadBoolean(f)) | |
elif b == SValueType.Double: | |
return SValue.FromDouble(cls.ReadDouble(f)) | |
elif b == SValueType.Float: | |
return SValue.FromFloat(cls.ReadSingle(f)) | |
elif b == SValueType.Integer: | |
return SValue.FromInteger(cls.ReadInt32(f)) | |
elif b == SValueType.String: | |
return SValue.FromString(cls.ReadString(f)) | |
elif b == SValueType.IntegerArray: | |
arr=[] | |
for i in range(cls.ReadInt32(f)): | |
arr.append(cls.ReadInt32(f)) | |
return SValue.FromIntegerArray(arr) | |
elif b == SValueType.Vector2: | |
return SValue.FromVector2(Vector2(cls.ReadSingle(f), cls.ReadSingle(f))); | |
else: | |
#catches case b==0 and errors | |
return SValue(None, SValueType.Null) | |
def SaveXML(self,f,indent='',name=None,compact=False): | |
'''save to XML, recurses into itself!''' | |
def fmt_name(t): | |
'''formats xml type "t" with name if needed''' | |
if name: | |
return '<%s name="%s">'%(t,name) | |
else: | |
return '<%s>'%t | |
if not compact: | |
f.write(indent) | |
if self.type == SValueType.Array: | |
f.write(fmt_name('array')) | |
compact1=compact | |
if len(self.val) <10 and not compact1: | |
compact1=True | |
for val in self.val: | |
if val.type in (SValueType.Object,SValueType.IntegerArray,SValueType.Array): | |
compact1=False | |
if not compact1: | |
f.write('\r\n') | |
for val in self.val: | |
val.SaveXML(f,indent+'\t',None,compact1) | |
if not compact: | |
f.write(indent) | |
f.write('</array>') | |
elif self.type == SValueType.Object: | |
f.write(fmt_name('dictionary')) | |
if not compact: | |
f.write('\r\n') | |
for key,val in self.val.iteritems(): | |
val.SaveXML(f,indent+'\t',key,compact) | |
if not compact: | |
f.write('\r\n'+indent) | |
f.write('</dictionary>') | |
elif self.type == SValueType.Boolean: | |
f.write(fmt_name('bool')) | |
f.write(repr(self.val)) | |
f.write('</bool>') | |
elif self.type == SValueType.Double: | |
f.write(fmt_name('double')) | |
f.write(repr(self.val))#TODO::: CHECK | |
f.write('</double>') | |
elif self.type == SValueType.Float: | |
f.write(fmt_name('float')) | |
f.write(repr(self.val))#TODO::: CHECK | |
f.write('</float>') | |
elif self.type == SValueType.Integer: | |
f.write(fmt_name('int')) | |
f.write(str(self.val))#TODO::: CHECK | |
f.write('</int>') | |
elif self.type == SValueType.String: | |
f.write(fmt_name('string')) | |
f.write(str(self.val))#TODO::: CHECK | |
f.write('</string>') | |
elif self.type == SValueType.IntegerArray: | |
f.write(fmt_name('int-arr')) | |
self.sval=[] | |
for val in self.val: | |
self.sval.append(str(val)) | |
s=" ".join(self.val) | |
f.write(s) | |
f.write('</int-arr>') | |
elif self.type == SValueType.Vector2: | |
f.write(fmt_name('vec2')) | |
f.write(repr(self.val.x)+' '+repr(self.val.y))#TODO::: CHECK | |
f.write('</vec2>') | |
elif self.type == SValueType.Null: | |
if name: | |
f.write('<null name="%s"/>') | |
else: | |
f.write('<null/>') | |
else: | |
raise Exception("missing/bad encoding type!") | |
if compact: | |
return | |
else: | |
f.write('\r\n') | |
if __name__ == '__main__': | |
sv= SValue.LoadStream(open("survival.hwm.unpacked/levels/level_1.xml.bin")) | |
sv.SaveXML(open("survival.hwm.unpacked/levels/level_1.xml",'wb')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment