buildframework/helium/tools/iad/iadinfo.py
author raptorbot <raptorbot@systemstesthead.symbian.intra>
Fri, 18 Dec 2009 19:57:42 +0000
branchwip
changeset 117 ecf683438dc6
parent 1 be27ed110b50
permissions -rw-r--r--
Don't mess around with EPOCROOT until actually entering raptor so we know what the original was Put the original epocroot back on the front of the whatcomp output. This allows what output to be either relative or absolute depending on what your epocroot is.

#============================================================================ 
#Name        : iadinfo.py 
#Part of     : Helium 

#Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
#All rights reserved.
#This component and the accompanying materials are made available
#under the terms of the License "Eclipse Public License v1.0"
#which accompanies this distribution, and is available
#at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
#Initial Contributors:
#Nokia Corporation - initial contribution.
#
#Contributors:
#
#Description:
#===============================================================================

import optparse
import sys, os
import struct
import zlib
import pdb
    
PyASN1Availabe = True

try :
    from pyasn1.codec.der import decoder
    from pyasn1.type import univ, base
except :
    PyASN1Availabe = False

def _findItem(item, itemParent, index, objectIdentifier) :
    if isinstance(item, base.AbstractSimpleAsn1Item) :
        if item == objectIdentifier :
            return itemParent[index + 1]
    else:
        for i in range(len(item)) :
            found = _findItem(item[i], item, i, objectIdentifier)
            if found: 
                return found

def findItem(decodedCert, objectIdentifier) :
    return _findItem(decodedCert, None, 0, objectIdentifier)


class CertificateOrganization :
    def __init__(self) :
        pass
    
    def parse(self, decodedCert) :
        self.commonName = findItem(decodedCert, (2, 5, 4, 3))
        self.countryCode = findItem(decodedCert, (2, 5, 4, 6))
        self.locality = findItem(decodedCert, (2, 5, 4, 7))
        self.state = findItem(decodedCert, (2, 5, 4, 8))
        self.street = findItem(decodedCert, (2, 5, 4, 9))
        self.organization = findItem(decodedCert, (2, 5, 4, 10))

    def readableStr(self) :
        buf = ""
        if self.commonName :
            buf += self.commonName.prettyPrint() + "\n"
        if self.countryCode :
            buf += self.countryCode.prettyPrint() + "\n"
        if self.locality :
            buf += self.locality.prettyPrint() + "\n"
        if self.state :
            buf += self.state.prettyPrint() + "\n"
        if self.street :
            buf += self.street.prettyPrint() + "\n"
        if self.organization :
            buf += self.organization.prettyPrint()
        return buf

class CertificateInfo :
    def __init__(self) :
        pass
        
    def parse(self, decodedCert) :
        self.issuer = CertificateOrganization()
        self.issuer.parse(decodedCert[0][3])
        
        self.signer = CertificateOrganization()
        self.signer.parse(decodedCert[0][5])
        
    def readableStr(self) :
        buf = "Signer:\n      " + "\n      ".join(self.signer.readableStr().split('\n')) + "\n"
        buf += "Issuer:\n      " + "\n      ".join(self.issuer.readableStr().split('\n')) + "\n"
        return buf
            

class SISFileHeader :
    def __init__(self) :
        self.uid1 = 0
        self.uid2 = 0
        self.uid3 = 0
        self.uidChecksum = 0

class SISField :
    def __init__(self) :
        self.type = 0
        self.length = None
        self.subFields = []
        
    def readFieldLength(self, fileReader) :
        length = fileReader.readBytesAsUint(4)
        if length & 0x80000000 > 0 :
            length = length << 32
            length |= fileReader.readBytesAsUint(4)
        return length
        
    def findField(self, fieldType, startIndex=0) :
        result = None
        index = startIndex
        
        for field in self.subFields[startIndex:] :
            if field.type == fieldType :
                result = field
                break
            ++ index
        return (result, index)
        
    def readableStr(self) :
        return ""
    
    def traverse(self, handler, depth=0) :
        handler.handleField(self, depth)
        for field in self.subFields :
            field.traverse(handler, depth + 1)
        
