// 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 }