def Float(parent): size = parent['size'].value if size == 4: return Float32(parent, 'float') elif size == 8: return Float64(parent, 'double') else: return RawBytes(parent, 'INVALID_FLOAT', size)
def parseBinaryComplex(parent): yield Float64(parent, "real") yield Float64(parent, "complex")
def parseBinaryFloat(parent): yield Float64(parent, "value")
def parseDate(parent): yield Float64(parent, "timestamp_microsec") yield UInt16(parent, "timestamp_sec")
def parseDouble(parent): yield Float64(parent, "value")
def createFields(self): yield Enum(Bits(self, "marker_type", 4), {0: "Simple", 1: "Int", 2: "Real", 3: "Date", 4: "Data", 5: "ASCII String", 6: "UTF-16-BE String", 8: "UID", 10: "Array", 13: "Dict", }) markertype = self['marker_type'].value if markertype == 0: # Simple (Null) yield Enum(Bits(self, "value", 4), {0: "Null", 8: "False", 9: "True", 15: "Fill Byte", }) if self['value'].display == "False": self.xml = lambda prefix: prefix + "<false/>" elif self['value'].display == "True": self.xml = lambda prefix: prefix + "<true/>" else: self.xml = lambda prefix: prefix + "" elif markertype == 1: # Int yield Bits(self, "size", 4, "log2 of number of bytes") size = self['size'].value # 8-bit (size=0), 16-bit (size=1) and 32-bit (size=2) numbers are unsigned # 64-bit (size=3) numbers are signed yield GenericInteger(self, "value", (size >= 3), (2**size) * 8) self.xml = lambda prefix: prefix + \ "<integer>%s</integer>" % self['value'].value elif markertype == 2: # Real yield Bits(self, "size", 4, "log2 of number of bytes") if self['size'].value == 2: # 2**2 = 4 byte float yield Float32(self, "value") elif self['size'].value == 3: # 2**3 = 8 byte float yield Float64(self, "value") else: # FIXME: What is the format of the real? yield Bits(self, "value", (2**self['size'].value) * 8) self.xml = lambda prefix: prefix + \ "<real>%s</real>" % self['value'].value elif markertype == 3: # Date yield Bits(self, "extra", 4, "Extra value, should be 3") # Use a heuristic to determine which epoch to use def cvt_time(v): v = timedelta(seconds=v) epoch2001 = datetime(2001, 1, 1) epoch1970 = datetime(1970, 1, 1) if (epoch2001 + v - datetime.today()).days > 5 * 365: return epoch1970 + v return epoch2001 + v yield displayHandler(Float64(self, "value"), lambda x: humanDatetime(cvt_time(x))) self.xml = lambda prefix: prefix + \ "<date>%sZ</date>" % ( cvt_time(self['value'].value).isoformat()) elif markertype == 4: # Data yield BPListSize(self, "size") if self['size'].value: yield Bytes(self, "value", self['size'].value) self.xml = lambda prefix: prefix + \ "<data>\n%s\n%s</data>" % ( self['value'].value.encode('base64').strip(), prefix) else: self.xml = lambda prefix: prefix + '<data></data>' elif markertype == 5: # ASCII String yield BPListSize(self, "size") if self['size'].value: yield String(self, "value", self['size'].value, charset="ASCII") self.xml = lambda prefix: prefix + \ "<string>%s</string>" % (self['value'].value.replace( '&', '&').encode('iso-8859-1')) else: self.xml = lambda prefix: prefix + '<string></string>' elif markertype == 6: # UTF-16-BE String yield BPListSize(self, "size") if self['size'].value: yield String(self, "value", self['size'].value * 2, charset="UTF-16-BE") self.xml = lambda prefix: prefix + \ "<string>%s</string>" % ( self['value'].value.replace('&', '&').encode('utf-8')) else: self.xml = lambda prefix: prefix + '<string></string>' elif markertype == 8: # UID yield Bits(self, "size", 4, "Number of bytes minus 1") yield GenericInteger(self, "value", False, (self['size'].value + 1) * 8) self.xml = lambda prefix: prefix + "" # no equivalent? elif markertype == 10: # Array yield BPListSize(self, "size") size = self['size'].value if size: yield BPListArray(self, "value", size) self.xml = lambda prefix: self['value'].createXML(prefix) elif markertype == 13: # Dict yield BPListSize(self, "size") yield BPListDict(self, "value", self['size'].value) self.xml = lambda prefix: self['value'].createXML(prefix) else: yield Bits(self, "value", 4) self.xml = lambda prefix: ''