""" CCP Blue file parser. Author: Tristan Seligmann Creation date: 03 September 2006 """ from time import strftime, gmtime EPOCH_DIFF = 116444736000000000 from hachoir.field import Parser, ParserError, FieldSet, Link from hachoir.field import ( UInt8, UInt16, UInt32, UInt64, String, RawBytes, CString, Enum) from hachoir.endian import LITTLE_ENDIAN from hachoir.text_handler import timestampWin64 class FileTime(UInt64): def _getDisplay(self): seconds = (self.value - EPOCH_DIFF) * 1e-7 return strftime('%a, %d %b %Y %H:%M:%S %z', gmtime(seconds)) class CCPBlue(Parser): tags = { "file_ext": "blue", "mime": ("application/x-ccp-blue",), "min_size": 32, "description": "A CCP Blue file" } endian = LITTLE_ENDIAN def validate(self): return self.stream.readBytes(0, 5) == 'Blue\0' def createFields(self): yield String(self, 'header', 9, 'Header ("Blue\0...")', charset='ASCII') yield String(self, 'subsystem1', 10, 'XXX Subsystem', strip='\0', charset='ASCII') yield String(self, 'subsystem2', 24, 'XXX Subsystem', strip='\0', charset='ASCII') yield UInt16(self, 'xxx1', 'XXX Value') yield UInt32(self, 'filesize', 'File size') yield UInt64(self, 'filetime', 'File time', text_handler=timestampWin64) yield RawBytes(self, 'xxx2', 15, 'XXX Value') yield UInt32(self, 'some_offset_1', 'Some offset (1)') yield UInt32(self, 'count_stringtable', 'Number of stringtable entries') yield UInt32(self, 'xxx3', 'XXX Value') yield UInt32(self, 'count_descriptors', 'XXX Value') yield UInt32(self, 'raw_data_count', 'Raw data count') yield UInt32(self, 'xxx4', 'XXX Value') yield UInt32(self, 'xxx5', 'XXX Value') yield RawBytes(self, 'raw_data_1', self['some_offset_1'].value, 'XXX Data') for n in xrange(self['count_descriptors'].value): yield Descriptor(self, 'descriptor[]') for n in xrange(self['raw_data_count'].value): yield UInt32(self, 'raw_data_2[]', 'XXX Data') #padding = self.seekByte(10428, 'raw_data_3') #if padding: # yield padding for n in xrange(self['count_stringtable'].value): yield UInt32(self, 'len_string[]', 'String length') yield String(self, 'string[]', self['len_string[%d]' % (n,)].value, 'String') # Read rest of the file (if any) # TODO: You may remove this code if self.current_size < self._size: yield self.seekBit(self._size, "end") class Descriptor(FieldSet): def createFields(self): class Name(Link): def _createValue(self): index = self.parent['index'].value value = self['/string[%d]' % (index,)] return value def _getDisplay(self): return self.value.value yield UInt16(self, 'index', 'String table index') yield Name(self, 'name') yield Enum(UInt8(self, 'type', 'Descriptor type'), typeNames) dtype = dataTypes[int(self['type'].value)] if dtype is not None: yield dtype(self, 'data') class Type7Data(FieldSet): def createFields(self): yield RawBytes(self, 'data', 3, 'XXX Data') class StructData(FieldSet): def createFields(self): yield RawBytes(self, 'padding', 1, 'Padding') yield UInt32(self, 'count_instances', 'Number of instances') yield UInt32(self, 'num_children', 'Number of child descriptors') for n in xrange(self['num_children'].value): yield Descriptor(self, 'child[]') class Type29Data(FieldSet): def createFields(self): yield RawBytes(self, 'data', 9, 'XXX Data') class Type58Data(FieldSet): def createFields(self): yield RawBytes(self, 'padding', 1, 'Padding') yield UInt32(self, 'count_instances', 'Number of instances') yield UInt32(self, 'num_children', 'Number of child descriptors') for n in xrange(self['num_children'].value): yield Descriptor(self, 'child[]') class Type112Data(FieldSet): def createFields(self): yield RawBytes(self, 'data', 9, 'XXX Data') dataTypes = { 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: Type7Data, 8: None, 9: StructData, 12: None, 29: Type29Data, 58: Type58Data, 112: Type112Data, } typeNames = { 1: 'int', 2: 'float', 4: 'bool', 5: 'reference', 6: 'None(?)', 8: 'str', 9: 'struct', 12: 'array', } class StringTable(FieldSet): def __init__(self, parent, name, count): self.count = count def createFields(self): for n in xrange(self.count): yield UInt32(self, 'len_string[]', 'String length') yield String(self, 'string[]', self['len_string[%d]' % (n,)].value, 'String')