github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/internal/binres/binres_test.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 package binres 6 7 import ( 8 "archive/zip" 9 "bytes" 10 "encoding" 11 "encoding/xml" 12 "fmt" 13 "io" 14 "io/ioutil" 15 "log" 16 "math" 17 "os" 18 "sort" 19 "strings" 20 "testing" 21 ) 22 23 func printrecurse(t *testing.T, pl *Pool, el *Element, ws string) { 24 for _, attr := range el.attrs { 25 ns := "" 26 if attr.NS != math.MaxUint32 { 27 ns = pl.strings[int(attr.NS)] 28 nss := strings.Split(ns, "/") 29 ns = nss[len(nss)-1] 30 } 31 32 val := "" 33 if attr.RawValue != math.MaxUint32 { 34 val = pl.strings[int(attr.RawValue)] 35 } else { 36 switch attr.TypedValue.Type { 37 case DataIntDec: 38 val = fmt.Sprintf("%v", attr.TypedValue.Value) 39 case DataIntBool: 40 val = fmt.Sprintf("%v", attr.TypedValue.Value == 1) 41 default: 42 val = fmt.Sprintf("0x%08X", attr.TypedValue.Value) 43 } 44 } 45 dt := attr.TypedValue.Type 46 47 t.Logf("%s|attr:ns(%v) name(%s) val(%s) valtyp(%s)\n", ws, ns, pl.strings[int(attr.Name)], val, dt) 48 } 49 t.Log() 50 for _, e := range el.Children { 51 printrecurse(t, pl, e, ws+" ") 52 } 53 } 54 55 func TestBootstrap(t *testing.T) { 56 bin, err := ioutil.ReadFile("testdata/bootstrap.bin") 57 if err != nil { 58 log.Fatal(err) 59 } 60 61 checkMarshal := func(res encoding.BinaryMarshaler, bsize int) { 62 b, err := res.MarshalBinary() 63 if err != nil { 64 t.Error(err) 65 } 66 idx := debugIndices[res] 67 a := bin[idx : idx+bsize] 68 if !bytes.Equal(a, b) { 69 x, y := len(a), len(b) 70 if x != y { 71 t.Errorf("%v: %T: byte length does not match, have %v, want %v", idx, res, y, x) 72 } 73 if x > y { 74 x, y = y, x 75 } 76 mismatch := false 77 for i := 0; i < x; i++ { 78 if mismatch = a[i] != b[i]; mismatch { 79 t.Errorf("%v: %T: first byte mismatch at %v of %v", idx, res, i, bsize) 80 break 81 } 82 } 83 if mismatch { 84 // print out a reasonable amount of data to help identify issues 85 truncate := x > 1300 86 if truncate { 87 x = 1300 88 } 89 t.Log(" HAVE WANT") 90 for i := 0; i < x; i += 4 { 91 he, we := 4, 4 92 if i+he >= x { 93 he = x - i 94 } 95 if i+we >= y { 96 we = y - i 97 } 98 t.Logf("%3v | % X % X\n", i, b[i:i+he], a[i:i+we]) 99 } 100 if truncate { 101 t.Log("... output truncated.") 102 } 103 } 104 } 105 } 106 107 bxml := new(XML) 108 if err := bxml.UnmarshalBinary(bin); err != nil { 109 t.Fatal(err) 110 } 111 112 for i, x := range bxml.Pool.strings { 113 t.Logf("Pool(%v): %q\n", i, x) 114 } 115 116 for _, e := range bxml.Children { 117 printrecurse(t, bxml.Pool, e, "") 118 } 119 120 checkMarshal(&bxml.chunkHeader, int(bxml.headerByteSize)) 121 checkMarshal(bxml.Pool, bxml.Pool.size()) 122 checkMarshal(bxml.Map, bxml.Map.size()) 123 checkMarshal(bxml.Namespace, bxml.Namespace.size()) 124 125 for el := range bxml.iterElements() { 126 checkMarshal(el, el.size()) 127 checkMarshal(el.end, el.end.size()) 128 } 129 130 checkMarshal(bxml.Namespace.end, bxml.Namespace.end.size()) 131 checkMarshal(bxml, bxml.size()) 132 } 133 134 func retset(xs []string) []string { 135 m := make(map[string]struct{}) 136 fo := xs[:0] 137 for _, x := range xs { 138 if x == "" { 139 continue 140 } 141 if _, ok := m[x]; !ok { 142 m[x] = struct{}{} 143 fo = append(fo, x) 144 } 145 } 146 return fo 147 } 148 149 type ByNamespace []xml.Attr 150 151 func (a ByNamespace) Len() int { return len(a) } 152 func (a ByNamespace) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 153 func (a ByNamespace) Less(i, j int) bool { 154 if a[j].Name.Space == "" { 155 return a[i].Name.Space != "" 156 } 157 return false 158 } 159 160 // WIP approximation of first steps to be taken to encode manifest 161 func TestEncode(t *testing.T) { 162 f, err := os.Open("testdata/bootstrap.xml") 163 if err != nil { 164 t.Fatal(err) 165 } 166 167 var attrs []xml.Attr 168 169 dec := xml.NewDecoder(f) 170 for { 171 tkn, err := dec.Token() 172 if err != nil { 173 if err == io.EOF { 174 break 175 } 176 return 177 // t.Fatal(err) 178 } 179 tkn = xml.CopyToken(tkn) 180 181 switch tkn := tkn.(type) { 182 case xml.StartElement: 183 attrs = append(attrs, tkn.Attr...) 184 default: 185 // t.Error("unhandled token type", tkn) 186 } 187 } 188 189 bvc := xml.Attr{ 190 Name: xml.Name{ 191 Space: "", 192 Local: "platformBuildVersionCode", 193 }, 194 Value: "10", 195 } 196 bvn := xml.Attr{ 197 Name: xml.Name{ 198 Space: "", 199 Local: "platformBuildVersionName", 200 }, 201 Value: "2.3.3", 202 } 203 attrs = append(attrs, bvc, bvn) 204 205 sort.Sort(ByNamespace(attrs)) 206 var names, vals []string 207 for _, attr := range attrs { 208 if strings.HasSuffix(attr.Name.Space, "tools") { 209 continue 210 } 211 names = append(names, attr.Name.Local) 212 vals = append(vals, attr.Value) 213 } 214 215 var all []string 216 all = append(all, names...) 217 all = append(all, vals...) 218 219 // do not eliminate duplicates until the entire slice has been composed. 220 // consider <activity android:label="label" .../> 221 // all attribute names come first followed by values; in such a case, the value "label" 222 // would be a reference to the same "android:label" in the string pool which will occur 223 // within the beginning of the pool where other attr names are located. 224 pl := new(Pool) 225 for _, x := range retset(all) { 226 pl.strings = append(pl.strings, x) 227 // t.Logf("Pool(%v) %q\n", i, x) 228 } 229 } 230 231 func TestAndroidJar(t *testing.T) { 232 zr, err := zip.OpenReader("/home/daniel/local/android-sdk/platforms/android-10/android.jar") 233 if err != nil { 234 t.Fatal(err) 235 } 236 defer zr.Close() 237 238 buf := new(bytes.Buffer) 239 for _, f := range zr.File { 240 if f.Name == "resources.arsc" { 241 rc, err := f.Open() 242 if err != nil { 243 t.Fatal(err) 244 } 245 _, err = io.Copy(buf, rc) 246 if err != nil { 247 t.Fatal(err) 248 } 249 rc.Close() 250 break 251 } 252 } 253 if buf.Len() == 0 { 254 t.Fatal("failed to read resources.arsc") 255 } 256 257 bin := buf.Bytes() 258 259 tbl := &Table{} 260 if err := tbl.UnmarshalBinary(bin); err != nil { 261 t.Fatal(err) 262 } 263 264 t.Logf("%+v\n", tbl.TableHeader) 265 t.Logf("%+v\n", tbl.pool.chunkHeader) 266 for i, x := range tbl.pool.strings[:10] { 267 t.Logf("pool(%v) %s\n", i, x) 268 } 269 270 t.Logf("%+v\n", tbl.pkg) 271 }