func (parser *Parser) getLEWord(off int) int {
	return int(int((int64(parser.Data[off+3])<<24)&0xff000000) |
		((int(parser.Data[off+2]) << 16) & 0x00ff0000) |
		((int(parser.Data[off+1]) << 8) & 0x0000ff00) |
		((int(parser.Data[off+0]) << 0) & 0x000000ff))
}
@param arr
the byte array to read
@param off
the offset of the word to read
@return value of a Little Endian 32 bit word from the byte arrayat offset
off.
package axmlParser
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"strconv"
)
const (
	TAG = "CXP"
	WORD_START_DOCUMENT = 0x00080003
	WORD_STRING_TABLE = 0x001C0001
	WORD_RES_TABLE    = 0x00080180
	WORD_START_NS  = 0x00100100
	WORD_END_NS    = 0x00100101
	WORD_START_TAG = 0x00100102
	WORD_END_TAG   = 0x00100103
	WORD_TEXT      = 0x00100104
	WORD_EOS       = 0xFFFFFFFF
	WORD_SIZE      = 4
	TYPE_ID_REF   = 0x01000008
	TYPE_ATTR_REF = 0x02000008
	TYPE_STRING   = 0x03000008
	TYPE_DIMEN    = 0x05000008
	TYPE_FRACTION = 0x06000008
	TYPE_INT      = 0x10000008
	TYPE_FLOAT    = 0x04000008
	TYPE_FLAGS  = 0x11000008
	TYPE_BOOL   = 0x12000008
	TYPE_COLOR  = 0x1C000008
	TYPE_COLOR2 = 0x1D000008
)
var (
	DIMEN = []string{"px", "dp", "sp",
		"pt", "in", "mm"}
)
type Parser struct {
	listener Listener
	Namespaces map[string]string
	Data       []byte
	StringsTable                        []string
	ResourcesIds                        []int
	StringsCount, StylesCount, ResCount int
	ParserOffset                        int
}
func New(listener Listener) *Parser {
	return &Parser{
		listener:     listener,
		Namespaces:   make(map[string]string),
		Data:         make([]byte, 0),
		StringsTable: make([]string, 0),
		ResourcesIds: make([]int, 0),
	}
}
func (parser *Parser) IsValid(header []byte) bool {
	return (header[0] == 0x03) && (header[1] == 0x00) &&
		(header[2] == 0x08) && (header[3] == 0x00)
}
func (parser *Parser) Parse(data []byte) error {
	var word0 int64
	parser.Data = data
	for parser.ParserOffset < len(parser.Data) {
		word0 = int64(parser.getLEWord(parser.ParserOffset))
		switch word0 {
		case WORD_START_DOCUMENT:
			parser.parseStartDocument()
		case WORD_STRING_TABLE:
			parser.parseStringTable()
		case WORD_RES_TABLE:
			parser.parseResourceTable()
		case WORD_START_NS:
			parser.parseNamespace(true)
		case WORD_END_NS:
			parser.parseNamespace(false)
		case WORD_START_TAG:
			parser.parseStartTag()
		case WORD_END_TAG:
			parser.parseEndTag()
		case WORD_TEXT:
			parser.parseText()
		case WORD_EOS:
			parser.listener.EndDocument()
		default:
			parser.ParserOffset += WORD_SIZE
		}
	}
	parser.listener.EndDocument()
	return nil
}
func (parser *Parser) parseStartDocument() {
	parser.listener.StartDocument()
	parser.ParserOffset += (2 * WORD_SIZE)
}
func (parser *Parser) parseStringTable() {
	chunk := parser.getLEWord(parser.ParserOffset + (1 * WORD_SIZE))
	parser.StringsCount = parser.getLEWord(parser.ParserOffset + (2 * WORD_SIZE))
	parser.StylesCount = parser.getLEWord(parser.ParserOffset + (3 * WORD_SIZE))
	strOffset := parser.ParserOffset + parser.getLEWord(parser.ParserOffset+(5*WORD_SIZE))
	styleOffset := parser.getLEWord(parser.ParserOffset + (6 * WORD_SIZE))
	parser.StringsTable = make([]string, parser.StringsCount)
	var offset int
	for i := 0; i < int(parser.StringsCount); i++ {
		offset = strOffset + parser.getLEWord(parser.ParserOffset+((i+7)*WORD_SIZE))
		parser.StringsTable[i] = parser.getStringFromStringTable(offset)
	}
	if styleOffset > 0 {
		for i := 0; i < parser.StylesCount; i++ {
		}
	}
	parser.ParserOffset += chunk
}
func (parser *Parser) parseResourceTable() {
	chunk := parser.getLEWord(parser.ParserOffset + (1 * WORD_SIZE))
	parser.ResCount = (chunk / 4) - 2
	parser.ResourcesIds = make([]int, parser.ResCount)
	for i := 0; i < parser.ResCount; i++ {
		parser.ResourcesIds[i] = parser.getLEWord(parser.ParserOffset + ((i + 2) * WORD_SIZE))
	}
	parser.ParserOffset += chunk
}
func (parser *Parser) parseNamespace(start bool) {
	prefixIdx := parser.getLEWord(parser.ParserOffset + (4 * WORD_SIZE))
	uriIdx := parser.getLEWord(parser.ParserOffset + (5 * WORD_SIZE))
	uri := parser.getString(uriIdx)
	prefix := parser.getString(prefixIdx)
	if start {
		parser.listener.StartPrefixMapping(prefix, uri)
		parser.Namespaces[uri] = prefix
	} else {
		parser.listener.EndPrefixMapping(prefix, uri)
		delete(parser.Namespaces, uri)
	}
	parser.ParserOffset += (6 * WORD_SIZE)
}
func (parser *Parser) parseStartTag() {
	uriIdx := parser.getLEWord(parser.ParserOffset + (4 * WORD_SIZE))
	nameIdx := parser.getLEWord(parser.ParserOffset + (5 * WORD_SIZE))
	attrCount := parser.getLEWord(parser.ParserOffset + (7 * WORD_SIZE))
	name := parser.getString(nameIdx)
	var uri, qname string
	if int64(uriIdx) == 0xFFFFFFFF {
		uri = ""
		qname = name
	} else {
		uri = parser.getString(uriIdx)
		if v, ok := parser.Namespaces[uri]; ok {
			qname = v + ":" + name
		} else {
			qname = name
		}
	}
	parser.ParserOffset += (9 * WORD_SIZE)
	attrs := make([]*Attribute, attrCount)  
	for a := 0; a < attrCount; a++ {
		attrs[a] = parser.parseAttribute()  
		parser.ParserOffset += (5 * 4)
	}
	parser.listener.StartElement(uri, name, qname, attrs)
}
func (parser *Parser) parseAttribute() *Attribute {
	attrNSIdx := parser.getLEWord(parser.ParserOffset)
	attrNameIdx := parser.getLEWord(parser.ParserOffset + (1 * WORD_SIZE))
	attrValueIdx := parser.getLEWord(parser.ParserOffset + (2 * WORD_SIZE))
	attrType := parser.getLEWord(parser.ParserOffset + (3 * WORD_SIZE))
	attrData := parser.getLEWord(parser.ParserOffset + (4 * WORD_SIZE))
	attr := new(Attribute)
	attr.Name = parser.getString(attrNameIdx)
	if int64(attrNSIdx) == 0xFFFFFFFF {
		attr.Namespace = ""
		attr.Prefix = ""
	} else {
		uri := parser.getString(attrNSIdx)
		if v, ok := parser.Namespaces[uri]; ok {
			attr.Namespace = uri
			attr.Prefix = v
		}
	}
	if int64(attrValueIdx) == 0xFFFFFFFF {
		attr.Value = parser.getAttributeValue(attrType, attrData)
	} else {
		attr.Value = parser.getString(attrValueIdx)
	}
	return attr
}
func (parser *Parser) parseText() {
	strIndex := parser.getLEWord(parser.ParserOffset + (4 * WORD_SIZE))
	data := parser.getString(strIndex)
	parser.listener.CharacterData(data)
	parser.ParserOffset += (7 * WORD_SIZE)
}
func (parser *Parser) parseEndTag() {
	uriIdx := parser.getLEWord(parser.ParserOffset + (4 * WORD_SIZE))
	nameIdx := parser.getLEWord(parser.ParserOffset + (5 * WORD_SIZE))
	name := parser.getString(nameIdx)
	var uri string
	if int64(uriIdx) == 0xFFFFFFFF {
		uri = ""
	} else {
		uri = parser.getString(uriIdx)
	}
	parser.listener.EndElement(uri, name, "")
	parser.ParserOffset += (6 * WORD_SIZE)
}
func (parser *Parser) getString(index int) string {
	var res string
	if (index >= 0) && (index < parser.StringsCount) {
		res = parser.StringsTable[index]
	} else {
		res = ""  
	}
	return res
}
func (parser *Parser) getStringFromStringTable(offset int) string {
	var strLength int
	var chars []byte
	if parser.Data[offset+1] == parser.Data[offset] {
		strLength = int(parser.Data[offset])
		chars = make([]byte, strLength)  
		for i := 0; i < strLength; i++ {
			chars[i] = parser.Data[offset+2+i]  
		}
	} else {
		strLength = ((int(parser.Data[offset+1] << 8)) & 0xFF00) |
			(int(parser.Data[offset]) & 0xFF)
		chars = make([]byte, strLength)  
		for i := 0; i < strLength; i++ {
			chars[i] = parser.Data[offset+2+(i*2)]  
		}
	}
	return string(chars)
}