class SISUnsupportedField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fileReader.readPlainBytes(self.length)

class SISStringField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.data = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        buf = fileReader.readPlainBytes(self.length)
        self.data = u""
        while len(buf) > 0 :
            temp = buf[:2]
            buf = buf[2:]
            self.data += unichr(ord(temp[0]) | ord(temp[1]) << 8)
        
    def readableStr(self) :
        return self.data
        
class SISArrayField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        type = fileReader.readBytesAsInt(4)
        l = self.length - 4
        while l > 0 :
            field = SISFieldTypes[type]()
            field.type = type
            field.initFromFile(fileReader)
            self.subFields.append(field)
            
            l -= field.length + 4 # field length + the length field
            padding = fileReader.skipPadding()
            l -= padding

class SISCompressedField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.algorithm = None
        self.uncompressedDataSize = None
        self.data = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.algorithm = fileReader.readBytesAsUint(4)
        self.uncompressedDataSize = fileReader.readBytesAsUint(8)
        data = fileReader.readPlainBytes(self.length - 4 - 8)
        if self.algorithm == 0 :
            self.data = data
        elif self.algorithm == 1 :
            self.data = zlib.decompress(data)
            
class SISVersionField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.version = (- 1, - 1, - 1)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        major = fileReader.readBytesAsInt(4)
        minor = fileReader.readBytesAsInt(4)
        build = fileReader.readBytesAsInt(4)
        self.version = (major, minor, build)
        
    def readableStr(self) :
        return str(self.version)
    
class SISVersionRangeField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.fromVersion = None
        self.toVersion = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.fromVersion = fieldParser.parseField(fileReader)
        if self.length - fieldParser.lastReadBytes > 0  :
            self.toVersion = fieldParser.parseField(fileReader)
    
class SISDateField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.year = None
        self.month = None
        self.day = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.year = fileReader.readBytesAsUint(2)
        self.month = fileReader.readBytesAsUint(1)
        self.day = fileReader.readBytesAsUint(1)
    
    def readableStr(self) :
        return str(self.year) + "." + str(self.month) + "." + str(self.day)
    
class SISTimeField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.hours = None
        self.minutes = None
        self.seconds = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.hours = fileReader.readBytesAsUint(1)
        self.minutes = fileReader.readBytesAsUint(1)
        self.seconds = fileReader.readBytesAsUint(1)
    
    def readableStr(self) :
        return str(self.hours) + ":" + str(self.minutes) + ":" + str(self.seconds)
    
class SISDateTimeField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.date = None
        self.time = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.date = fieldParser.parseField(fileReader)
        self.time = fieldParser.parseField(fileReader)
    
class SISUidField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.uid = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.uid = fileReader.readBytesAsUint(4)
        
    def readableStr(self) :
        return hex(self.uid)
    
class SISLanguageField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.language = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.language = fileReader.readBytesAsUint(4)
        
    def readableStr(self) :
        return str(self.language)
    
class SISContentsField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        field = fieldParser.parseField(fileReader)
        while field :
            if field.type == 3 : # compressed<conroller>
                bufferReader = SISBufferReader(field.data)
                field = fieldParser.parseField(bufferReader)
            self.subFields.append(field)
            field = fieldParser.parseField(fileReader)

class SISControllerField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        bufferReader = SISBufferReader(fileReader.readPlainBytes(self.length))
        field = fieldParser.parseField(bufferReader)
        while field :
            self.subFields.append(field)
            field = fieldParser.parseField(bufferReader)

class SISInfoField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.installType = None
        self.installFlags = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # UID
        self.subFields.append(fieldParser.parseField(fileReader)) # Vendor name unique
        self.subFields.append(fieldParser.parseField(fileReader)) # names
        self.subFields.append(fieldParser.parseField(fileReader)) # vendor names
        self.subFields.append(fieldParser.parseField(fileReader)) # version
        self.subFields.append(fieldParser.parseField(fileReader)) # creation time
        self.installType = fileReader.readBytesAsUint(1)
        self.installFlags = fileReader.readBytesAsUint(1) 
            
