Esempio n. 1
0
class AXMLParser:

    CHUNK_AXML_FILE = 0x00080003
    CHUNK_RESOURCEIDS = 0x00080180
    CHUNK_XML_FIRST = 0x00100100
    CHUNK_XML_START_NAMESPACE = 0x00100100
    CHUNK_XML_END_NAMESPACE = 0x00100101
    CHUNK_XML_START_TAG = 0x00100102
    CHUNK_XML_END_TAG = 0x00100103
    CHUNK_XML_TEXT = 0x00100104
    CHUNK_XML_LAST = 0x00100104

    START_DOCUMENT = 0
    END_DOCUMENT = 1
    START_TAG = 2
    END_TAG = 3
    TEXT = 4

    ATTRIBUTE_IX_NAMESPACE_URI = 0
    ATTRIBUTE_IX_NAME = 1
    ATTRIBUTE_IX_VALUE_STRING = 2
    ATTRIBUTE_IX_VALUE_TYPE = 3
    ATTRIBUTE_IX_VALUE_DATA = 4
    ATTRIBUTE_LENGHT = 5

    TYPE_ATTRIBUTE = 2
    TYPE_DIMENSION = 5
    TYPE_FIRST_COLOR_INT = 28
    TYPE_FIRST_INT = 16
    TYPE_FLOAT = 4
    TYPE_FRACTION = 6
    TYPE_INT_BOOLEAN = 18
    TYPE_INT_COLOR_ARGB4 = 30
    TYPE_INT_COLOR_ARGB8 = 28
    TYPE_INT_COLOR_RGB4 = 31
    TYPE_INT_COLOR_RGB8 = 29
    TYPE_INT_DEC = 16
    TYPE_INT_HEX = 17
    TYPE_LAST_COLOR_INT = 31
    TYPE_LAST_INT = 31
    TYPE_NULL = 0
    TYPE_REFERENCE = 1
    TYPE_STRING = 3

    def __init__(self, raw_buff):
        self.reset()

        self.valid_axml = True
        self.buff = BuffHandle(raw_buff)

        axml_file = unpack('<L', self.buff.read(4))[0]

        if axml_file == self.CHUNK_AXML_FILE:
            self.buff.read(4)

            self.sb = StringBlock(self.buff)

            self.m_resourceIDs = []
            self.m_prefixuri = {}
            self.m_uriprefix = {}
            self.m_prefixuriL = []

            self.visited_ns = []
        else:
            self.valid_axml = False
            logging.warning("Not a valid xml file")

    def is_valid(self):
        return self.valid_axml

    def reset(self):
        self.m_event = -1
        self.m_lineNumber = -1
        self.m_name = -1
        self.m_namespaceUri = -1
        self.m_attributes = []
        self.m_idAttribute = -1
        self.m_classAttribute = -1
        self.m_styleAttribute = -1

    def next(self):
        self.doNext()
        return self.m_event

    def doNext(self):
        if self.m_event == self.END_DOCUMENT:
            return

        event = self.m_event

        self.reset()
        while True:
            chunkType = -1

            # Fake END_DOCUMENT event.
            if event == self.END_TAG:
                pass

            # START_DOCUMENT
            if event == self.START_DOCUMENT:
                chunkType = self.CHUNK_XML_START_TAG
            else:
                if self.buff.end():
                    self.m_event = self.END_DOCUMENT
                    break
                chunkType = unpack('<L', self.buff.read(4))[0]

            if chunkType == self.CHUNK_RESOURCEIDS:
                chunkSize = unpack('<L', self.buff.read(4))[0]
                # FIXME
                if chunkSize < 8 or chunkSize % 4 != 0:
                    logging.warning("Invalid chunk size")

                for i in range(0, chunkSize / 4 - 2):
                    self.m_resourceIDs.append(unpack('<L', self.buff.read(4))[0])

                continue

            # FIXME
            if chunkType < self.CHUNK_XML_FIRST or chunkType > self.CHUNK_XML_LAST:
                logging.warning("invalid chunk type")

            # Fake START_DOCUMENT event.
            if chunkType == self.CHUNK_XML_START_TAG and event == -1:
                self.m_event = self.START_DOCUMENT
                break

            self.buff.read(4)  # /*chunkSize*/
            lineNumber = unpack('<L', self.buff.read(4))[0]
            self.buff.read(4)  # 0xFFFFFFFF

            if chunkType == self.CHUNK_XML_START_NAMESPACE or chunkType == self.CHUNK_XML_END_NAMESPACE:
                if chunkType == self.CHUNK_XML_START_NAMESPACE:
                    prefix = unpack('<L', self.buff.read(4))[0]
                    uri = unpack('<L', self.buff.read(4))[0]

                    self.m_prefixuri[prefix] = uri
                    self.m_uriprefix[uri] = prefix
                    self.m_prefixuriL.append((prefix, uri))
                    self.ns = uri
                else:
                    self.ns = -1
                    self.buff.read(4)
                    self.buff.read(4)
                    (prefix, uri) = self.m_prefixuriL.pop()
                continue

            self.m_lineNumber = lineNumber

            if chunkType == self.CHUNK_XML_START_TAG:
                self.m_namespaceUri = unpack('<L', self.buff.read(4))[0]
                self.m_name = unpack('<L', self.buff.read(4))[0]

                # FIXME
                self.buff.read(4)  # flags

                attributeCount = unpack('<L', self.buff.read(4))[0]
                self.m_idAttribute = (attributeCount >> 16) - 1
                attributeCount = attributeCount & 0xFFFF
                self.m_classAttribute = unpack('<L', self.buff.read(4))[0]
                self.m_styleAttribute = (self.m_classAttribute >> 16) - 1

                self.m_classAttribute = (self.m_classAttribute & 0xFFFF) - 1

                for i in range(0, attributeCount * self.ATTRIBUTE_LENGHT):
                    self.m_attributes.append(unpack('<L', self.buff.read(4))[0])

                for i in range(self.ATTRIBUTE_IX_VALUE_TYPE, len(self.m_attributes), self.ATTRIBUTE_LENGHT):
                    self.m_attributes[i] = self.m_attributes[i] >> 24

                self.m_event = self.START_TAG
                break

            if chunkType == self.CHUNK_XML_END_TAG:
                self.m_namespaceUri = unpack('<L', self.buff.read(4))[0]
                self.m_name = unpack('<L', self.buff.read(4))[0]
                self.m_event = self.END_TAG
                break

            if chunkType == self.CHUNK_XML_TEXT:
                self.m_name = unpack('<L', self.buff.read(4))[0]

                # FIXME
                self.buff.read(4)
                self.buff.read(4)

                self.m_event = self.TEXT
                break

    def getPrefixByUri(self, uri):
        try:
            return self.m_uriprefix[uri]
        except KeyError:
            return -1

    def getPrefix(self):
        try:
            return self.sb.getString(self.m_uriprefix[self.m_namespaceUri])
        except KeyError:
            return u''

    def getName(self):
        if self.m_name == -1 or (self.m_event != self.START_TAG and self.m_event != self.END_TAG):
            return u''
        return self.sb.getString(self.m_name)

    def getText(self):
        if self.m_name == -1 or self.m_event != self.TEXT:
            return u''
        return self.sb.getString(self.m_name)

    def getNamespacePrefix(self, pos):
        prefix = self.m_prefixuriL[pos][0]
        return self.sb.getString(prefix)

    def getNamespaceUri(self, pos):
        uri = self.m_prefixuriL[pos][1]
        return self.sb.getString(uri)

    def getXMLNS(self):
        buff = ""
        for i in self.m_uriprefix:
            if i not in self.visited_ns:
                buff += "xmlns:%s=\"%s\"\n" % (
                    self.sb.getString(self.m_uriprefix[i]), self.sb.getString(self.m_prefixuri[self.m_uriprefix[i]]))
                self.visited_ns.append(i)
        return buff

    def getNamespaceCount(self, pos):
        pass

    def getAttributeOffset(self, index):
        # FIXME
        if self.m_event != self.START_TAG:
            logging.warning("Current event is not START_TAG.")

        offset = index * 5
        # FIXME
        if offset >= len(self.m_attributes):
            logging.warning("Invalid attribute index")

        return offset

    def getAttributeCount(self):
        if self.m_event != self.START_TAG:
            return -1

        return len(self.m_attributes) / self.ATTRIBUTE_LENGHT

    def getAttributePrefix(self, index):
        offset = self.getAttributeOffset(index)
        uri = self.m_attributes[offset + self.ATTRIBUTE_IX_NAMESPACE_URI]
        prefix = self.getPrefixByUri(uri)
        if prefix == -1:
            return ""
        return self.sb.getString(prefix)

    def getAttributeName(self, index):
        offset = self.getAttributeOffset(index)
        name = self.m_attributes[offset + self.ATTRIBUTE_IX_NAME]
        if name == -1:
            return ""
        return self.sb.getString(name)

    def getAttributeValueType(self, index):
        offset = self.getAttributeOffset(index)
        return self.m_attributes[offset + self.ATTRIBUTE_IX_VALUE_TYPE]

    def getAttributeValueData(self, index):
        offset = self.getAttributeOffset(index)
        return self.m_attributes[offset + self.ATTRIBUTE_IX_VALUE_DATA]

    def getAttributeValue(self, index):
        offset = self.getAttributeOffset(index)
        valueType = self.m_attributes[offset + self.ATTRIBUTE_IX_VALUE_TYPE]
        if valueType == self.TYPE_STRING:
            valueString = self.m_attributes[offset + self.ATTRIBUTE_IX_VALUE_STRING]
            return self.sb.getString(valueString)
        return ""