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