github.com/corfe83/mobile@v0.0.0-20220928034243-9edc37f43fac/internal/binres/binres.go (about)

     1  // Copyright 2015 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:generate go run genarsc.go
     6  //go:generate stringer -output binres_string.go -type ResType,DataType
     7  
     8  // Package binres implements encoding and decoding of android binary resources.
     9  //
    10  // Binary resource structs support unmarshalling the binary output of aapt.
    11  // Implementations of marshalling for each struct must produce the exact input
    12  // sent to unmarshalling. This allows tests to validate each struct representation
    13  // of the binary format as follows:
    14  //
    15  //  * unmarshal the output of aapt
    16  //  * marshal the struct representation
    17  //  * perform byte-to-byte comparison with aapt output per chunk header and body
    18  //
    19  // This process should strive to make structs idiomatic to make parsing xml text
    20  // into structs trivial.
    21  //
    22  // Once the struct representation is validated, tests for parsing xml text
    23  // into structs can become self-referential as the following holds true:
    24  //
    25  //  * the unmarshalled input of aapt output is the only valid target
    26  //  * the unmarshalled input of xml text may be compared to the unmarshalled
    27  //    input of aapt output to identify errors, e.g. text-trims, wrong flags, etc
    28  //
    29  // This provides validation, byte-for-byte, for producing binary xml resources.
    30  //
    31  // It should be made clear that unmarshalling binary resources is currently only
    32  // in scope for proving that the BinaryMarshaler works correctly. Any other use
    33  // is currently out of scope.
    34  //
    35  // A simple view of binary xml document structure:
    36  //
    37  //  XML
    38  //    Pool
    39  //    Map
    40  //    Namespace
    41  //    [...node]
    42  //
    43  // Additional resources:
    44  // https://android.googlesource.com/platform/frameworks/base/+/master/libs/androidfw/include/androidfw/ResourceTypes.h
    45  // https://justanapplication.wordpress.com/2011/09/13/ (a series of articles, increment date)
    46  package binres
    47  
    48  import (
    49  	"encoding"
    50  	"encoding/binary"
    51  	"encoding/xml"
    52  	"fmt"
    53  	"io"
    54  	"sort"
    55  	"strconv"
    56  	"strings"
    57  	"unicode"
    58  )
    59  
    60  func errWrongType(have ResType, want ...ResType) error {
    61  	return fmt.Errorf("wrong resource type %s, want one of %v", have, want)
    62  }
    63  
    64  type ResType uint16
    65  
    66  func (t ResType) IsSupported() bool {
    67  	return t != ResNull
    68  }
    69  
    70  // explicitly defined for clarity and resolvability with apt source
    71  const (
    72  	ResNull       ResType = 0x0000
    73  	ResStringPool ResType = 0x0001
    74  	ResTable      ResType = 0x0002
    75  	ResXML        ResType = 0x0003
    76  
    77  	ResXMLStartNamespace ResType = 0x0100
    78  	ResXMLEndNamespace   ResType = 0x0101
    79  	ResXMLStartElement   ResType = 0x0102
    80  	ResXMLEndElement     ResType = 0x0103
    81  	ResXMLCharData       ResType = 0x0104
    82  
    83  	ResXMLResourceMap ResType = 0x0180
    84  
    85  	ResTablePackage  ResType = 0x0200
    86  	ResTableType     ResType = 0x0201
    87  	ResTableTypeSpec ResType = 0x0202
    88  	ResTableLibrary  ResType = 0x0203
    89  )
    90  
    91  var (
    92  	btou16 = binary.LittleEndian.Uint16
    93  	btou32 = binary.LittleEndian.Uint32
    94  	putu16 = binary.LittleEndian.PutUint16
    95  	putu32 = binary.LittleEndian.PutUint32
    96  )
    97  
    98  // unmarshaler wraps BinaryUnmarshaler to provide byte size of decoded chunks.
    99  type unmarshaler interface {
   100  	encoding.BinaryUnmarshaler
   101  
   102  	// size returns the byte size unmarshalled after a call to
   103  	// UnmarshalBinary, or otherwise zero.
   104  	size() int
   105  }
   106  
   107  // chunkHeader appears at the front of every data chunk in a resource.
   108  type chunkHeader struct {
   109  	// Type of data that follows this header.
   110  	typ ResType
   111  
   112  	// Advance slice index by this value to find its associated data, if any.
   113  	headerByteSize uint16
   114  
   115  	// This is the header size plus the size of any data associated with the chunk.
   116  	// Advance slice index by this value to completely skip its contents, including
   117  	// any child chunks. If this value is the same as headerByteSize, there is
   118  	// no data associated with the chunk.
   119  	byteSize uint32
   120  }
   121  
   122  // size implements unmarshaler.
   123  func (hdr chunkHeader) size() int { return int(hdr.byteSize) }
   124  
   125  func (hdr *chunkHeader) UnmarshalBinary(bin []byte) error {
   126  	hdr.typ = ResType(btou16(bin))
   127  	if !hdr.typ.IsSupported() {
   128  		return fmt.Errorf("%s not supported", hdr.typ)
   129  	}
   130  	hdr.headerByteSize = btou16(bin[2:])
   131  	hdr.byteSize = btou32(bin[4:])
   132  	if len(bin) < int(hdr.byteSize) {
   133  		return fmt.Errorf("too few bytes to unmarshal chunk body, have %v, need at-least %v", len(bin), hdr.byteSize)
   134  	}
   135  	return nil
   136  }
   137  
   138  func (hdr chunkHeader) MarshalBinary() ([]byte, error) {
   139  	if !hdr.typ.IsSupported() {
   140  		return nil, fmt.Errorf("%s not supported", hdr.typ)
   141  	}
   142  
   143  	bin := make([]byte, 8)
   144  	putu16(bin, uint16(hdr.typ))
   145  	putu16(bin[2:], hdr.headerByteSize)
   146  	putu32(bin[4:], hdr.byteSize)
   147  	return bin, nil
   148  }
   149  
   150  type XML struct {
   151  	chunkHeader
   152  
   153  	Pool *Pool
   154  	Map  *Map
   155  
   156  	Namespace *Namespace
   157  	Children  []*Element
   158  
   159  	// tmp field used when unmarshalling binary
   160  	stack []*Element
   161  }
   162  
   163  // RawValueByName returns the original raw string value of first matching element attribute, or error if not exists.
   164  // Given <manifest package="VAL" ...> then RawValueByName("manifest", xml.Name{Local: "package"}) returns "VAL".
   165  func (bx *XML) RawValueByName(elname string, attrname xml.Name) (string, error) {
   166  	elref, err := bx.Pool.RefByName(elname)
   167  	if err != nil {
   168  		return "", err
   169  	}
   170  	nref, err := bx.Pool.RefByName(attrname.Local)
   171  	if err != nil {
   172  		return "", err
   173  	}
   174  	nsref := PoolRef(NoEntry)
   175  	if attrname.Space != "" {
   176  		nsref, err = bx.Pool.RefByName(attrname.Space)
   177  		if err != nil {
   178  			return "", err
   179  		}
   180  	}
   181  
   182  	for el := range bx.iterElements() {
   183  		if el.Name == elref {
   184  			for _, attr := range el.attrs {
   185  				// TODO enforce TypedValue DataString constraint?
   186  				if nsref == attr.NS && nref == attr.Name {
   187  					return bx.Pool.strings[int(attr.RawValue)], nil
   188  				}
   189  			}
   190  		}
   191  	}
   192  	return "", fmt.Errorf("no matching element %q for attribute %+v found", elname, attrname)
   193  }
   194  
   195  const (
   196  	androidSchema = "http://schemas.android.com/apk/res/android"
   197  	toolsSchema   = "http://schemas.android.com/tools"
   198  )
   199  
   200  // skipSynthesize is set true for tests to avoid synthesis of additional nodes and attributes.
   201  var skipSynthesize bool
   202  
   203  // UnmarshalXML decodes an AndroidManifest.xml document returning type XML
   204  // containing decoded resources.
   205  func UnmarshalXML(r io.Reader, withIcon bool) (*XML, error) {
   206  	tbl, err := OpenTable()
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  
   211  	lr := &lineReader{r: r}
   212  	dec := xml.NewDecoder(lr)
   213  	bx := new(XML)
   214  
   215  	// temporary pool to resolve real poolref later
   216  	pool := new(Pool)
   217  
   218  	type ltoken struct {
   219  		xml.Token
   220  		line int
   221  	}
   222  	var q []ltoken
   223  
   224  	for {
   225  		line := lr.line(dec.InputOffset())
   226  		tkn, err := dec.Token()
   227  		if err != nil {
   228  			if err == io.EOF {
   229  				break
   230  			}
   231  			return nil, err
   232  		}
   233  		tkn = xml.CopyToken(tkn)
   234  
   235  		switch tkn := tkn.(type) {
   236  		case xml.StartElement:
   237  			switch tkn.Name.Local {
   238  			default:
   239  				q = append(q, ltoken{tkn, line})
   240  			case "uses-sdk":
   241  				return nil, fmt.Errorf("manual declaration of uses-sdk in AndroidManifest.xml not supported")
   242  			case "manifest":
   243  				// synthesize additional attributes and nodes for use during encode.
   244  				tkn.Attr = append(tkn.Attr,
   245  					xml.Attr{
   246  						Name: xml.Name{
   247  							Space: "",
   248  							Local: "platformBuildVersionCode",
   249  						},
   250  						Value: "23",
   251  					},
   252  					xml.Attr{
   253  						Name: xml.Name{
   254  							Space: "",
   255  							Local: "platformBuildVersionName",
   256  						},
   257  						Value: "4.0.4-1406430",
   258  					})
   259  
   260  				q = append(q, ltoken{tkn, line})
   261  
   262  				if !skipSynthesize {
   263  					s := xml.StartElement{
   264  						Name: xml.Name{
   265  							Space: "",
   266  							Local: "uses-sdk",
   267  						},
   268  						Attr: []xml.Attr{
   269  							xml.Attr{
   270  								Name: xml.Name{
   271  									Space: androidSchema,
   272  									Local: "minSdkVersion",
   273  								},
   274  								Value: fmt.Sprintf("%v", 23),
   275  							},
   276  							xml.Attr{
   277  								Name: xml.Name{
   278  									Space: androidSchema,
   279  									Local: "targetSdkVersion",
   280  								},
   281  								Value: fmt.Sprintf("%v", 30),
   282  							},
   283  						},
   284  					}
   285  					e := xml.EndElement{Name: xml.Name{Local: "uses-sdk"}}
   286  
   287  					q = append(q, ltoken{s, line}, ltoken{e, line})
   288  				}
   289  			case "application":
   290  				if !skipSynthesize {
   291  					for _, attr := range tkn.Attr {
   292  						if attr.Name.Space == androidSchema && attr.Name.Local == "icon" {
   293  							return nil, fmt.Errorf("manual declaration of android:icon in AndroidManifest.xml not supported")
   294  						}
   295  					}
   296  					if withIcon {
   297  						tkn.Attr = append(tkn.Attr,
   298  							xml.Attr{
   299  								Name: xml.Name{
   300  									Space: androidSchema,
   301  									Local: "icon",
   302  								},
   303  								Value: "@mipmap/icon",
   304  							})
   305  					}
   306  				}
   307  				q = append(q, ltoken{tkn, line})
   308  			}
   309  		default:
   310  			q = append(q, ltoken{tkn, line})
   311  		}
   312  	}
   313  
   314  	for _, ltkn := range q {
   315  		tkn, line := ltkn.Token, ltkn.line
   316  
   317  		switch tkn := tkn.(type) {
   318  		case xml.StartElement:
   319  			el := &Element{
   320  				NodeHeader: NodeHeader{
   321  					LineNumber: uint32(line),
   322  					Comment:    0xFFFFFFFF,
   323  				},
   324  				NS:   NoEntry,
   325  				Name: pool.ref(tkn.Name.Local),
   326  			}
   327  			if len(bx.stack) == 0 {
   328  				bx.Children = append(bx.Children, el)
   329  			} else {
   330  				n := len(bx.stack)
   331  				var p *Element
   332  				p, bx.stack = bx.stack[n-1], bx.stack[:n-1]
   333  				p.Children = append(p.Children, el)
   334  				bx.stack = append(bx.stack, p)
   335  			}
   336  			bx.stack = append(bx.stack, el)
   337  
   338  			for _, attr := range tkn.Attr {
   339  				if (attr.Name.Space == "xmlns" && attr.Name.Local == "tools") || attr.Name.Space == toolsSchema {
   340  					continue // TODO can tbl be queried for schemas to determine validity instead?
   341  				}
   342  
   343  				if attr.Name.Space == "xmlns" && attr.Name.Local == "android" {
   344  					if bx.Namespace != nil {
   345  						return nil, fmt.Errorf("multiple declarations of xmlns:android encountered")
   346  					}
   347  					bx.Namespace = &Namespace{
   348  						NodeHeader: NodeHeader{
   349  							LineNumber: uint32(line),
   350  							Comment:    NoEntry,
   351  						},
   352  						prefix: 0,
   353  						uri:    0,
   354  					}
   355  					continue
   356  				}
   357  
   358  				nattr := &Attribute{
   359  					NS:       pool.ref(attr.Name.Space),
   360  					Name:     pool.ref(attr.Name.Local),
   361  					RawValue: NoEntry,
   362  				}
   363  				el.attrs = append(el.attrs, nattr)
   364  
   365  				if attr.Name.Space == "" {
   366  					nattr.NS = NoEntry
   367  					// TODO it's unclear how to query these
   368  					switch attr.Name.Local {
   369  					case "platformBuildVersionCode":
   370  						nattr.TypedValue.Type = DataIntDec
   371  						i, err := strconv.Atoi(attr.Value)
   372  						if err != nil {
   373  							return nil, err
   374  						}
   375  						nattr.TypedValue.Value = uint32(i)
   376  					default: // "package", "platformBuildVersionName", and any invalid
   377  						nattr.RawValue = pool.ref(attr.Value)
   378  						nattr.TypedValue.Type = DataString
   379  					}
   380  				} else {
   381  					// get type spec and value data type
   382  					ref, err := tbl.RefByName("attr/" + attr.Name.Local)
   383  					if err != nil {
   384  						return nil, err
   385  					}
   386  					nt, err := ref.Resolve(tbl)
   387  					if err != nil {
   388  						return nil, err
   389  					}
   390  					if len(nt.values) == 0 {
   391  						panic("encountered empty values slice")
   392  					}
   393  
   394  					if len(nt.values) == 1 {
   395  						val := nt.values[0]
   396  						if val.data.Type != DataIntDec {
   397  							panic("TODO only know how to handle DataIntDec type here")
   398  						}
   399  
   400  						t := DataType(val.data.Value)
   401  						switch t {
   402  						case DataString, DataAttribute, DataType(0x3e):
   403  							// TODO identify 0x3e, in bootstrap.xml this is the native lib name
   404  							nattr.RawValue = pool.ref(attr.Value)
   405  							nattr.TypedValue.Type = DataString
   406  							nattr.TypedValue.Value = uint32(nattr.RawValue)
   407  						case DataIntBool, DataType(0x08):
   408  							nattr.TypedValue.Type = DataIntBool
   409  							switch attr.Value {
   410  							case "true":
   411  								nattr.TypedValue.Value = 0xFFFFFFFF
   412  							case "false":
   413  								nattr.TypedValue.Value = 0
   414  							default:
   415  								return nil, fmt.Errorf("invalid bool value %q", attr.Value)
   416  							}
   417  						case DataIntDec, DataFloat, DataFraction:
   418  							// TODO DataFraction needs it's own case statement. minSdkVersion identifies as DataFraction
   419  							// but has accepted input in the past such as android:minSdkVersion="L"
   420  							// Other use-cases for DataFraction are currently unknown as applicable to manifest generation
   421  							// but this provides minimum support for writing out minSdkVersion="15" correctly.
   422  							nattr.TypedValue.Type = DataIntDec
   423  							i, err := strconv.Atoi(attr.Value)
   424  							if err != nil {
   425  								return nil, err
   426  							}
   427  							nattr.TypedValue.Value = uint32(i)
   428  						case DataReference:
   429  							nattr.TypedValue.Type = DataReference
   430  							dref, err := tbl.RefByName(attr.Value)
   431  							if err != nil {
   432  								if strings.HasPrefix(attr.Value, "@mipmap") {
   433  									// firstDrawableId is a TableRef matching first entry of mipmap spec initialized by NewMipmapTable.
   434  									// 7f is default package, 02 is mipmap spec, 0000 is first entry; e.g. R.drawable.icon
   435  									// TODO resource table should generate ids as required.
   436  									const firstDrawableId = 0x7f020000
   437  									nattr.TypedValue.Value = firstDrawableId
   438  									continue
   439  								}
   440  								return nil, err
   441  							}
   442  							nattr.TypedValue.Value = uint32(dref)
   443  						default:
   444  							return nil, fmt.Errorf("unhandled data type %0#2x: %s", uint8(t), t)
   445  						}
   446  					} else {
   447  						// 0x01000000 is an unknown ref that doesn't point to anything, typically
   448  						// located at the start of entry value lists, peek at last value to determine type.
   449  						t := nt.values[len(nt.values)-1].data.Type
   450  						switch t {
   451  						case DataIntDec:
   452  							for _, val := range nt.values {
   453  								if val.name == 0x01000000 {
   454  									continue
   455  								}
   456  								nr, err := val.name.Resolve(tbl)
   457  								if err != nil {
   458  									return nil, err
   459  								}
   460  								if attr.Value == nr.key.Resolve(tbl.pkgs[0].keyPool) { // TODO hard-coded pkg ref
   461  									nattr.TypedValue = *val.data
   462  									break
   463  								}
   464  							}
   465  						case DataIntHex:
   466  							nattr.TypedValue.Type = t
   467  							for _, x := range strings.Split(attr.Value, "|") {
   468  								for _, val := range nt.values {
   469  									if val.name == 0x01000000 {
   470  										continue
   471  									}
   472  									nr, err := val.name.Resolve(tbl)
   473  									if err != nil {
   474  										return nil, err
   475  									}
   476  									if x == nr.key.Resolve(tbl.pkgs[0].keyPool) { // TODO hard-coded pkg ref
   477  										nattr.TypedValue.Value |= val.data.Value
   478  										break
   479  									}
   480  								}
   481  							}
   482  						default:
   483  							return nil, fmt.Errorf("unhandled data type for configuration %0#2x: %s", uint8(t), t)
   484  						}
   485  					}
   486  				}
   487  			}
   488  		case xml.CharData:
   489  			if s := poolTrim(string(tkn)); s != "" {
   490  				cdt := &CharData{
   491  					NodeHeader: NodeHeader{
   492  						LineNumber: uint32(line),
   493  						Comment:    NoEntry,
   494  					},
   495  					RawData: pool.ref(s),
   496  				}
   497  				el := bx.stack[len(bx.stack)-1]
   498  				if el.head == nil {
   499  					el.head = cdt
   500  				} else if el.tail == nil {
   501  					el.tail = cdt
   502  				} else {
   503  					return nil, fmt.Errorf("element head and tail already contain chardata")
   504  				}
   505  			}
   506  		case xml.EndElement:
   507  			if tkn.Name.Local == "manifest" {
   508  				bx.Namespace.end = &Namespace{
   509  					NodeHeader: NodeHeader{
   510  						LineNumber: uint32(line),
   511  						Comment:    NoEntry,
   512  					},
   513  					prefix: 0,
   514  					uri:    0,
   515  				}
   516  			}
   517  			n := len(bx.stack)
   518  			var el *Element
   519  			el, bx.stack = bx.stack[n-1], bx.stack[:n-1]
   520  			if el.end != nil {
   521  				return nil, fmt.Errorf("element end already exists")
   522  			}
   523  			el.end = &ElementEnd{
   524  				NodeHeader: NodeHeader{
   525  					LineNumber: uint32(line),
   526  					Comment:    NoEntry,
   527  				},
   528  				NS:   el.NS,
   529  				Name: el.Name,
   530  			}
   531  		case xml.Comment, xml.ProcInst:
   532  			// discard
   533  		default:
   534  			panic(fmt.Errorf("unhandled token type: %T %+v", tkn, tkn))
   535  		}
   536  	}
   537  
   538  	// pools appear to be sorted as follows:
   539  	// * attribute names prefixed with android:
   540  	// * "android", [schema-url], [empty-string]
   541  	// * for each node:
   542  	//   * attribute names with no prefix
   543  	//   * node name
   544  	//   * attribute value if data type of name is DataString, DataAttribute, or 0x3e (an unknown)
   545  	bx.Pool = new(Pool)
   546  
   547  	var arecurse func(*Element)
   548  	arecurse = func(el *Element) {
   549  		for _, attr := range el.attrs {
   550  			if attr.NS == NoEntry {
   551  				continue
   552  			}
   553  			if attr.NS.Resolve(pool) == androidSchema {
   554  				bx.Pool.strings = append(bx.Pool.strings, attr.Name.Resolve(pool))
   555  			}
   556  		}
   557  		for _, child := range el.Children {
   558  			arecurse(child)
   559  		}
   560  	}
   561  	for _, el := range bx.Children {
   562  		arecurse(el)
   563  	}
   564  
   565  	// TODO encoding/xml does not enforce namespace prefix and manifest encoding in aapt
   566  	// appears to ignore all other prefixes. Inserting this manually is not strictly correct
   567  	// for the general case, but the effort to do otherwise currently offers nothing.
   568  	bx.Pool.strings = append(bx.Pool.strings, "android", androidSchema)
   569  
   570  	// there always appears to be an empty string located after schema, even if one is
   571  	// not present in manifest.
   572  	bx.Pool.strings = append(bx.Pool.strings, "")
   573  
   574  	var brecurse func(*Element)
   575  	brecurse = func(el *Element) {
   576  		for _, attr := range el.attrs {
   577  			if attr.NS == NoEntry {
   578  				bx.Pool.strings = append(bx.Pool.strings, attr.Name.Resolve(pool))
   579  			}
   580  		}
   581  
   582  		bx.Pool.strings = append(bx.Pool.strings, el.Name.Resolve(pool))
   583  
   584  		for _, attr := range el.attrs {
   585  			if attr.RawValue != NoEntry {
   586  				bx.Pool.strings = append(bx.Pool.strings, attr.RawValue.Resolve(pool))
   587  			} else if attr.NS == NoEntry {
   588  				bx.Pool.strings = append(bx.Pool.strings, fmt.Sprintf("%+v", attr.TypedValue.Value))
   589  			}
   590  		}
   591  
   592  		if el.head != nil {
   593  			bx.Pool.strings = append(bx.Pool.strings, el.head.RawData.Resolve(pool))
   594  		}
   595  		if el.tail != nil {
   596  			bx.Pool.strings = append(bx.Pool.strings, el.tail.RawData.Resolve(pool))
   597  		}
   598  
   599  		for _, child := range el.Children {
   600  			brecurse(child)
   601  		}
   602  	}
   603  	for _, el := range bx.Children {
   604  		brecurse(el)
   605  	}
   606  
   607  	// do not eliminate duplicates until the entire slice has been composed.
   608  	// consider <activity android:label="label" .../>
   609  	// all attribute names come first followed by values; in such a case, the value "label"
   610  	// would be a reference to the same "android:label" in the string pool which will occur
   611  	// within the beginning of the pool where other attr names are located.
   612  	bx.Pool.strings = asSet(bx.Pool.strings)
   613  
   614  	// TODO consider cases of multiple declarations of the same attr name that should return error
   615  	// before ever reaching this point.
   616  	bx.Map = new(Map)
   617  	for _, s := range bx.Pool.strings {
   618  		ref, err := tbl.RefByName("attr/" + s)
   619  		if err != nil {
   620  			break // break after first non-ref as all strings after are also non-refs.
   621  		}
   622  		bx.Map.rs = append(bx.Map.rs, ref)
   623  	}
   624  
   625  	// resolve tmp pool refs to final pool refs
   626  	// TODO drop this in favor of sort directly on Table
   627  	var resolve func(el *Element)
   628  	resolve = func(el *Element) {
   629  		if el.NS != NoEntry {
   630  			el.NS = bx.Pool.ref(el.NS.Resolve(pool))
   631  			el.end.NS = el.NS
   632  		}
   633  		el.Name = bx.Pool.ref(el.Name.Resolve(pool))
   634  		el.end.Name = el.Name
   635  		for _, attr := range el.attrs {
   636  			if attr.NS != NoEntry {
   637  				attr.NS = bx.Pool.ref(attr.NS.Resolve(pool))
   638  			}
   639  			attr.Name = bx.Pool.ref(attr.Name.Resolve(pool))
   640  			if attr.RawValue != NoEntry {
   641  				attr.RawValue = bx.Pool.ref(attr.RawValue.Resolve(pool))
   642  				if attr.TypedValue.Type == DataString {
   643  					attr.TypedValue.Value = uint32(attr.RawValue)
   644  				}
   645  			}
   646  		}
   647  		for _, child := range el.Children {
   648  			resolve(child)
   649  		}
   650  	}
   651  	for _, el := range bx.Children {
   652  		resolve(el)
   653  	}
   654  
   655  	var asort func(*Element)
   656  	asort = func(el *Element) {
   657  		sort.Sort(byType(el.attrs))
   658  		sort.Sort(byNamespace(el.attrs))
   659  		sort.Sort(byName(el.attrs))
   660  		for _, child := range el.Children {
   661  			asort(child)
   662  		}
   663  	}
   664  	for _, el := range bx.Children {
   665  		asort(el)
   666  	}
   667  
   668  	for i, s := range bx.Pool.strings {
   669  		switch s {
   670  		case androidSchema:
   671  			bx.Namespace.uri = PoolRef(i)
   672  			bx.Namespace.end.uri = PoolRef(i)
   673  		case "android":
   674  			bx.Namespace.prefix = PoolRef(i)
   675  			bx.Namespace.end.prefix = PoolRef(i)
   676  		}
   677  	}
   678  
   679  	return bx, nil
   680  }
   681  
   682  // UnmarshalBinary decodes all resource chunks in buf returning any error encountered.
   683  func (bx *XML) UnmarshalBinary(buf []byte) error {
   684  	if err := (&bx.chunkHeader).UnmarshalBinary(buf); err != nil {
   685  		return err
   686  	}
   687  	buf = buf[8:]
   688  	for len(buf) > 0 {
   689  		k, err := bx.unmarshalBinaryKind(buf)
   690  		if err != nil {
   691  			return err
   692  		}
   693  		buf = buf[k.size():]
   694  	}
   695  	return nil
   696  }
   697  
   698  // unmarshalBinaryKind decodes and stores the first resource chunk of bin.
   699  // It returns the unmarshaler interface and any error encountered.
   700  // If k.size() < len(bin), subsequent chunks can be decoded at bin[k.size():].
   701  func (bx *XML) unmarshalBinaryKind(bin []byte) (k unmarshaler, err error) {
   702  	k, err = bx.kind(ResType(btou16(bin)))
   703  	if err != nil {
   704  		return nil, err
   705  	}
   706  	if err = k.UnmarshalBinary(bin); err != nil {
   707  		return nil, err
   708  	}
   709  	return k, nil
   710  }
   711  
   712  func (bx *XML) kind(t ResType) (unmarshaler, error) {
   713  	switch t {
   714  	case ResStringPool:
   715  		if bx.Pool != nil {
   716  			return nil, fmt.Errorf("pool already exists")
   717  		}
   718  		bx.Pool = new(Pool)
   719  		return bx.Pool, nil
   720  	case ResXMLResourceMap:
   721  		if bx.Map != nil {
   722  			return nil, fmt.Errorf("resource map already exists")
   723  		}
   724  		bx.Map = new(Map)
   725  		return bx.Map, nil
   726  	case ResXMLStartNamespace:
   727  		if bx.Namespace != nil {
   728  			return nil, fmt.Errorf("namespace start already exists")
   729  		}
   730  		bx.Namespace = new(Namespace)
   731  		return bx.Namespace, nil
   732  	case ResXMLEndNamespace:
   733  		if bx.Namespace.end != nil {
   734  			return nil, fmt.Errorf("namespace end already exists")
   735  		}
   736  		bx.Namespace.end = new(Namespace)
   737  		return bx.Namespace.end, nil
   738  	case ResXMLStartElement:
   739  		el := new(Element)
   740  		if len(bx.stack) == 0 {
   741  			bx.Children = append(bx.Children, el)
   742  		} else {
   743  			n := len(bx.stack)
   744  			var p *Element
   745  			p, bx.stack = bx.stack[n-1], bx.stack[:n-1]
   746  			p.Children = append(p.Children, el)
   747  			bx.stack = append(bx.stack, p)
   748  		}
   749  		bx.stack = append(bx.stack, el)
   750  		return el, nil
   751  	case ResXMLEndElement:
   752  		n := len(bx.stack)
   753  		var el *Element
   754  		el, bx.stack = bx.stack[n-1], bx.stack[:n-1]
   755  		if el.end != nil {
   756  			return nil, fmt.Errorf("element end already exists")
   757  		}
   758  		el.end = new(ElementEnd)
   759  		return el.end, nil
   760  	case ResXMLCharData: // TODO assure correctness
   761  		cdt := new(CharData)
   762  		el := bx.stack[len(bx.stack)-1]
   763  		if el.head == nil {
   764  			el.head = cdt
   765  		} else if el.tail == nil {
   766  			el.tail = cdt
   767  		} else {
   768  			return nil, fmt.Errorf("element head and tail already contain chardata")
   769  		}
   770  		return cdt, nil
   771  	default:
   772  		return nil, fmt.Errorf("unexpected type %s", t)
   773  	}
   774  }
   775  
   776  func (bx *XML) MarshalBinary() ([]byte, error) {
   777  	bx.typ = ResXML
   778  	bx.headerByteSize = 8
   779  
   780  	var (
   781  		bin, b []byte
   782  		err    error
   783  	)
   784  	b, err = bx.chunkHeader.MarshalBinary()
   785  	if err != nil {
   786  		return nil, err
   787  	}
   788  	bin = append(bin, b...)
   789  
   790  	b, err = bx.Pool.MarshalBinary()
   791  	if err != nil {
   792  		return nil, err
   793  	}
   794  	bin = append(bin, b...)
   795  
   796  	b, err = bx.Map.MarshalBinary()
   797  	if err != nil {
   798  		return nil, err
   799  	}
   800  	bin = append(bin, b...)
   801  
   802  	b, err = bx.Namespace.MarshalBinary()
   803  	if err != nil {
   804  		return nil, err
   805  	}
   806  	bin = append(bin, b...)
   807  
   808  	for _, child := range bx.Children {
   809  		if err := marshalRecurse(child, &bin); err != nil {
   810  			return nil, err
   811  		}
   812  	}
   813  
   814  	b, err = bx.Namespace.end.MarshalBinary()
   815  	if err != nil {
   816  		return nil, err
   817  	}
   818  	bin = append(bin, b...)
   819  
   820  	putu32(bin[4:], uint32(len(bin)))
   821  	return bin, nil
   822  }
   823  
   824  func marshalRecurse(el *Element, bin *[]byte) error {
   825  	b, err := el.MarshalBinary()
   826  	if err != nil {
   827  		return err
   828  	}
   829  	*bin = append(*bin, b...)
   830  
   831  	if el.head != nil {
   832  		b, err := el.head.MarshalBinary()
   833  		if err != nil {
   834  			return err
   835  		}
   836  		*bin = append(*bin, b...)
   837  	}
   838  
   839  	for _, child := range el.Children {
   840  		if err := marshalRecurse(child, bin); err != nil {
   841  			return err
   842  		}
   843  	}
   844  
   845  	b, err = el.end.MarshalBinary()
   846  	if err != nil {
   847  		return err
   848  	}
   849  	*bin = append(*bin, b...)
   850  
   851  	return nil
   852  }
   853  
   854  func (bx *XML) iterElements() <-chan *Element {
   855  	ch := make(chan *Element, 1)
   856  	go func() {
   857  		for _, el := range bx.Children {
   858  			iterElementsRecurse(el, ch)
   859  		}
   860  		close(ch)
   861  	}()
   862  	return ch
   863  }
   864  
   865  func iterElementsRecurse(el *Element, ch chan *Element) {
   866  	ch <- el
   867  	for _, e := range el.Children {
   868  		iterElementsRecurse(e, ch)
   869  	}
   870  }
   871  
   872  // asSet returns a set from a slice of strings.
   873  func asSet(xs []string) []string {
   874  	m := make(map[string]bool)
   875  	fo := xs[:0]
   876  	for _, x := range xs {
   877  		if !m[x] {
   878  			m[x] = true
   879  			fo = append(fo, x)
   880  		}
   881  	}
   882  	return fo
   883  }
   884  
   885  // poolTrim trims all but immediately surrounding space.
   886  // \n\t\tfoobar\n\t\t becomes \tfoobar\n
   887  func poolTrim(s string) string {
   888  	var start, end int
   889  	for i, r := range s {
   890  		if !unicode.IsSpace(r) {
   891  			if i != 0 {
   892  				start = i - 1 // preserve preceding space
   893  			}
   894  			break
   895  		}
   896  	}
   897  
   898  	for i := len(s) - 1; i >= 0; i-- {
   899  		r := rune(s[i])
   900  		if !unicode.IsSpace(r) {
   901  			if i != len(s)-1 {
   902  				end = i + 2
   903  			}
   904  			break
   905  		}
   906  	}
   907  
   908  	if start == 0 && end == 0 {
   909  		return "" // every char was a space
   910  	}
   911  
   912  	return s[start:end]
   913  }
   914  
   915  // byNamespace sorts attributes based on string pool position of namespace.
   916  // Given that "android" always preceeds "" in the pool, this results in the
   917  // correct ordering of attributes.
   918  type byNamespace []*Attribute
   919  
   920  func (a byNamespace) Len() int { return len(a) }
   921  func (a byNamespace) Less(i, j int) bool {
   922  	return a[i].NS < a[j].NS
   923  }
   924  func (a byNamespace) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   925  
   926  // byType sorts attributes by the uint8 value of the type.
   927  type byType []*Attribute
   928  
   929  func (a byType) Len() int { return len(a) }
   930  func (a byType) Less(i, j int) bool {
   931  	return a[i].TypedValue.Type < a[j].TypedValue.Type
   932  }
   933  func (a byType) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   934  
   935  // byName sorts attributes that have matching types based on string pool position of name.
   936  type byName []*Attribute
   937  
   938  func (a byName) Len() int { return len(a) }
   939  func (a byName) Less(i, j int) bool {
   940  	return (a[i].TypedValue.Type == DataString || a[i].TypedValue.Type == DataIntDec) &&
   941  		(a[j].TypedValue.Type == DataString || a[j].TypedValue.Type == DataIntDec) &&
   942  		a[i].Name < a[j].Name
   943  }
   944  func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   945  
   946  type lineReader struct {
   947  	off   int64
   948  	lines []int64
   949  	r     io.Reader
   950  }
   951  
   952  func (r *lineReader) Read(p []byte) (n int, err error) {
   953  	n, err = r.r.Read(p)
   954  	for i := 0; i < n; i++ {
   955  		if p[i] == '\n' {
   956  			r.lines = append(r.lines, r.off+int64(i))
   957  		}
   958  	}
   959  	r.off += int64(n)
   960  	return n, err
   961  }
   962  
   963  func (r *lineReader) line(pos int64) int {
   964  	return sort.Search(len(r.lines), func(i int) bool {
   965  		return pos < r.lines[i]
   966  	}) + 1
   967  }