class SISSupportedLanguagesField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # languages
        
class SISSupportedOptionsField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # options
            
class SISPrerequisitiesField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # target devices
        self.subFields.append(fieldParser.parseField(fileReader)) # dependencies
        
        
class SISDependencyField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # UID
        field = fieldParser.parseField(fileReader)
        # Version range field is optional
        if field.type == VersionRangeField :
            self.subFields.append(field) # version range
            self.subFields.append(fieldParser.parseField(fileReader)) # dependency names
        else :
            self.subFields.append(field) # dependency names
    
class SISPropertiesField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # properties
    
class SISPropertyField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.key = None
        self.value = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.key = fileReader.readBytesAsInt(4)
        self.value = fileReader.readBytesAsInt(4)
    
# There is a type for this field, but there is no definition of the field contents
class SISSignaturesField(SISUnsupportedField) :
    pass
    
class SISCertificateChainField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # certificate data
    
class SISLogoField(SISField) :
    def __init__(self) :
        SISField.__init__(self)

    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # logo file
    
class SISFileDescriptionField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.operation = None
        self.operationOptions = None
        self.compressedLength = None
        self.uncompressedLength = None
        self.fileIndex = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        
        self.subFields.append(fieldParser.parseField(fileReader))
        self.subFields.append(fieldParser.parseField(fileReader))
        field = fieldParser.parseField(fileReader)
        self.subFields.append(field)
        if field.type == 41 : # read field was capabilities ==> there is one more field left
            self.subFields.append(fieldParser.parseField(fileReader))
        
        self.operation = fileReader.readBytesAsUint(4)
        self.operationOptions = fileReader.readBytesAsUint(4)
        self.compressedLength = fileReader.readBytesAsUint(8)
        self.uncompressedLength = fileReader.readBytesAsUint(8)
        self.fileIndex = fileReader.readBytesAsUint(4)
        
    def readableStr(self) :
        return "index: " + str(self.fileIndex)
    
class SISHashField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.algorithm = None

    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.algorithm = fileReader.readBytesAsUint(4)
        self.subFields.append(fieldParser.parseField(fileReader)) # logo file
    
class SISIfField(SISField) :
    def __init__(self) :
        SISField.__init__(self)

    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # expression
        self.subFields.append(fieldParser.parseField(fileReader)) # install block
        self.subFields.append(fieldParser.parseField(fileReader)) # else ifs

class SISElseIfField(SISField) :
    def __init__(self) :
        SISField.__init__(self)

    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # expression
        self.subFields.append(fieldParser.parseField(fileReader)) # install block
    
class SISInstallBlockField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.files = None
        self.embeddedSISFiles = None
        self.ifBlocks = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader))
        self.subFields.append(fieldParser.parseField(fileReader))
        self.subFields.append(fieldParser.parseField(fileReader))

class SISExpressionField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.operator = None
        self.integerValue = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.operator = fileReader.readBytesAsUint(4)
        self.integerValue = fileReader.readBytesAsInt(4)
        
        if self.operator == 10 or self.operator == 13 :
            self.subFields.append(fieldParser.parseField(fileReader))
        if self.operator == 1 or self.operator == 2 or self.operator == 3 or self.operator == 4 or self.operator == 5 or self.operator == 6 or self.operator == 7 or self.operator == 8 or self.operator == 11 or self.operator == 12 :
            self.subFields.append(fieldParser.parseField(fileReader))
        if not (self.operator == 13 or self.operator == 14 or self.operator == 15 or self.operator == 16 or self.operator == 10) :
            self.subFields.append(fieldParser.parseField(fileReader))
        
class SISDataField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # data units
    
class SISDataUnitField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # file data
    
class SISFileDataField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # raw file data
    
class SISSupportedOptionField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # names
    
class SISControllerChecksumField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.checksum = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.checksum = fileReader.readBytesAsUint(2)
    
class SISDataChecksumField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.checksum = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.checksum = fileReader.readBytesAsUint(2)
    
class SISSignatureField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # signature algorithm
        self.subFields.append(fieldParser.parseField(fileReader)) # signature data
    
