github.com/provpn/mobile@v0.0.0-20210315122651-28c475f89f6c/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: "15",
   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", MinSDK),
   275  							},
   276  						},
   277  					}
   278  					e := xml.EndElement{Name: xml.Name{Local: "uses-sdk"}}
   279  
   280  					q = append(q, ltoken{s, line}, ltoken{e, line})
   281  				}
   282  			case "application":
   283  				if !skipSynthesize {
   284  					for _, attr := range tkn.Attr {
   285  						if attr.Name.Space == androidSchema && attr.Name.Local == "icon" {
   286  							return nil, fmt.Errorf("manual declaration of android:icon in AndroidManifest.xml not supported")
   287  						}
   288  					}
   289  					if withIcon {
   290  						tkn.Attr = append(tkn.Attr,
   291  							xml.Attr{
   292  								Name: xml.Name{
   293  									Space: androidSchema,
   294  									Local: "icon",
   295  								},
   296  								Value: "@mipmap/icon",
   297  							})
   298  					}
   299  				}
   300  				q = append(q, ltoken{tkn, line})
   301  			}
   302  		default:
   303  			q = append(q, ltoken{tkn, line})
   304  		}
   305  	}
   306  
   307  	for _, ltkn := range q {
   308  		tkn, line := ltkn.Token, ltkn.line
   309  
   310  		switch tkn := tkn.(type) {
   311  		case xml.StartElement:
   312  			el := &Element{
   313  				NodeHeader: NodeHeader{
   314  					LineNumber: uint32(line),
   315  					Comment:    0xFFFFFFFF,
   316  				},
   317  				NS:   NoEntry,
   318  				Name: pool.ref(tkn.Name.Local),
   319  			}
   320  			if len(bx.stack) == 0 {
   321  				bx.Children = append(bx.Children, el)
   322  			} else {
   323  				n := len(bx.stack)
   324  				var p *Element
   325  				p, bx.stack = bx.stack[n-1], bx.stack[:n-1]
   326  				p.Children = append(p.Children, el)
   327  				bx.stack = append(bx.stack, p)
   328  			}
   329  			bx.stack = append(bx.stack, el)
   330  
   331  			for _, attr := range tkn.Attr {
   332  				if (attr.Name.Space == "xmlns" && attr.Name.Local == "tools") || attr.Name.Space == toolsSchema {
   333  					continue // TODO can tbl be queried for schemas to determine validity instead?
   334  				}
   335  
   336  				if attr.Name.Space == "xmlns" && attr.Name.Local == "android" {
   337  					if bx.Namespace != nil {
   338  						return nil, fmt.Errorf("multiple declarations of xmlns:android encountered")
   339  					}
   340  					bx.Namespace = &Namespace{
   341  						NodeHeader: NodeHeader{
   342  							LineNumber: uint32(line),
   343  							Comment:    NoEntry,
   344  						},
   345  						prefix: 0,
   346  						uri:    0,
   347  					}
   348  					continue
   349  				}
   350  
   351  				nattr := &Attribute{
   352  					NS:       pool.ref(attr.Name.Space),
   353  					Name:     pool.ref(attr.Name.Local),
   354  					RawValue: NoEntry,
   355  				}
   356  				el.attrs = append(el.attrs, nattr)
   357  
   358  				if attr.Name.Space == "" {
   359  					nattr.NS = NoEntry
   360  					// TODO it's unclear how to query these
   361  					switch attr.Name.Local {
   362  					case "platformBuildVersionCode":
   363  						nattr.TypedValue.Type = DataIntDec
   364  						i, err := strconv.Atoi(attr.Value)
   365  						if err != nil {
   366  							return nil, err
   367  						}
   368  						nattr.TypedValue.Value = uint32(i)
   369  					default: // "package", "platformBuildVersionName", and any invalid
   370  						nattr.RawValue = pool.ref(attr.Value)
   371  						nattr.TypedValue.Type = DataString
   372  					}
   373  				} else {
   374  					// get type spec and value data type
   375  					ref, err := tbl.RefByName("attr/" + attr.Name.Local)
   376  					if err != nil {
   377  						return nil, err
   378  					}
   379  					nt, err := ref.Resolve(tbl)
   380  					if err != nil {
   381  						return nil, err
   382  					}
   383  					if len(nt.values) == 0 {
   384  						panic("encountered empty values slice")
   385  					}
   386  
   387  					if len(nt.values) == 1 {
   388  						val := nt.values[0]
   389  						if val.data.Type != DataIntDec {
   390  							panic("TODO only know how to handle DataIntDec type here")
   391  						}
   392  
   393  						t := DataType(val.data.Value)
   394  						switch t {
   395  						case DataString, DataAttribute, DataType(0x3e):
   396  							// TODO identify 0x3e, in bootstrap.xml this is the native lib name
   397  							nattr.RawValue = pool.ref(attr.Value)
   398  							nattr.TypedValue.Type = DataString
   399  							nattr.TypedValue.Value = uint32(nattr.RawValue)
   400  						case DataIntBool, DataType(0x08):
   401  							nattr.TypedValue.Type = DataIntBool
   402  							switch attr.Value {
   403  							case "true":
   404  								nattr.TypedValue.Value = 0xFFFFFFFF
   405  							case "false":
   406  								nattr.TypedValue.Value = 0
   407  							default:
   408  								return nil, fmt.Errorf("invalid bool value %q", attr.Value)
   409  							}
   410  						case DataIntDec, DataFloat, DataFraction:
   411  							// TODO DataFraction needs it's own case statement. minSdkVersion identifies as DataFraction
   412  							// but has accepted input in the past such as android:minSdkVersion="L"
   413  							// Other use-cases for DataFraction are currently unknown as applicable to manifest generation
   414  							// but this provides minimum support for writing out minSdkVersion="15" correctly.
   415  							nattr.TypedValue.Type = DataIntDec
   416  							i, err := strconv.Atoi(attr.Value)
   417  							if err != nil {
   418  								return nil, err
   419  							}
   420  							nattr.TypedValue.Value = uint32(i)
   421  						case DataReference:
   422  							nattr.TypedValue.Type = DataReference
   423  							dref, err := tbl.RefByName(attr.Value)
   424  							if err != nil {
   425  								if strings.HasPrefix(attr.Value, "@mipmap") {
   426  									// firstDrawableId is a TableRef matching first entry of mipmap spec initialized by NewMipmapTable.
   427  									// 7f is default package, 02 is mipmap spec, 0000 is first entry; e.g. R.drawable.icon
   428  									// TODO resource table should generate ids as required.
   429  									const firstDrawableId = 0x7f020000
   430  									nattr.TypedValue.Value = firstDrawableId
   431  									continue
   432  								}
   433  								return nil, err
   434  							}
   435  							nattr.TypedValue.Value = uint32(dref)
   436  						default:
   437  							return nil, fmt.Errorf("unhandled data type %0#2x: %s", uint8(t), t)
   438  						}
   439  					} else {
   440  						// 0x01000000 is an unknown ref that doesn't point to anything, typically
   441  						// located at the start of entry value lists, peek at last value to determine type.
   442  						t := nt.values[len(nt.values)-1].data.Type
   443  						switch t {
   444  						case DataIntDec:
   445  							for _, val := range nt.values {
   446  								if val.name == 0x01000000 {
   447  									continue
   448  								}
   449  								nr, err := val.name.Resolve(tbl)
   450  								if err != nil {
   451  									return nil, err
   452  								}
   453  								if attr.Value == nr.key.Resolve(tbl.pkgs[0].keyPool) { // TODO hard-coded pkg ref
   454  									nattr.TypedValue = *val.data
   455  									break
   456  								}
   457  							}
   458  						case DataIntHex:
   459  							nattr.TypedValue.Type = t
   460  							for _, x := range strings.Split(attr.Value, "|") {
   461  								for _, val := range nt.values {
   462  									if val.name == 0x01000000 {
   463  										continue
   464  									}
   465  									nr, err := val.name.Resolve(tbl)
   466  									if err != nil {
   467  										return nil, err
   468  									}
   469  									if x == nr.key.Resolve(tbl.pkgs[0].keyPool) { // TODO hard-coded pkg ref
   470  										nattr.TypedValue.Value |= val.data.Value
   471  										break
   472  									}
   473  								}
   474  							}
   475  						default:
   476  							return nil, fmt.Errorf("unhandled data type for configuration %0#2x: %s", uint8(t), t)
   477  						}
   478  					}
   479  				}
   480  			}
   481  		case xml.CharData:
   482  			if s := poolTrim(string(tkn)); s != "" {
   483  				cdt := &CharData{
   484  					NodeHeader: NodeHeader{
   485  						LineNumber: uint32(line),
   486  						Comment:    NoEntry,
   487  					},
   488  					RawData: pool.ref(s),
   489  				}
   490  				el := bx.stack[len(bx.stack)-1]
   491  				if el.head == nil {
   492  					el.head = cdt
   493  				} else if el.tail == nil {
   494  					el.tail = cdt
   495  				} else {
   496  					return nil, fmt.Errorf("element head and tail already contain chardata")
   497  				}
   498  			}
   499  		case xml.EndElement:
   500  			if tkn.Name.Local == "manifest" {
   501  				bx.Namespace.end = &Namespace{
   502  					NodeHeader: NodeHeader{
   503  						LineNumber: uint32(line),
   504  						Comment:    NoEntry,
   505  					},
   506  					prefix: 0,
   507  					uri:    0,
   508  				}
   509  			}
   510  			n := len(bx.stack)
   511  			var el *Element
   512  			el, bx.stack = bx.stack[n-1], bx.stack[:n-1]
   513  			if el.end != nil {
   514  				return nil, fmt.Errorf("element end already exists")
   515  			}
   516  			el.end = &ElementEnd{
   517  				NodeHeader: NodeHeader{
   518  					LineNumber: uint32(line),
   519  					Comment:    NoEntry,
   520  				},
   521  				NS:   el.NS,
   522  				Name: el.Name,
   523  			}
   524  		case xml.Comment, xml.ProcInst:
   525  			// discard
   526  		default:
   527  			panic(fmt.Errorf("unhandled token type: %T %+v", tkn, tkn))
   528  		}
   529  	}
   530  
   531  	// pools appear to be sorted as follows:
   532  	// * attribute names prefixed with android:
   533  	// * "android", [schema-url], [empty-string]
   534  	// * for each node:
   535  	//   * attribute names with no prefix
   536  	//   * node name
   537  	//   * attribute value if data type of name is DataString, DataAttribute, or 0x3e (an unknown)
   538  	bx.Pool = new(Pool)
   539  
   540  	var arecurse func(*Element)
   541  	arecurse = func(el *Element) {
   542  		for _, attr := range el.attrs {
   543  			if attr.NS == NoEntry {
   544  				continue
   545  			}
   546  			if attr.NS.Resolve(pool) == androidSchema {
   547  				bx.Pool.strings = append(bx.Pool.strings, attr.Name.Resolve(pool))
   548  			}
   549  		}
   550  		for _, child := range el.Children {
   551  			arecurse(child)
   552  		}
   553  	}
   554  	for _, el := range bx.Children {
   555  		arecurse(el)
   556  	}
   557  
   558  	// TODO encoding/xml does not enforce namespace prefix and manifest encoding in aapt
   559  	// appears to ignore all other prefixes. Inserting this manually is not strictly correct
   560  	// for the general case, but the effort to do otherwise currently offers nothing.
   561  	bx.Pool.strings = append(bx.Pool.strings, "android", androidSchema)
   562  
   563  	// there always appears to be an empty string located after schema, even if one is
   564  	// not present in manifest.
   565  	bx.Pool.strings = append(bx.Pool.strings, "")
   566  
   567  	var brecurse func(*Element)
   568  	brecurse = func(el *Element) {
   569  		for _, attr := range el.attrs {
   570  			if attr.NS == NoEntry {
   571  				bx.Pool.strings = append(bx.Pool.strings, attr.Name.Resolve(pool))
   572  			}
   573  		}
   574  
   575  		bx.Pool.strings = append(bx.Pool.strings, el.Name.Resolve(pool))
   576  
   577  		for _, attr := range el.attrs {
   578  			if attr.RawValue != NoEntry {
   579  				bx.Pool.strings = append(bx.Pool.strings, attr.RawValue.Resolve(pool))
   580  			} else if attr.NS == NoEntry {
   581  				bx.Pool.strings = append(bx.Pool.strings, fmt.Sprintf("%+v", attr.TypedValue.Value))
   582  			}
   583  		}
   584  
   585  		if el.head != nil {
   586  			bx.Pool.strings = append(bx.Pool.strings, el.head.RawData.Resolve(pool))
   587  		}
   588  		if el.tail != nil {
   589  			bx.Pool.strings = append(bx.Pool.strings, el.tail.RawData.Resolve(pool))
   590  		}
   591  
   592  		for _, child := range el.Children {
   593  			brecurse(child)
   594  		}
   595  	}
   596  	for _, el := range bx.Children {
   597  		brecurse(el)
   598  	}
   599  
   600  	// do not eliminate duplicates until the entire slice has been composed.
   601  	// consider <activity android:label="label" .../>
   602  	// all attribute names come first followed by values; in such a case, the value "label"
   603  	// would be a reference to the same "android:label" in the string pool which will occur
   604  	// within the beginning of the pool where other attr names are located.
   605  	bx.Pool.strings = asSet(bx.Pool.strings)
   606  
   607  	// TODO consider cases of multiple declarations of the same attr name that should return error
   608  	// before ever reaching this point.
   609  	bx.Map = new(Map)
   610  	for _, s := range bx.Pool.strings {
   611  		ref, err := tbl.RefByName("attr/" + s)
   612  		if err != nil {
   613  			break // break after first non-ref as all strings after are also non-refs.
   614  		}
   615  		bx.Map.rs = append(bx.Map.rs, ref)
   616  	}
   617  
   618  	// resolve tmp pool refs to final pool refs
   619  	// TODO drop this in favor of sort directly on Table
   620  	var resolve func(el *Element)
   621  	resolve = func(el *Element) {
   622  		if el.NS != NoEntry {
   623  			el.NS = bx.Pool.ref(el.NS.Resolve(pool))
   624  			el.end.NS = el.NS
   625  		}
   626  		el.Name = bx.Pool.ref(el.Name.Resolve(pool))
   627  		el.end.Name = el.Name
   628  		for _, attr := range el.attrs {
   629  			if attr.NS != NoEntry {
   630  				attr.NS = bx.Pool.ref(attr.NS.Resolve(pool))
   631  			}
   632  			attr.Name = bx.Pool.ref(attr.Name.Resolve(pool))
   633  			if attr.RawValue != NoEntry {
   634  				attr.RawValue = bx.Pool.ref(attr.RawValue.Resolve(pool))
   635  				if attr.TypedValue.Type == DataString {
   636  					attr.TypedValue.Value = uint32(attr.RawValue)
   637  				}
   638  			}
   639  		}
   640  		for _, child := range el.Children {
   641  			resolve(child)
   642  		}
   643  	}
   644  	for _, el := range bx.Children {
   645  		resolve(el)
   646  	}
   647  
   648  	var asort func(*Element)
   649  	asort = func(el *Element) {
   650  		sort.Sort(byType(el.attrs))
   651  		sort.Sort(byNamespace(el.attrs))
   652  		sort.Sort(byName(el.attrs))
   653  		for _, child := range el.Children {
   654  			asort(child)
   655  		}
   656  	}
   657  	for _, el := range bx.Children {
   658  		asort(el)
   659  	}
   660  
   661  	for i, s := range bx.Pool.strings {
   662  		switch s {
   663  		case androidSchema:
   664  			bx.Namespace.uri = PoolRef(i)
   665  			bx.Namespace.end.uri = PoolRef(i)
   666  		case "android":
   667  			bx.Namespace.prefix = PoolRef(i)
   668  			bx.Namespace.end.prefix = PoolRef(i)
   669  		}
   670  	}
   671  
   672  	return bx, nil
   673  }
   674  
   675  // UnmarshalBinary decodes all resource chunks in buf returning any error encountered.
   676  func (bx *XML) UnmarshalBinary(buf []byte) error {
   677  	if err := (&bx.chunkHeader).UnmarshalBinary(buf); err != nil {
   678  		return err
   679  	}
   680  	buf = buf[8:]
   681  	for len(buf) > 0 {
   682  		k, err := bx.unmarshalBinaryKind(buf)
   683  		if err != nil {
   684  			return err
   685  		}
   686  		buf = buf[k.size():]
   687  	}
   688  	return nil
   689  }
   690  
   691  // unmarshalBinaryKind decodes and stores the first resource chunk of bin.
   692  // It returns the unmarshaler interface and any error encountered.
   693  // If k.size() < len(bin), subsequent chunks can be decoded at bin[k.size():].
   694  func (bx *XML) unmarshalBinaryKind(bin []byte) (k unmarshaler, err error) {
   695  	k, err = bx.kind(ResType(btou16(bin)))
   696  	if err != nil {
   697  		return nil, err
   698  	}
   699  	if err = k.UnmarshalBinary(bin); err != nil {
   700  		return nil, err
   701  	}
   702  	return k, nil
   703  }
   704  
   705  func (bx *XML) kind(t ResType) (unmarshaler, error) {
   706  	switch t {
   707  	case ResStringPool:
   708  		if bx.Pool != nil {
   709  			return nil, fmt.Errorf("pool already exists")
   710  		}
   711  		bx.Pool = new(Pool)
   712  		return bx.Pool, nil
   713  	case ResXMLResourceMap:
   714  		if bx.Map != nil {
   715  			return nil, fmt.Errorf("resource map already exists")
   716  		}
   717  		bx.Map = new(Map)
   718  		return bx.Map, nil
   719  	case ResXMLStartNamespace:
   720  		if bx.Namespace != nil {
   721  			return nil, fmt.Errorf("namespace start already exists")
   722  		}
   723  		bx.Namespace = new(Namespace)
   724  		return bx.Namespace, nil
   725  	case ResXMLEndNamespace:
   726  		if bx.Namespace.end != nil {
   727  			return nil, fmt.Errorf("namespace end already exists")
   728  		}
   729  		bx.Namespace.end = new(Namespace)
   730  		return bx.Namespace.end, nil
   731  	case ResXMLStartElement:
   732  		el := new(Element)
   733  		if len(bx.stack) == 0 {
   734  			bx.Children = append(bx.Children, el)
   735  		} else {
   736  			n := len(bx.stack)
   737  			var p *Element
   738  			p, bx.stack = bx.stack[n-1], bx.stack[:n-1]
   739  			p.Children = append(p.Children, el)
   740  			bx.stack = append(bx.stack, p)
   741  		}
   742  		bx.stack = append(bx.stack, el)
   743  		return el, nil
   744  	case ResXMLEndElement:
   745  		n := len(bx.stack)
   746  		var el *Element
   747  		el, bx.stack = bx.stack[n-1], bx.stack[:n-1]
   748  		if el.end != nil {
   749  			return nil, fmt.Errorf("element end already exists")
   750  		}
   751  		el.end = new(ElementEnd)
   752  		return el.end, nil
   753  	case ResXMLCharData: // TODO assure correctness
   754  		cdt := new(CharData)
   755  		el := bx.stack[len(bx.stack)-1]
   756  		if el.head == nil {
   757  			el.head = cdt
   758  		} else if el.tail == nil {
   759  			el.tail = cdt
   760  		} else {
   761  			return nil, fmt.Errorf("element head and tail already contain chardata")
   762  		}
   763  		return cdt, nil
   764  	default:
   765  		return nil, fmt.Errorf("unexpected type %s", t)
   766  	}
   767  }
   768  
   769  func (bx *XML) MarshalBinary() ([]byte, error) {
   770  	bx.typ = ResXML
   771  	bx.headerByteSize = 8
   772  
   773  	var (
   774  		bin, b []byte
   775  		err    error
   776  	)
   777  	b, err = bx.chunkHeader.MarshalBinary()
   778  	if err != nil {
   779  		return nil, err
   780  	}
   781  	bin = append(bin, b...)
   782  
   783  	b, err = bx.Pool.MarshalBinary()
   784  	if err != nil {
   785  		return nil, err
   786  	}
   787  	bin = append(bin, b...)
   788  
   789  	b, err = bx.Map.MarshalBinary()
   790  	if err != nil {
   791  		return nil, err
   792  	}
   793  	bin = append(bin, b...)
   794  
   795  	b, err = bx.Namespace.MarshalBinary()
   796  	if err != nil {
   797  		return nil, err
   798  	}
   799  	bin = append(bin, b...)
   800  
   801  	for _, child := range bx.Children {
   802  		if err := marshalRecurse(child, &bin); err != nil {
   803  			return nil, err
   804  		}
   805  	}
   806  
   807  	b, err = bx.Namespace.end.MarshalBinary()
   808  	if err != nil {
   809  		return nil, err
   810  	}
   811  	bin = append(bin, b...)
   812  
   813  	putu32(bin[4:], uint32(len(bin)))
   814  	return bin, nil
   815  }
   816  
   817  func marshalRecurse(el *Element, bin *[]byte) error {
   818  	b, err := el.MarshalBinary()
   819  	if err != nil {
   820  		return err
   821  	}
   822  	*bin = append(*bin, b...)
   823  
   824  	if el.head != nil {
   825  		b, err := el.head.MarshalBinary()
   826  		if err != nil {
   827  			return err
   828  		}
   829  		*bin = append(*bin, b...)
   830  	}
   831  
   832  	for _, child := range el.Children {
   833  		if err := marshalRecurse(child, bin); err != nil {
   834  			return err
   835  		}
   836  	}
   837  
   838  	b, err = el.end.MarshalBinary()
   839  	if err != nil {
   840  		return err
   841  	}
   842  	*bin = append(*bin, b...)
   843  
   844  	return nil
   845  }
   846  
   847  func (bx *XML) iterElements() <-chan *Element {
   848  	ch := make(chan *Element, 1)
   849  	go func() {
   850  		for _, el := range bx.Children {
   851  			iterElementsRecurse(el, ch)
   852  		}
   853  		close(ch)
   854  	}()
   855  	return ch
   856  }
   857  
   858  func iterElementsRecurse(el *Element, ch chan *Element) {
   859  	ch <- el
   860  	for _, e := range el.Children {
   861  		iterElementsRecurse(e, ch)
   862  	}
   863  }
   864  
   865  // asSet returns a set from a slice of strings.
   866  func asSet(xs []string) []string {
   867  	m := make(map[string]bool)
   868  	fo := xs[:0]
   869  	for _, x := range xs {
   870  		if !m[x] {
   871  			m[x] = true
   872  			fo = append(fo, x)
   873  		}
   874  	}
   875  	return fo
   876  }
   877  
   878  // poolTrim trims all but immediately surrounding space.
   879  // \n\t\tfoobar\n\t\t becomes \tfoobar\n
   880  func poolTrim(s string) string {
   881  	var start, end int
   882  	for i, r := range s {
   883  		if !unicode.IsSpace(r) {
   884  			if i != 0 {
   885  				start = i - 1 // preserve preceding space
   886  			}
   887  			break
   888  		}
   889  	}
   890  
   891  	for i := len(s) - 1; i >= 0; i-- {
   892  		r := rune(s[i])
   893  		if !unicode.IsSpace(r) {
   894  			if i != len(s)-1 {
   895  				end = i + 2
   896  			}
   897  			break
   898  		}
   899  	}
   900  
   901  	if start == 0 && end == 0 {
   902  		return "" // every char was a space
   903  	}
   904  
   905  	return s[start:end]
   906  }
   907  
   908  // byNamespace sorts attributes based on string pool position of namespace.
   909  // Given that "android" always preceeds "" in the pool, this results in the
   910  // correct ordering of attributes.
   911  type byNamespace []*Attribute
   912  
   913  func (a byNamespace) Len() int { return len(a) }
   914  func (a byNamespace) Less(i, j int) bool {
   915  	return a[i].NS < a[j].NS
   916  }
   917  func (a byNamespace) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   918  
   919  // byType sorts attributes by the uint8 value of the type.
   920  type byType []*Attribute
   921  
   922  func (a byType) Len() int { return len(a) }
   923  func (a byType) Less(i, j int) bool {
   924  	return a[i].TypedValue.Type < a[j].TypedValue.Type
   925  }
   926  func (a byType) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   927  
   928  // byName sorts attributes that have matching types based on string pool position of name.
   929  type byName []*Attribute
   930  
   931  func (a byName) Len() int { return len(a) }
   932  func (a byName) Less(i, j int) bool {
   933  	return (a[i].TypedValue.Type == DataString || a[i].TypedValue.Type == DataIntDec) &&
   934  		(a[j].TypedValue.Type == DataString || a[j].TypedValue.Type == DataIntDec) &&
   935  		a[i].Name < a[j].Name
   936  }
   937  func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   938  
   939  type lineReader struct {
   940  	off   int64
   941  	lines []int64
   942  	r     io.Reader
   943  }
   944  
   945  func (r *lineReader) Read(p []byte) (n int, err error) {
   946  	n, err = r.r.Read(p)
   947  	for i := 0; i < n; i++ {
   948  		if p[i] == '\n' {
   949  			r.lines = append(r.lines, r.off+int64(i))
   950  		}
   951  	}
   952  	r.off += int64(n)
   953  	return n, err
   954  }
   955  
   956  func (r *lineReader) line(pos int64) int {
   957  	return sort.Search(len(r.lines), func(i int) bool {
   958  		return pos < r.lines[i]
   959  	}) + 1
   960  }