This fixes remaining issues that prevented use of package to encode manifest for packaging correctly. * Chunk headers are now encoded based on content * Fixes for namespace and value fields * Improved sorting based on native aapt output Change-Id: Ic63046973a7b0431533463ed4dd2de50f1d73191 Reviewed-on: https://go-review.googlesource.com/19224 Reviewed-by: David Crawshaw <crawshaw@golang.org>
253 lines
6.3 KiB
Go
253 lines
6.3 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package binres
|
|
|
|
// NodeHeader is header all xml node types have, providing additional
|
|
// information regarding an xml node over binChunkHeader.
|
|
type NodeHeader struct {
|
|
chunkHeader
|
|
LineNumber uint32 // line number in source file this element appears
|
|
Comment PoolRef // optional xml comment associated with element, MaxUint32 if none
|
|
}
|
|
|
|
func (hdr *NodeHeader) UnmarshalBinary(bin []byte) error {
|
|
if err := (&hdr.chunkHeader).UnmarshalBinary(bin); err != nil {
|
|
return err
|
|
}
|
|
hdr.LineNumber = btou32(bin[8:])
|
|
hdr.Comment = PoolRef(btou32(bin[12:]))
|
|
return nil
|
|
}
|
|
|
|
func (hdr *NodeHeader) MarshalBinary() ([]byte, error) {
|
|
bin := make([]byte, 16)
|
|
b, err := hdr.chunkHeader.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(bin, b)
|
|
putu32(bin[8:], hdr.LineNumber)
|
|
putu32(bin[12:], uint32(hdr.Comment))
|
|
return bin, nil
|
|
}
|
|
|
|
type Namespace struct {
|
|
NodeHeader
|
|
prefix PoolRef
|
|
uri PoolRef
|
|
|
|
end *Namespace // TODO don't let this type be recursive
|
|
}
|
|
|
|
func (ns *Namespace) UnmarshalBinary(bin []byte) error {
|
|
if err := (&ns.NodeHeader).UnmarshalBinary(bin); err != nil {
|
|
return err
|
|
}
|
|
buf := bin[ns.headerByteSize:]
|
|
ns.prefix = PoolRef(btou32(buf))
|
|
ns.uri = PoolRef(btou32(buf[4:]))
|
|
return nil
|
|
}
|
|
|
|
func (ns *Namespace) MarshalBinary() ([]byte, error) {
|
|
if ns.end == nil {
|
|
ns.typ = ResXMLEndNamespace
|
|
} else {
|
|
ns.typ = ResXMLStartNamespace
|
|
}
|
|
ns.headerByteSize = 16
|
|
ns.byteSize = 24
|
|
|
|
bin := make([]byte, ns.byteSize)
|
|
b, err := ns.NodeHeader.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(bin, b)
|
|
putu32(bin[16:], uint32(ns.prefix))
|
|
putu32(bin[20:], uint32(ns.uri))
|
|
return bin, nil
|
|
}
|
|
|
|
type Element struct {
|
|
NodeHeader
|
|
NS PoolRef
|
|
Name PoolRef // name of node if element, otherwise chardata if CDATA
|
|
AttributeStart uint16 // byte offset where attrs start
|
|
AttributeSize uint16 // byte size of attrs
|
|
AttributeCount uint16 // length of attrs
|
|
IdIndex uint16 // Index (1-based) of the "id" attribute. 0 if none.
|
|
ClassIndex uint16 // Index (1-based) of the "class" attribute. 0 if none.
|
|
StyleIndex uint16 // Index (1-based) of the "style" attribute. 0 if none.
|
|
|
|
attrs []*Attribute
|
|
Children []*Element
|
|
end *ElementEnd
|
|
|
|
head, tail *CharData
|
|
}
|
|
|
|
func (el *Element) UnmarshalBinary(buf []byte) error {
|
|
if err := (&el.NodeHeader).UnmarshalBinary(buf); err != nil {
|
|
return err
|
|
}
|
|
buf = buf[el.headerByteSize:]
|
|
el.NS = PoolRef(btou32(buf))
|
|
el.Name = PoolRef(btou32(buf[4:]))
|
|
|
|
el.AttributeStart = btou16(buf[8:])
|
|
el.AttributeSize = btou16(buf[10:])
|
|
el.AttributeCount = btou16(buf[12:])
|
|
el.IdIndex = btou16(buf[14:])
|
|
el.ClassIndex = btou16(buf[16:])
|
|
el.StyleIndex = btou16(buf[18:])
|
|
|
|
buf = buf[el.AttributeStart:]
|
|
el.attrs = make([]*Attribute, int(el.AttributeCount))
|
|
for i := range el.attrs {
|
|
attr := new(Attribute)
|
|
if err := attr.UnmarshalBinary(buf); err != nil {
|
|
return err
|
|
}
|
|
el.attrs[i] = attr
|
|
buf = buf[el.AttributeSize:]
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (el *Element) MarshalBinary() ([]byte, error) {
|
|
el.typ = ResXMLStartElement
|
|
el.headerByteSize = 16
|
|
el.AttributeSize = 20
|
|
el.AttributeStart = 20
|
|
el.AttributeCount = uint16(len(el.attrs))
|
|
el.IdIndex = 0
|
|
el.ClassIndex = 0
|
|
el.StyleIndex = 0
|
|
el.byteSize = uint32(el.headerByteSize) + uint32(el.AttributeStart) + uint32(len(el.attrs)*int(el.AttributeSize))
|
|
|
|
bin := make([]byte, el.byteSize)
|
|
b, err := el.NodeHeader.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(bin, b)
|
|
putu32(bin[16:], uint32(el.NS))
|
|
putu32(bin[20:], uint32(el.Name))
|
|
putu16(bin[24:], el.AttributeStart)
|
|
putu16(bin[26:], el.AttributeSize)
|
|
putu16(bin[28:], el.AttributeCount)
|
|
putu16(bin[30:], el.IdIndex)
|
|
putu16(bin[32:], el.ClassIndex)
|
|
putu16(bin[34:], el.StyleIndex)
|
|
|
|
buf := bin[36:]
|
|
for _, attr := range el.attrs {
|
|
b, err := attr.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(buf, b)
|
|
buf = buf[int(el.AttributeSize):]
|
|
}
|
|
|
|
return bin, nil
|
|
}
|
|
|
|
// ElementEnd marks the end of an element node, either Element or CharData.
|
|
type ElementEnd struct {
|
|
NodeHeader
|
|
NS PoolRef
|
|
Name PoolRef // name of node if binElement, raw chardata if binCharData
|
|
}
|
|
|
|
func (el *ElementEnd) UnmarshalBinary(bin []byte) error {
|
|
(&el.NodeHeader).UnmarshalBinary(bin)
|
|
buf := bin[el.headerByteSize:]
|
|
el.NS = PoolRef(btou32(buf))
|
|
el.Name = PoolRef(btou32(buf[4:]))
|
|
return nil
|
|
}
|
|
|
|
func (el *ElementEnd) MarshalBinary() ([]byte, error) {
|
|
el.typ = ResXMLEndElement
|
|
el.headerByteSize = 16
|
|
el.byteSize = 24
|
|
|
|
bin := make([]byte, 24)
|
|
b, err := el.NodeHeader.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(bin, b)
|
|
putu32(bin[16:], uint32(el.NS))
|
|
putu32(bin[20:], uint32(el.Name))
|
|
return bin, nil
|
|
}
|
|
|
|
type Attribute struct {
|
|
NS PoolRef
|
|
Name PoolRef
|
|
RawValue PoolRef // The original raw string value of this attribute.
|
|
TypedValue Data // Processesd typed value of this attribute.
|
|
}
|
|
|
|
func (attr *Attribute) UnmarshalBinary(bin []byte) error {
|
|
attr.NS = PoolRef(btou32(bin))
|
|
attr.Name = PoolRef(btou32(bin[4:]))
|
|
attr.RawValue = PoolRef(btou32(bin[8:]))
|
|
return (&attr.TypedValue).UnmarshalBinary(bin[12:])
|
|
}
|
|
|
|
func (attr *Attribute) MarshalBinary() ([]byte, error) {
|
|
bin := make([]byte, 20)
|
|
putu32(bin, uint32(attr.NS))
|
|
putu32(bin[4:], uint32(attr.Name))
|
|
putu32(bin[8:], uint32(attr.RawValue))
|
|
b, err := attr.TypedValue.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(bin[12:], b)
|
|
return bin, nil
|
|
}
|
|
|
|
// CharData represents a CDATA node and includes ref to node's text value.
|
|
type CharData struct {
|
|
NodeHeader
|
|
RawData PoolRef // raw character data
|
|
TypedData Data // typed value of character data
|
|
}
|
|
|
|
func (cdt *CharData) UnmarshalBinary(bin []byte) error {
|
|
if err := (&cdt.NodeHeader).UnmarshalBinary(bin); err != nil {
|
|
return err
|
|
}
|
|
buf := bin[cdt.headerByteSize:]
|
|
cdt.RawData = PoolRef(btou32(buf))
|
|
return (&cdt.TypedData).UnmarshalBinary(buf[4:])
|
|
}
|
|
|
|
func (cdt *CharData) MarshalBinary() ([]byte, error) {
|
|
cdt.typ = ResXMLCharData
|
|
cdt.headerByteSize = 16
|
|
cdt.byteSize = 28
|
|
|
|
bin := make([]byte, cdt.byteSize)
|
|
b, err := cdt.NodeHeader.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(bin, b)
|
|
putu32(bin[16:], uint32(cdt.RawData))
|
|
b, err = cdt.TypedData.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(bin[20:], b)
|
|
return bin, nil
|
|
}
|