class SISBlobField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.data = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.data = fileReader.readPlainBytes(self.length)
    
class SISSignatureAlgorithmField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # algorithm identifier
    
class SISSignatureCertificateChainField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        fieldParser = SISFieldParser()
        self.subFields.append(fieldParser.parseField(fileReader)) # signatures
        self.subFields.append(fieldParser.parseField(fileReader)) # certificate chain
    
class SISDataIndexField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.dataIndex = None
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.dataIndex = fileReader.readBytesAsUint(4)

class SISCapabilitiesField(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.capabilities = 0
        self.readableCaps = []
        
    def initFromFile(self, fileReader) :
        self.length = self.readFieldLength(fileReader)
        self.capabilities = fileReader.readBytesAsUint(self.length)
        
        for i in range(20) :
            if (self.capabilities >> i) & 0x01 :
                self.readableCaps.append(CapabilityNames[i])
                
    def readableStr(self) :
        return " ".join(self.readableCaps)
    
SISFieldTypes = { 
    1 : SISStringField,
    2 : SISArrayField,
    3 : SISCompressedField,
    4 : SISVersionField,
    5 : SISVersionRangeField,
    6 : SISDateField,
    7 : SISTimeField,
    8 : SISDateTimeField,
    9 : SISUidField,
    10 : SISUnsupportedField,
    11 : SISLanguageField,
    12 : SISContentsField,
    13 : SISControllerField,
    14 : SISInfoField,
    15 : SISSupportedLanguagesField,
    16 : SISSupportedOptionsField,
    17 : SISPrerequisitiesField,
    18 : SISDependencyField,
    19 : SISPropertiesField,
    20 : SISPropertyField,
    21 : SISSignaturesField,
    22 : SISCertificateChainField,
    23 : SISLogoField,
    24 : SISFileDescriptionField,
    25 : SISHashField,
    26 : SISIfField,
    27 : SISElseIfField,
    28 : SISInstallBlockField,
    29 : SISExpressionField,
    30 : SISDataField,
    31 : SISDataUnitField,
    32 : SISFileDataField,
    33 : SISSupportedOptionField,
    34 : SISControllerChecksumField,
    35 : SISDataChecksumField,
    36 : SISSignatureField,
    37 : SISBlobField,
    38 : SISSignatureAlgorithmField,
    39 : SISSignatureCertificateChainField,
    40 : SISDataIndexField,
    41 : SISCapabilitiesField
    }

[StringField,
 ArrayField,
 CompressedField,
 VersionField,
 VersionRangeField,
 DateField,
 TimeField,
 DateTimeField,
 UidField,
 UnusedField,
 LanguageField,
 ContentsField,
 ControllerField,
 InfoField,
 SupportedLanguagesField,
 SupportedOptionsField,
 PrerequisitiesField,
 DependencyField,
 PropertiesField,
 PropertyField,
 SignaturesField,
 CertificateChainField,
 LogoField,
 FileDescriptionField,
 HashField,
 IfField,
 ElseIfField,
 InstallBlockField,
 ExpressionField,
 DataField,
 DataUnitField,
 FileDataField,
 SupportedOptionField,
 ControllerChecksumField,
 DataChecksumField,
 SignatureField,
 BlobField,
 SignatureAlgorithmField,
 SignatureCertificateChainField,
 DataIndexField,
 CapabilitiesField] = range(1, 42)
     
FieldNames = {
 0 : "ROOT",
 StringField : "StringField",
 ArrayField : "ArrayField",
 CompressedField : "CompressedField",
 VersionField : "VersionField",
 VersionRangeField : "VersionRangeField",
 DateField : "DateField",
 TimeField : "TimeField",
 DateTimeField : "DateTimeField",
 UidField : "UidField",
 UnusedField : "UnusedField",
 LanguageField : "LanguageField",
 ContentsField : "ContentsField",
 ControllerField : "ControllerField",
 InfoField : "InfoField",
 SupportedLanguagesField : "SupportedLanguagesField",
 SupportedOptionsField : "SupportedOptionsField",
 PrerequisitiesField : "PrerequisitiesField",
 DependencyField : "DependencyField",
 PropertiesField : "PropertiesField",
 PropertyField : "PropertyField",
 SignaturesField : "SignaturesField",
 CertificateChainField : "CertificateChainField",
 LogoField : "LogoField",
 FileDescriptionField : "FileDescriptionField",
 HashField : "HashField",
 IfField : "IfField",
 ElseIfField : "ElseIfField",
 InstallBlockField : "InstallBlockField",
 ExpressionField : "ExpressionField",
 DataField : "DataField",
 DataUnitField : "DataUnitField",
 FileDataField : "FileDataField",
 SupportedOptionField : "SupportedOptionField",
 ControllerChecksumField : "ControllerChecksumField",
 DataChecksumField : "DataChecksumField",
 SignatureField : "SignatureField",
 BlobField : "BlobField",
 SignatureAlgorithmField : "SignatureAlgorithmField",
 SignatureCertificateChainField : "SignatureCertificateChainField",
 DataIndexField : "DataIndexField",
 CapabilitiesField : "CapabilitiesField"
}
     
CapabilityNames = {
    0 : "TCB",
    1 : "CommDD",
    2 : "PowerMgmt",
    3 : "MultimediaDD",
    4 : "ReadDeviceData",
    5 : "WriteDeviceData",
    6 : "DRM",
    7 : "TrustedUI",
    8 : "ProtServ",
    9 : "DiskAdmin",
    10 : "NetworkControl",
    11 : "AllFiles",
    12 : "SwEvent",
    13 : "NetworkServices",
    14 : "LocalServices",
    15 : "ReadUserData",
    16 : "WriteUserData",
    17 : "Location",
    18 : "SurroundingsDD",
    19 : "UserEnvironment"
    }

InstallTypes = {
    0: "SA",
    1: "SP",
    2: "PU",
    3: "PA",
    4: "PP"
    }
    
class SISReader :
    def __init__(self) :
        self.bytesRead = 0
        
    def readUnsignedBytes(self, numBytes) :
        buf = self.readPlainBytes(numBytes)
        if len(buf) < numBytes :
            return []
            
        format = ""
        for i in range(numBytes) :
            format += "B"
        return struct.unpack(format, buf)
    
    def readSignedBytes(self, numBytes) :
        buf = self.readPlainBytes(numBytes)
        if len(buf) < numBytes :
            return []
            
        format = ""
        for i in range(numBytes) :
            format += "b"
        return struct.unpack(format, buf)
        
    def readBytesAsUint(self, numBytes) :
        result = 0
        bytes = self.readUnsignedBytes(numBytes)
        if len(bytes) == numBytes :
            for i in range(numBytes) :
                result |= bytes[i] << (i * 8)
        
        return result
        
    def readBytesAsInt(self, numBytes) :
        result = 0
        bytes = self.readSignedBytes(numBytes)
        if len(bytes) == numBytes :
            for i in range(numBytes) :
                result |= bytes[i] << (i * 8)
        
        return result
        
    def skipPadding(self) :
        result = 0
        if self.bytesRead % 4 != 0 :
            paddingLength = 4 - self.bytesRead % 4
            self.readPlainBytes(paddingLength)
            result = paddingLength
            
        return result

    def readPlainBytes(self, numBytes) :
        pass

class SISFileReader(SISReader) : 
    def __init__(self, inStream) :
        SISReader.__init__(self)
        self.inStream = inStream
        self.eof = False
        self.bytesRead = 0

    def readPlainBytes(self, numBytes) :
        if self.eof :
            return ""
            
        if numBytes == 0 :
            return ""
            
        buf = ""
        buf = self.inStream.read(numBytes)
        if len(buf) < numBytes :
            self.eof = True
            return ""
            
        self.bytesRead += numBytes
        
        return buf

    def isEof(self) :
        return self.eof
        
class SISBufferReader(SISReader) :
    def __init__(self, buffer) :
        self.buffer = buffer
        self.bytesRead = 0
        
    def readPlainBytes(self, numBytes) :
        if self.isEof() :
            return ""
            
        if numBytes == 0 :
            return ""
            
        result = self.buffer[self.bytesRead:self.bytesRead + numBytes]
            
        self.bytesRead += numBytes
        
        return result
            
    def isEof(self) :
        return self.bytesRead >= len(self.buffer)
        
class SISFieldParser :
    def __init__(self) :
        self.lastReadBytes = 0
        
    def parseField(self, fileReader) :
        """Reads the next field from the fileReader stream and returns it"""
        field = None
        self.lastReadBytes = 0
        type = fileReader.readBytesAsUint(4)
        self.lastReadBytes += 4
        if type != 0 :
            field = SISFieldTypes[type]()
            field.type = type
            field.initFromFile(fileReader)
            self.lastReadBytes += field.length + 4 # Field length + length field
            self.lastReadBytes += fileReader.skipPadding()
        return field

class SISInfo(SISField) :
    def __init__(self) :
        SISField.__init__(self)
        self.fin = None
        self.fileHeader = SISFileHeader()
        
    def parse(self, filename) :
        fin = open(filename, 'rb')
        fileReader = SISFileReader(fin)
        self.parseHeader(fileReader)
        self.parseSISFields(fileReader)
        
    def parseHeader(self, fileReader) :
        self.fileHeader.uid1 = fileReader.readBytesAsUint(4)
        self.fileHeader.uid2 = fileReader.readBytesAsUint(4)
        self.fileHeader.uid3 = fileReader.readBytesAsUint(4)
        self.fileHeader.uidChecksum = fileReader.readBytesAsUint(4)
        
    def parseSISFields(self, fileReader) :
        parser = SISFieldParser()
        while not fileReader.isEof() :
            self.subFields.append(parser.parseField(fileReader))

class Handler :
    def __init__(self) :
        self.files = []
        self.fileDatas = []
        self.signatureCertificateChains = []
        
    def handleField(self, field, depth) :
        if field.type == FileDescriptionField :
            self.files.append(field)
        elif field.type == FileDataField :
            self.fileDatas.append(field)
        elif field.type == SignatureCertificateChainField  :
            self.signatureCertificateChains.append(field)

    def execute(self, options) :
        for f in self.files :
            if options.info :
                buf = "   " + f.findField(StringField)[0].readableStr()
                caps = f.findField(CapabilitiesField)[0]
                if caps :
                    buf += " [" + " ".join(f.findField(CapabilitiesField)[0].readableCaps) + "]"
                print buf
            if options.extract :
                parts = f.findField(StringField)[0].readableStr().split("\\")
                if len(parts[len(parts) - 1]) > 0 :
                    path = os.path.abspath(options.extract)
                    path += os.sep + os.sep.join(parts[1: - 1])
                    if not os.path.exists(path) :
                        os.makedirs(path)
                    newFile = file(path + os.sep + parts[len(parts) - 1], "wb")
                    newFile.write(self.fileDatas[f.fileIndex].findField(CompressedField)[0].data)
                    newFile.close()
        for s in self.signatureCertificateChains :
            if options.certificate:
                buf = s.findField(CertificateChainField)[0].subFields[0].data
                print "Certificate chain:"
                i = 1
                while len(buf) > 0 :
                    print "   Certificate " + str(i) + ":"
                    i += 1
                    decoded = decoder.decode(buf)
                    cer = CertificateInfo()
                    cer.parse(decoded[0])
                    readableStr = cer.readableStr()
                    print "      " + "\n      ".join(readableStr.split('\n'))
                    buf = decoded[1]
            
class ContentPrinter :
    def __init__(self) :
        pass
        
    def handleField(self, field, depth) :
        buf = ""
        for i in range(depth) :
            buf += "  "
        buf += FieldNames[field.type] + " "
        if len(field.readableStr()) > 0 :
            buf += field.readableStr()
        print buf

class IADHandler :
    def __init__(self) :
        self.packageVersion = (0, 0, 0)
        self.packageUid = 0
        self.vendorName = ""
        self.packageNames = []
        self.packageNamesFields = []
        self.languages = []
        self.platformDependencies = []
        self.packageDependencies = []
        self.installType = 0
        self.installFlags = 0
        
    def handleDependency(self, field) :
        dep = [0, - 1, - 1, - 1, - 1, - 1, - 1]
        dep[0] = field.subFields[0].uid
        if field.subFields[1] and field.subFields[1].type == VersionRangeField :
            r = field.subFields[1]
            if r.fromVersion != None :
                dep[1] = r.fromVersion.version[0]
                dep[2] = r.fromVersion.version[1]
                dep[3] = r.fromVersion.version[2]
            if r.toVersion != None :
                dep[4] = r.toVersion.version[0]
                dep[5] = r.toVersion.version[1]
                dep[6] = r.toVersion.version[2]
        return dep
        
    def handleField(self, field, depth) :
        if field.type == InfoField :
            self.packageVersion = field.subFields[4].version
            self.packageVersionField = field.subFields[4]
            self.packageUid = field.subFields[0].uid
            self.packageUidField = field.subFields[0]
            self.vendorName = field.subFields[1].data
            self.vendorNameField = field.subFields[1]
            self.installType = field.installType
            self.installFlags = field.installFlags
            for name in field.subFields[2].subFields :
                self.packageNames.append(name.data)
        elif field.type == LanguageField :
            self.languages.append(field.language)
        elif field.type == PrerequisitiesField :
            for f in field.subFields[0].subFields :
                dependency = self.handleDependency(f)
                self.platformDependencies.append(dependency)
            for f in field.subFields[1].subFields :
                dependency = self.handleDependency(f)
                self.packageDependencies.append(dependency)
        
    def getInfo (self, fileName) :
        sisInfo = SISInfo()
        sisInfo.parse(fileName)
        handler = IADHandler()
        sisInfo.traverse(handler)
        info = "<sisinfo>\n" \
             + "  <uid>" + hex(handler.packageUid) + "</uid>\n" \
             + "  <vendor>" + handler.vendorName + "</vendor>\n" \
             + "  <version>" \
             + "<major>" + repr(handler.packageVersion[0]) + "</major>" \
             + "<minor>" + repr(handler.packageVersion[1]) + "</minor>" \
             + "<build>" + repr(handler.packageVersion[2]) + "</build>" \
             + "</version>\n" \
             + "  <type>" + InstallTypes[self.installType] + "</type>\n"
        for num, name in enumerate(handler.packageNames) :
            info += "  <name language='" + repr(handler.languages[num]) + "'>" + name + "</name>\n"
        for language in handler.languages :
            info += "  <language>" + repr(language) + "</language>\n"
        for platDep in handler.platformDependencies :
            info += "  <platform_dependency><uid>" + hex(platDep[0]) + "</uid>\n"
            info += "    <from>" \
                 + "<major>" + repr(platDep[1]) + "</major>" \
                 + "<minor>" + repr(platDep[2]) + "</minor>"
#           info += "<build>" + repr(platDep[3]) + "</build>"
            info += "</from>\n    <to>" \
                 + "<major>" + repr(platDep[4]) + "</major>" \
                 + "<minor>" + repr(platDep[5]) + "</minor>"
#           info += "<build>" + repr(platDep[6]) + "</build>"
            info += "</to>\n" \
             + "  </platform_dependency>\n"
        for packageDep in handler.packageDependencies :
            info += "  <package_dependency><uid>" + hex(packageDep[0]) + "</uid>\n"
            info += "    <from>" \
                 + "<major>" + repr(packageDep[1]) + "</major>" \
                 + "<minor>" + repr(packageDep[2]) + "</minor>"
#           info += "<build>" + repr(packageDep[3]) + "</build>"
            info += "</from>\n    <to>" \
                 + "<major>" + repr(packageDep[4]) + "</major>" \
                 + "<minor>" + repr(packageDep[5]) + "</minor>"
#           info += "<build>" + repr(packageDep[6]) + "</build>"
            info += "</to>\n" \
                 + "  </package_dependency>\n"
        info += "</sisinfo>\n"
        return info

if __name__ == "__main__" :
    handler = IADHandler()
    print (handler.getInfo (sys.argv[1]))