| Index: third_party/go/src/golang.org/x/mobile/cmd/gomobile/binary_xml.go
|
| diff --git a/third_party/go/src/golang.org/x/mobile/cmd/gomobile/binary_xml.go b/third_party/go/src/golang.org/x/mobile/cmd/gomobile/binary_xml.go
|
| deleted file mode 100644
|
| index 7b11aaad3fa4d56568ec166288b13aa8d73c5a97..0000000000000000000000000000000000000000
|
| --- a/third_party/go/src/golang.org/x/mobile/cmd/gomobile/binary_xml.go
|
| +++ /dev/null
|
| @@ -1,694 +0,0 @@
|
| -// 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 main
|
| -
|
| -import (
|
| - "encoding/xml"
|
| - "fmt"
|
| - "io"
|
| - "sort"
|
| - "strconv"
|
| - "strings"
|
| - "unicode/utf16"
|
| -)
|
| -
|
| -// binaryXML converts XML into Android's undocumented binary XML format.
|
| -//
|
| -// The best source of information on this format seems to be the source code
|
| -// in AOSP frameworks-base. Android "resource" types seem to describe the
|
| -// encoded bytes, in particular:
|
| -//
|
| -// ResChunk_header
|
| -// ResStringPool_header
|
| -// ResXMLTree_node
|
| -//
|
| -// These are defined in:
|
| -//
|
| -// https://android.googlesource.com/platform/frameworks/base/+/master/include/androidfw/ResourceTypes.h
|
| -//
|
| -// The rough format of the file is a resource chunk containing a sequence of
|
| -// chunks. Each chunk is made up of a header and a body. The header begins with
|
| -// the contents of the ResChunk_header struct, which includes the size of both
|
| -// the header and the body.
|
| -//
|
| -// Both the header and body are 4-byte aligned.
|
| -//
|
| -// Values are encoded as little-endian.
|
| -//
|
| -// The android source code for encoding is done in the aapt tool. Its source
|
| -// code lives in AOSP:
|
| -//
|
| -// https://android.googlesource.com/platform/frameworks/base.git/+/master/tools/aapt
|
| -//
|
| -// A sample layout:
|
| -//
|
| -// File Header (ResChunk_header, type XML)
|
| -// Chunk: String Pool (type STRING_POOL)
|
| -// Sequence of strings, each with the format:
|
| -// uint16 length
|
| -// uint16 extended_length -- only if top bit set on length
|
| -// UTF-16LE string
|
| -// two zero bytes
|
| -// Resource Map
|
| -// The [i]th 4-byte entry in the resource map corresponds with
|
| -// the [i]th string from the string pool. The 4-bytes are a
|
| -// Resource ID constant defined:
|
| -// http://developer.android.com/reference/android/R.attr.html
|
| -// This appears to be a way to map strings onto enum values.
|
| -// Chunk: Namespace Start (ResXMLTree_node; ResXMLTree_namespaceExt)
|
| -// Chunk: Element Start
|
| -// ResXMLTree_node
|
| -// ResXMLTree_attrExt
|
| -// ResXMLTree_attribute (repeated attributeCount times)
|
| -// Chunk: Element End
|
| -// (ResXMLTree_node; ResXMLTree_endElementExt)
|
| -// ...
|
| -// Chunk: Namespace End
|
| -func binaryXML(r io.Reader) ([]byte, error) {
|
| - lr := &lineReader{r: r}
|
| - d := xml.NewDecoder(lr)
|
| -
|
| - pool := new(binStringPool)
|
| - depth := 0
|
| - elements := []chunk{}
|
| - namespaceEnds := make(map[int][]binEndNamespace)
|
| -
|
| - for {
|
| - line := lr.line(d.InputOffset())
|
| - tok, err := d.Token()
|
| - if err != nil {
|
| - if err == io.EOF {
|
| - break
|
| - }
|
| - return nil, err
|
| - }
|
| - switch tok := tok.(type) {
|
| - case xml.StartElement:
|
| - // Intercept namespace definitions.
|
| - var attr []*binAttr
|
| - for _, a := range tok.Attr {
|
| - if a.Name.Space == "xmlns" {
|
| - elements = append(elements, binStartNamespace{
|
| - line: line,
|
| - prefix: pool.get(a.Name.Local),
|
| - url: pool.get(a.Value),
|
| - })
|
| - namespaceEnds[depth] = append([]binEndNamespace{{
|
| - line: line,
|
| - prefix: pool.get(a.Name.Local),
|
| - url: pool.get(a.Value),
|
| - }}, namespaceEnds[depth]...)
|
| - continue
|
| - }
|
| - ba, err := pool.getAttr(a)
|
| - if err != nil {
|
| - return nil, fmt.Errorf("%d: %s: %v", line, a.Name.Local, err)
|
| - }
|
| - attr = append(attr, ba)
|
| - }
|
| -
|
| - depth++
|
| - elements = append(elements, &binStartElement{
|
| - line: line,
|
| - ns: pool.getNS(tok.Name.Space),
|
| - name: pool.get(tok.Name.Local),
|
| - attr: attr,
|
| - })
|
| - case xml.EndElement:
|
| - elements = append(elements, &binEndElement{
|
| - line: line,
|
| - ns: pool.getNS(tok.Name.Space),
|
| - name: pool.get(tok.Name.Local),
|
| - })
|
| - depth--
|
| - if nsEnds := namespaceEnds[depth]; len(nsEnds) > 0 {
|
| - delete(namespaceEnds, depth)
|
| - for _, nsEnd := range nsEnds {
|
| - elements = append(elements, nsEnd)
|
| - }
|
| - }
|
| - case xml.CharData:
|
| - // The aapt tool appears to "compact" leading and
|
| - // trailing whitepsace. See XMLNode::removeWhitespace in
|
| - // https://android.googlesource.com/platform/frameworks/base.git/+/master/tools/aapt/XMLNode.cpp
|
| - if len(tok) == 0 {
|
| - continue
|
| - }
|
| - start, end := 0, len(tok)
|
| - for start < len(tok) && isSpace(tok[start]) {
|
| - start++
|
| - }
|
| - for end > start && isSpace(tok[end-1]) {
|
| - end--
|
| - }
|
| - if start == end {
|
| - continue // all whitespace, skip it
|
| - }
|
| -
|
| - // Preserve one character of whitespace.
|
| - if start > 0 {
|
| - start--
|
| - }
|
| - if end < len(tok) {
|
| - end++
|
| - }
|
| -
|
| - elements = append(elements, &binCharData{
|
| - line: line,
|
| - data: pool.get(string(tok[start:end])),
|
| - })
|
| - case xml.Comment:
|
| - // Ignored by Anroid Binary XML format.
|
| - case xml.ProcInst:
|
| - // Ignored by Anroid Binary XML format?
|
| - case xml.Directive:
|
| - // Ignored by Anroid Binary XML format.
|
| - default:
|
| - return nil, fmt.Errorf("apk: unexpected token: %v (%T)", tok, tok)
|
| - }
|
| - }
|
| -
|
| - sortPool(pool)
|
| - for _, e := range elements {
|
| - if e, ok := e.(*binStartElement); ok {
|
| - sortAttr(e, pool)
|
| - }
|
| - }
|
| -
|
| - resMap := &binResMap{pool}
|
| -
|
| - size := 8 + pool.size() + resMap.size()
|
| - for _, e := range elements {
|
| - size += e.size()
|
| - }
|
| -
|
| - b := make([]byte, 0, size)
|
| - b = appendHeader(b, headerXML, size)
|
| - b = pool.append(b)
|
| - b = resMap.append(b)
|
| - for _, e := range elements {
|
| - b = e.append(b)
|
| - }
|
| -
|
| - return b, nil
|
| -}
|
| -
|
| -func isSpace(b byte) bool {
|
| - switch b {
|
| - case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
|
| - return true
|
| - }
|
| - return false
|
| -}
|
| -
|
| -type headerType uint16
|
| -
|
| -const (
|
| - headerXML headerType = 0x0003
|
| - headerStringPool = 0x0001
|
| - headerResourceMap = 0x0180
|
| - headerStartNamespace = 0x0100
|
| - headerEndNamespace = 0x0101
|
| - headerStartElement = 0x0102
|
| - headerEndElement = 0x0103
|
| - headerCharData = 0x0104
|
| -)
|
| -
|
| -func appendU16(b []byte, v uint16) []byte {
|
| - return append(b, byte(v), byte(v>>8))
|
| -}
|
| -
|
| -func appendU32(b []byte, v uint32) []byte {
|
| - return append(b, byte(v), byte(v>>8), byte(v>>16), byte(v>>24))
|
| -}
|
| -
|
| -func appendHeader(b []byte, typ headerType, size int) []byte {
|
| - b = appendU16(b, uint16(typ))
|
| - b = appendU16(b, 8)
|
| - b = appendU16(b, uint16(size))
|
| - b = appendU16(b, 0)
|
| - return b
|
| -}
|
| -
|
| -// Attributes of the form android:key are mapped to resource IDs, which are
|
| -// embedded into the Binary XML format.
|
| -//
|
| -// http://developer.android.com/reference/android/R.attr.html
|
| -var resourceCodes = map[string]uint32{
|
| - "versionCode": 0x0101021b,
|
| - "versionName": 0x0101021c,
|
| - "minSdkVersion": 0x0101020c,
|
| - "windowFullscreen": 0x0101020d,
|
| - "label": 0x01010001,
|
| - "hasCode": 0x0101000c,
|
| - "debuggable": 0x0101000f,
|
| - "name": 0x01010003,
|
| - "configChanges": 0x0101001f,
|
| - "value": 0x01010024,
|
| -}
|
| -
|
| -// http://developer.android.com/reference/android/R.attr.html#configChanges
|
| -var configChanges = map[string]uint32{
|
| - "mcc": 0x0001,
|
| - "mnc": 0x0002,
|
| - "locale": 0x0004,
|
| - "touchscreen": 0x0008,
|
| - "keyboard": 0x0010,
|
| - "keyboardHidden": 0x0020,
|
| - "navigation": 0x0040,
|
| - "orientation": 0x0080,
|
| - "screenLayout": 0x0100,
|
| - "uiMode": 0x0200,
|
| - "screenSize": 0x0400,
|
| - "smallestScreenSize": 0x0800,
|
| - "layoutDirection": 0x2000,
|
| - "fontScale": 0x40000000,
|
| -}
|
| -
|
| -type lineReader struct {
|
| - off int64
|
| - lines []int64
|
| - r io.Reader
|
| -}
|
| -
|
| -func (r *lineReader) Read(p []byte) (n int, err error) {
|
| - n, err = r.r.Read(p)
|
| - for i := 0; i < n; i++ {
|
| - if p[i] == '\n' {
|
| - r.lines = append(r.lines, r.off+int64(i))
|
| - }
|
| - }
|
| - r.off += int64(n)
|
| - return n, err
|
| -}
|
| -
|
| -func (r *lineReader) line(pos int64) int {
|
| - return sort.Search(len(r.lines), func(i int) bool {
|
| - return pos < r.lines[i]
|
| - }) + 1
|
| -}
|
| -
|
| -type bstring struct {
|
| - ind uint32
|
| - str string
|
| - enc []byte // 2-byte length, utf16le, 2-byte zero
|
| -}
|
| -
|
| -type chunk interface {
|
| - size() int
|
| - append([]byte) []byte
|
| -}
|
| -
|
| -type binResMap struct {
|
| - pool *binStringPool
|
| -}
|
| -
|
| -func (p *binResMap) append(b []byte) []byte {
|
| - b = appendHeader(b, headerResourceMap, p.size())
|
| - for _, bstr := range p.pool.s {
|
| - c, ok := resourceCodes[bstr.str]
|
| - if !ok {
|
| - break
|
| - }
|
| - b = appendU32(b, c)
|
| - }
|
| - return b
|
| -}
|
| -
|
| -func (p *binResMap) size() int {
|
| - count := 0
|
| - for _, bstr := range p.pool.s {
|
| - if _, ok := resourceCodes[bstr.str]; !ok {
|
| - break
|
| - }
|
| - count++
|
| - }
|
| - return 8 + 4*count
|
| -}
|
| -
|
| -type binStringPool struct {
|
| - s []*bstring
|
| - m map[string]*bstring
|
| -}
|
| -
|
| -func (p *binStringPool) get(str string) *bstring {
|
| - if p.m == nil {
|
| - p.m = make(map[string]*bstring)
|
| - }
|
| - res := p.m[str]
|
| - if res != nil {
|
| - return res
|
| - }
|
| - res = &bstring{
|
| - ind: uint32(len(p.s)),
|
| - str: str,
|
| - }
|
| - p.s = append(p.s, res)
|
| - p.m[str] = res
|
| -
|
| - if len(str)>>16 > 0 {
|
| - panic(fmt.Sprintf("string lengths over 1<<15 not yet supported, got len %d for string that starts %q", len(str), str[:100]))
|
| - }
|
| - strUTF16 := utf16.Encode([]rune(str))
|
| - res.enc = appendU16(nil, uint16(len(strUTF16)))
|
| - for _, w := range strUTF16 {
|
| - res.enc = appendU16(res.enc, w)
|
| - }
|
| - res.enc = appendU16(res.enc, 0)
|
| - return res
|
| -}
|
| -
|
| -func (p *binStringPool) getNS(ns string) *bstring {
|
| - if ns == "" {
|
| - // Register empty string for inclusion in output (like aapt),
|
| - // but do not reference it from namespace elements.
|
| - p.get("")
|
| - return nil
|
| - }
|
| - return p.get(ns)
|
| -}
|
| -
|
| -func (p *binStringPool) getAttr(attr xml.Attr) (*binAttr, error) {
|
| - a := &binAttr{
|
| - ns: p.getNS(attr.Name.Space),
|
| - name: p.get(attr.Name.Local),
|
| - }
|
| - if attr.Name.Space != "http://schemas.android.com/apk/res/android" {
|
| - a.data = p.get(attr.Value)
|
| - return a, nil
|
| - }
|
| -
|
| - // Some android attributes have interesting values.
|
| - switch attr.Name.Local {
|
| - case "versionCode", "minSdkVersion":
|
| - v, err := strconv.Atoi(attr.Value)
|
| - if err != nil {
|
| - return nil, err
|
| - }
|
| - a.data = int(v)
|
| - case "hasCode", "debuggable":
|
| - v, err := strconv.ParseBool(attr.Value)
|
| - if err != nil {
|
| - return nil, err
|
| - }
|
| - a.data = v
|
| - case "configChanges":
|
| - v := uint32(0)
|
| - for _, c := range strings.Split(attr.Value, "|") {
|
| - v |= configChanges[c]
|
| - }
|
| - a.data = v
|
| - default:
|
| - a.data = p.get(attr.Value)
|
| - }
|
| - return a, nil
|
| -}
|
| -
|
| -const stringPoolPreamble = 0 +
|
| - 8 + // chunk header
|
| - 4 + // string count
|
| - 4 + // style count
|
| - 4 + // flags
|
| - 4 + // strings start
|
| - 4 + // styles start
|
| - 0
|
| -
|
| -func (p *binStringPool) unpaddedSize() int {
|
| - strLens := 0
|
| - for _, s := range p.s {
|
| - strLens += len(s.enc)
|
| - }
|
| - return stringPoolPreamble + 4*len(p.s) + strLens
|
| -}
|
| -
|
| -func (p *binStringPool) size() int {
|
| - size := p.unpaddedSize()
|
| - size += size % 0x04
|
| - return size
|
| -}
|
| -
|
| -// overloaded for testing.
|
| -var (
|
| - sortPool = func(p *binStringPool) {
|
| - sort.Sort(p)
|
| -
|
| - // Move resourceCodes to the front.
|
| - s := make([]*bstring, 0)
|
| - m := make(map[string]*bstring)
|
| - for str := range resourceCodes {
|
| - bstr := p.m[str]
|
| - if bstr == nil {
|
| - continue
|
| - }
|
| - bstr.ind = uint32(len(s))
|
| - s = append(s, bstr)
|
| - m[str] = bstr
|
| - delete(p.m, str)
|
| - }
|
| - for _, bstr := range p.m {
|
| - bstr.ind = uint32(len(s))
|
| - s = append(s, bstr)
|
| - }
|
| - p.s = s
|
| - p.m = m
|
| - }
|
| - sortAttr = func(e *binStartElement, p *binStringPool) {}
|
| -)
|
| -
|
| -func (b *binStringPool) Len() int { return len(b.s) }
|
| -func (b *binStringPool) Less(i, j int) bool { return b.s[i].str < b.s[j].str }
|
| -func (b *binStringPool) Swap(i, j int) {
|
| - b.s[i], b.s[j] = b.s[j], b.s[i]
|
| - b.s[i].ind, b.s[j].ind = b.s[j].ind, b.s[i].ind
|
| -}
|
| -
|
| -func (p *binStringPool) append(b []byte) []byte {
|
| - stringsStart := uint32(stringPoolPreamble + 4*len(p.s))
|
| - b = appendU16(b, uint16(headerStringPool))
|
| - b = appendU16(b, 0x1c) // chunk header size
|
| - b = appendU16(b, uint16(p.size()))
|
| - b = appendU16(b, 0)
|
| - b = appendU32(b, uint32(len(p.s)))
|
| - b = appendU32(b, 0) // style count
|
| - b = appendU32(b, 0) // flags
|
| - b = appendU32(b, stringsStart)
|
| - b = appendU32(b, 0) // styles start
|
| -
|
| - off := 0
|
| - for _, bstr := range p.s {
|
| - b = appendU32(b, uint32(off))
|
| - off += len(bstr.enc)
|
| - }
|
| - for _, bstr := range p.s {
|
| - b = append(b, bstr.enc...)
|
| - }
|
| -
|
| - for i := p.unpaddedSize() % 0x04; i > 0; i-- {
|
| - b = append(b, 0)
|
| - }
|
| - return b
|
| -}
|
| -
|
| -type binStartElement struct {
|
| - line int
|
| - ns *bstring
|
| - name *bstring
|
| - attr []*binAttr
|
| -}
|
| -
|
| -func (e *binStartElement) size() int {
|
| - return 8 + // chunk header
|
| - 4 + // line number
|
| - 4 + // comment
|
| - 4 + // ns
|
| - 4 + // name
|
| - 2 + 2 + 2 + // attribute start, size, count
|
| - 2 + 2 + 2 + // id/class/style index
|
| - len(e.attr)*(4+4+4+4+4)
|
| -}
|
| -
|
| -func (e *binStartElement) append(b []byte) []byte {
|
| - b = appendU16(b, uint16(headerStartElement))
|
| - b = appendU16(b, 0x10) // chunk header size
|
| - b = appendU16(b, uint16(e.size()))
|
| - b = appendU16(b, 0)
|
| - b = appendU32(b, uint32(e.line))
|
| - b = appendU32(b, 0xffffffff) // comment
|
| - if e.ns == nil {
|
| - b = appendU32(b, 0xffffffff)
|
| - } else {
|
| - b = appendU32(b, e.ns.ind)
|
| - }
|
| - b = appendU32(b, e.name.ind)
|
| - b = appendU16(b, 0x14) // attribute start
|
| - b = appendU16(b, 0x14) // attribute size
|
| - b = appendU16(b, uint16(len(e.attr)))
|
| - b = appendU16(b, 0) // ID index (none)
|
| - b = appendU16(b, 0) // class index (none)
|
| - b = appendU16(b, 0) // style index (none)
|
| - for _, a := range e.attr {
|
| - b = a.append(b)
|
| - }
|
| - return b
|
| -}
|
| -
|
| -type binAttr struct {
|
| - ns *bstring
|
| - name *bstring
|
| - data interface{} // either int (INT_DEC) or *bstring (STRING)
|
| -}
|
| -
|
| -func (a *binAttr) append(b []byte) []byte {
|
| - if a.ns != nil {
|
| - b = appendU32(b, a.ns.ind)
|
| - } else {
|
| - b = appendU32(b, 0xffffffff)
|
| - }
|
| - b = appendU32(b, a.name.ind)
|
| - switch v := a.data.(type) {
|
| - case int:
|
| - b = appendU32(b, 0xffffffff) // raw value
|
| - b = appendU16(b, 8) // size
|
| - b = append(b, 0) // unused padding
|
| - b = append(b, 0x10) // INT_DEC
|
| - b = appendU32(b, uint32(v))
|
| - case bool:
|
| - b = appendU32(b, 0xffffffff) // raw value
|
| - b = appendU16(b, 8) // size
|
| - b = append(b, 0) // unused padding
|
| - b = append(b, 0x12) // INT_BOOLEAN
|
| - if v {
|
| - b = appendU32(b, 0xffffffff)
|
| - } else {
|
| - b = appendU32(b, 0)
|
| - }
|
| - case uint32:
|
| - b = appendU32(b, 0xffffffff) // raw value
|
| - b = appendU16(b, 8) // size
|
| - b = append(b, 0) // unused padding
|
| - b = append(b, 0x11) // INT_HEX
|
| - b = appendU32(b, uint32(v))
|
| - case *bstring:
|
| - b = appendU32(b, v.ind) // raw value
|
| - b = appendU16(b, 8) // size
|
| - b = append(b, 0) // unused padding
|
| - b = append(b, 0x03) // STRING
|
| - b = appendU32(b, v.ind)
|
| - default:
|
| - panic(fmt.Sprintf("unexpected attr type: %T (%v)", v, v))
|
| - }
|
| - return b
|
| -}
|
| -
|
| -type binEndElement struct {
|
| - line int
|
| - ns *bstring
|
| - name *bstring
|
| - attr []*binAttr
|
| -}
|
| -
|
| -func (*binEndElement) size() int {
|
| - return 8 + // chunk header
|
| - 4 + // line number
|
| - 4 + // comment
|
| - 4 + // ns
|
| - 4 // name
|
| -}
|
| -
|
| -func (e *binEndElement) append(b []byte) []byte {
|
| - b = appendU16(b, uint16(headerEndElement))
|
| - b = appendU16(b, 0x10) // chunk header size
|
| - b = appendU16(b, uint16(e.size()))
|
| - b = appendU16(b, 0)
|
| - b = appendU32(b, uint32(e.line))
|
| - b = appendU32(b, 0xffffffff) // comment
|
| - if e.ns == nil {
|
| - b = appendU32(b, 0xffffffff)
|
| - } else {
|
| - b = appendU32(b, e.ns.ind)
|
| - }
|
| - b = appendU32(b, e.name.ind)
|
| - return b
|
| -}
|
| -
|
| -type binStartNamespace struct {
|
| - line int
|
| - prefix *bstring
|
| - url *bstring
|
| -}
|
| -
|
| -func (binStartNamespace) size() int {
|
| - return 8 + // chunk header
|
| - 4 + // line number
|
| - 4 + // comment
|
| - 4 + // prefix
|
| - 4 // url
|
| -}
|
| -
|
| -func (e binStartNamespace) append(b []byte) []byte {
|
| - b = appendU16(b, uint16(headerStartNamespace))
|
| - b = appendU16(b, 0x10) // chunk header size
|
| - b = appendU16(b, uint16(e.size()))
|
| - b = appendU16(b, 0)
|
| - b = appendU32(b, uint32(e.line))
|
| - b = appendU32(b, 0xffffffff) // comment
|
| - b = appendU32(b, e.prefix.ind)
|
| - b = appendU32(b, e.url.ind)
|
| - return b
|
| -}
|
| -
|
| -type binEndNamespace struct {
|
| - line int
|
| - prefix *bstring
|
| - url *bstring
|
| -}
|
| -
|
| -func (binEndNamespace) size() int {
|
| - return 8 + // chunk header
|
| - 4 + // line number
|
| - 4 + // comment
|
| - 4 + // prefix
|
| - 4 // url
|
| -}
|
| -
|
| -func (e binEndNamespace) append(b []byte) []byte {
|
| - b = appendU16(b, uint16(headerEndNamespace))
|
| - b = appendU16(b, 0x10) // chunk header size
|
| - b = appendU16(b, uint16(e.size()))
|
| - b = appendU16(b, 0)
|
| - b = appendU32(b, uint32(e.line))
|
| - b = appendU32(b, 0xffffffff) // comment
|
| - b = appendU32(b, e.prefix.ind)
|
| - b = appendU32(b, e.url.ind)
|
| - return b
|
| -}
|
| -
|
| -type binCharData struct {
|
| - line int
|
| - data *bstring
|
| -}
|
| -
|
| -func (*binCharData) size() int {
|
| - return 8 + // chunk header
|
| - 4 + // line number
|
| - 4 + // comment
|
| - 4 + // data
|
| - 8 // junk
|
| -}
|
| -
|
| -func (e *binCharData) append(b []byte) []byte {
|
| - b = appendU16(b, uint16(headerCharData))
|
| - b = appendU16(b, 0x10) // chunk header size
|
| - b = appendU16(b, 0x1c) // size
|
| - b = appendU16(b, 0)
|
| - b = appendU32(b, uint32(e.line))
|
| - b = appendU32(b, 0xffffffff) // comment
|
| - b = appendU32(b, e.data.ind)
|
| - b = appendU16(b, 0x08)
|
| - b = appendU16(b, 0)
|
| - b = appendU16(b, 0)
|
| - b = appendU16(b, 0)
|
| - return b
|
| -}
|
|
|