table.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  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. package binres
  5. import (
  6. "bytes"
  7. "compress/gzip"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "strings"
  12. "unicode/utf16"
  13. )
  14. const NoEntry = 0xFFFFFFFF
  15. // TableRef uniquely identifies entries within a resource table.
  16. type TableRef uint32
  17. // Resolve returns the Entry of TableRef in the given table.
  18. //
  19. // A TableRef is structured as follows:
  20. //
  21. // 0xpptteeee
  22. // pp: package index
  23. // tt: type spec index in package
  24. // eeee: entry index in type spec
  25. //
  26. // The package and type spec values start at 1 for the first item,
  27. // to help catch cases where they have not been supplied.
  28. func (ref TableRef) Resolve(tbl *Table) (*Entry, error) {
  29. pkg := tbl.pkgs[uint8(ref>>24)-1]
  30. spec := pkg.specs[uint8(ref>>16)-1]
  31. idx := uint16(ref)
  32. for _, typ := range spec.types {
  33. if idx < uint16(len(typ.entries)) {
  34. nt := typ.entries[idx]
  35. if nt == nil {
  36. return nil, errors.New("nil entry match")
  37. }
  38. return nt, nil
  39. }
  40. }
  41. return nil, errors.New("failed to resolve table reference")
  42. }
  43. // Table is a container for packaged resources. Resource values within a package
  44. // are obtained through pool while resource names and identifiers are obtained
  45. // through each package's type and key pools respectively.
  46. type Table struct {
  47. chunkHeader
  48. pool *Pool
  49. pkgs []*Package
  50. }
  51. // NewMipmapTable returns a resource table initialized for a single xxxhdpi mipmap resource
  52. // and the path to write resource data to.
  53. func NewMipmapTable(pkgname string) (*Table, string) {
  54. pkg := &Package{id: 127, name: pkgname, typePool: &Pool{}, keyPool: &Pool{}}
  55. attr := pkg.typePool.ref("attr")
  56. mipmap := pkg.typePool.ref("mipmap")
  57. icon := pkg.keyPool.ref("icon")
  58. nt := &Entry{values: []*Value{{data: &Data{Type: DataString}}}}
  59. typ := &Type{id: 2, indices: []uint32{0}, entries: []*Entry{nt}}
  60. typ.config.screenType.density = 640
  61. typ.config.version.sdk = 4
  62. pkg.specs = append(pkg.specs,
  63. &TypeSpec{
  64. id: uint8(attr) + 1, //1,
  65. },
  66. &TypeSpec{
  67. id: uint8(mipmap) + 1, //2,
  68. entryCount: 1,
  69. entries: []uint32{uint32(icon)}, // {0}
  70. types: []*Type{typ},
  71. })
  72. pkg.lastPublicType = uint32(len(pkg.typePool.strings)) // 2
  73. pkg.lastPublicKey = uint32(len(pkg.keyPool.strings)) // 1
  74. name := "res/mipmap-xxxhdpi-v4/icon.png"
  75. tbl := &Table{pool: &Pool{}, pkgs: []*Package{pkg}}
  76. tbl.pool.ref(name)
  77. return tbl, name
  78. }
  79. // OpenSDKTable decodes resources.arsc from sdk platform jar.
  80. func OpenSDKTable() (*Table, error) {
  81. bin, err := apiResources()
  82. if err != nil {
  83. return nil, err
  84. }
  85. tbl := new(Table)
  86. if err := tbl.UnmarshalBinary(bin); err != nil {
  87. return nil, err
  88. }
  89. return tbl, nil
  90. }
  91. // OpenTable decodes the prepacked resources.arsc for the supported sdk platform.
  92. func OpenTable() (*Table, error) {
  93. zr, err := gzip.NewReader(bytes.NewReader(arsc))
  94. if err != nil {
  95. return nil, fmt.Errorf("gzip: %v", err)
  96. }
  97. defer zr.Close()
  98. var buf bytes.Buffer
  99. if _, err := io.Copy(&buf, zr); err != nil {
  100. return nil, fmt.Errorf("io: %v", err)
  101. }
  102. tbl := new(Table)
  103. if err := tbl.UnmarshalBinary(buf.Bytes()); err != nil {
  104. return nil, err
  105. }
  106. return tbl, nil
  107. }
  108. // SpecByName parses the spec name from an entry string if necessary and returns
  109. // the Package and TypeSpec associated with that name along with their respective
  110. // indices.
  111. //
  112. // For example:
  113. //
  114. // tbl.SpecByName("@android:style/Theme.NoTitleBar")
  115. // tbl.SpecByName("style")
  116. //
  117. // Both locate the spec by name "style".
  118. func (tbl *Table) SpecByName(name string) (int, *Package, int, *TypeSpec, error) {
  119. n := strings.TrimPrefix(name, "@android:")
  120. n = strings.Split(n, "/")[0]
  121. for pp, pkg := range tbl.pkgs {
  122. for tt, spec := range pkg.specs {
  123. if n == pkg.typePool.strings[spec.id-1] {
  124. return pp, pkg, tt, spec, nil
  125. }
  126. }
  127. }
  128. return 0, nil, 0, nil, fmt.Errorf("spec by name not found: %q", name)
  129. }
  130. // RefByName returns the TableRef by a given name. The ref may be used to resolve the
  131. // associated Entry and is used for the generation of binary manifest files.
  132. func (tbl *Table) RefByName(name string) (TableRef, error) {
  133. pp, pkg, tt, spec, err := tbl.SpecByName(name)
  134. if err != nil {
  135. return 0, err
  136. }
  137. q := strings.Split(name, "/")
  138. if len(q) != 2 {
  139. return 0, fmt.Errorf("invalid entry format, missing forward-slash: %q", name)
  140. }
  141. n := q[1]
  142. for _, t := range spec.types {
  143. for eeee, nt := range t.entries {
  144. if nt == nil { // NoEntry
  145. continue
  146. }
  147. if n == pkg.keyPool.strings[nt.key] {
  148. return TableRef(uint32(eeee) | uint32(tt+1)<<16 | uint32(pp+1)<<24), nil
  149. }
  150. }
  151. }
  152. return 0, fmt.Errorf("failed to find table ref by %q", name)
  153. }
  154. func (tbl *Table) UnmarshalBinary(bin []byte) error {
  155. if err := (&tbl.chunkHeader).UnmarshalBinary(bin); err != nil {
  156. return err
  157. }
  158. if tbl.typ != ResTable {
  159. return fmt.Errorf("unexpected resource type %s, want %s", tbl.typ, ResTable)
  160. }
  161. npkgs := btou32(bin[8:])
  162. tbl.pkgs = make([]*Package, npkgs)
  163. buf := bin[tbl.headerByteSize:]
  164. tbl.pool = new(Pool)
  165. if err := tbl.pool.UnmarshalBinary(buf); err != nil {
  166. return err
  167. }
  168. buf = buf[tbl.pool.size():]
  169. for i := range tbl.pkgs {
  170. pkg := new(Package)
  171. if err := pkg.UnmarshalBinary(buf); err != nil {
  172. return err
  173. }
  174. tbl.pkgs[i] = pkg
  175. buf = buf[pkg.byteSize:]
  176. }
  177. return nil
  178. }
  179. func (tbl *Table) MarshalBinary() ([]byte, error) {
  180. bin := make([]byte, 12)
  181. putu16(bin, uint16(ResTable))
  182. putu16(bin[2:], 12)
  183. putu32(bin[8:], uint32(len(tbl.pkgs)))
  184. if tbl.pool.IsUTF8() {
  185. tbl.pool.flags ^= UTF8Flag
  186. defer func() {
  187. tbl.pool.flags |= UTF8Flag
  188. }()
  189. }
  190. b, err := tbl.pool.MarshalBinary()
  191. if err != nil {
  192. return nil, err
  193. }
  194. bin = append(bin, b...)
  195. for _, pkg := range tbl.pkgs {
  196. b, err = pkg.MarshalBinary()
  197. if err != nil {
  198. return nil, err
  199. }
  200. bin = append(bin, b...)
  201. }
  202. putu32(bin[4:], uint32(len(bin)))
  203. return bin, nil
  204. }
  205. // Package contains a collection of resource data types.
  206. type Package struct {
  207. chunkHeader
  208. id uint32
  209. name string
  210. lastPublicType uint32 // last index into typePool that is for public use
  211. lastPublicKey uint32 // last index into keyPool that is for public use
  212. typePool *Pool // type names; e.g. theme
  213. keyPool *Pool // resource names; e.g. Theme.NoTitleBar
  214. aliases []*StagedAlias
  215. specs []*TypeSpec
  216. }
  217. func (pkg *Package) UnmarshalBinary(bin []byte) error {
  218. if err := (&pkg.chunkHeader).UnmarshalBinary(bin); err != nil {
  219. return err
  220. }
  221. if pkg.typ != ResTablePackage {
  222. return errWrongType(pkg.typ, ResTablePackage)
  223. }
  224. pkg.id = btou32(bin[8:])
  225. var name []uint16
  226. for i := 0; i < 128; i++ {
  227. x := btou16(bin[12+i*2:])
  228. if x == 0 {
  229. break
  230. }
  231. name = append(name, x)
  232. }
  233. pkg.name = string(utf16.Decode(name))
  234. typeOffset := btou32(bin[268:]) // 0 if inheriting from another package
  235. pkg.lastPublicType = btou32(bin[272:])
  236. keyOffset := btou32(bin[276:]) // 0 if inheriting from another package
  237. pkg.lastPublicKey = btou32(bin[280:])
  238. var idOffset uint32 // value determined by either typePool or keyPool below
  239. if typeOffset != 0 {
  240. pkg.typePool = new(Pool)
  241. if err := pkg.typePool.UnmarshalBinary(bin[typeOffset:]); err != nil {
  242. return err
  243. }
  244. idOffset = typeOffset + pkg.typePool.byteSize
  245. }
  246. if keyOffset != 0 {
  247. pkg.keyPool = new(Pool)
  248. if err := pkg.keyPool.UnmarshalBinary(bin[keyOffset:]); err != nil {
  249. return err
  250. }
  251. idOffset = keyOffset + pkg.keyPool.byteSize
  252. }
  253. if idOffset == 0 {
  254. return nil
  255. }
  256. buf := bin[idOffset:pkg.byteSize]
  257. for len(buf) > 0 {
  258. t := ResType(btou16(buf))
  259. switch t {
  260. case ResTableTypeSpec:
  261. spec := new(TypeSpec)
  262. if err := spec.UnmarshalBinary(buf); err != nil {
  263. return err
  264. }
  265. pkg.specs = append(pkg.specs, spec)
  266. buf = buf[spec.byteSize:]
  267. case ResTableType:
  268. typ := new(Type)
  269. if err := typ.UnmarshalBinary(buf); err != nil {
  270. return err
  271. }
  272. last := pkg.specs[len(pkg.specs)-1]
  273. last.types = append(last.types, typ)
  274. buf = buf[typ.byteSize:]
  275. case ResTableStagedAlias:
  276. alias := new(StagedAlias)
  277. if err := alias.UnmarshalBinary(buf); err != nil {
  278. return err
  279. }
  280. pkg.aliases = append(pkg.aliases, alias)
  281. buf = buf[alias.byteSize:]
  282. default:
  283. return errWrongType(t, ResTableTypeSpec, ResTableType, ResTableStagedAlias)
  284. }
  285. }
  286. return nil
  287. }
  288. func (pkg *Package) MarshalBinary() ([]byte, error) {
  289. // Package header size is determined by C++ struct ResTable_package
  290. // see frameworks/base/include/ResourceTypes.h
  291. bin := make([]byte, 288)
  292. putu16(bin, uint16(ResTablePackage))
  293. putu16(bin[2:], 288)
  294. putu32(bin[8:], pkg.id)
  295. p := utf16.Encode([]rune(pkg.name))
  296. for i, x := range p {
  297. putu16(bin[12+i*2:], x)
  298. }
  299. if pkg.typePool != nil {
  300. if pkg.typePool.IsUTF8() {
  301. pkg.typePool.flags ^= UTF8Flag
  302. defer func() {
  303. pkg.typePool.flags |= UTF8Flag
  304. }()
  305. }
  306. b, err := pkg.typePool.MarshalBinary()
  307. if err != nil {
  308. return nil, err
  309. }
  310. putu32(bin[268:], uint32(len(bin)))
  311. putu32(bin[272:], pkg.lastPublicType)
  312. bin = append(bin, b...)
  313. }
  314. if pkg.keyPool != nil {
  315. if pkg.keyPool.IsUTF8() {
  316. pkg.keyPool.flags ^= UTF8Flag
  317. defer func() {
  318. pkg.keyPool.flags |= UTF8Flag
  319. }()
  320. }
  321. b, err := pkg.keyPool.MarshalBinary()
  322. if err != nil {
  323. return nil, err
  324. }
  325. putu32(bin[276:], uint32(len(bin)))
  326. putu32(bin[280:], pkg.lastPublicKey)
  327. bin = append(bin, b...)
  328. }
  329. for _, alias := range pkg.aliases {
  330. b, err := alias.MarshalBinary()
  331. if err != nil {
  332. return nil, err
  333. }
  334. bin = append(bin, b...)
  335. }
  336. for _, spec := range pkg.specs {
  337. b, err := spec.MarshalBinary()
  338. if err != nil {
  339. return nil, err
  340. }
  341. bin = append(bin, b...)
  342. }
  343. putu32(bin[4:], uint32(len(bin)))
  344. return bin, nil
  345. }
  346. // TypeSpec provides a specification for the resources defined by a particular type.
  347. type TypeSpec struct {
  348. chunkHeader
  349. id uint8 // id-1 is name index in Package.typePool
  350. res0 uint8 // must be 0
  351. res1 uint16 // must be 0
  352. entryCount uint32 // number of uint32 entry configuration masks that follow
  353. entries []uint32 // entry configuration masks
  354. types []*Type
  355. }
  356. func (spec *TypeSpec) UnmarshalBinary(bin []byte) error {
  357. if err := (&spec.chunkHeader).UnmarshalBinary(bin); err != nil {
  358. return err
  359. }
  360. if spec.typ != ResTableTypeSpec {
  361. return errWrongType(spec.typ, ResTableTypeSpec)
  362. }
  363. spec.id = uint8(bin[8])
  364. spec.res0 = uint8(bin[9])
  365. spec.res1 = btou16(bin[10:])
  366. spec.entryCount = btou32(bin[12:])
  367. spec.entries = make([]uint32, spec.entryCount)
  368. for i := range spec.entries {
  369. spec.entries[i] = btou32(bin[16+i*4:])
  370. }
  371. return nil
  372. }
  373. func (spec *TypeSpec) MarshalBinary() ([]byte, error) {
  374. bin := make([]byte, 16+len(spec.entries)*4)
  375. putu16(bin, uint16(ResTableTypeSpec))
  376. putu16(bin[2:], 16)
  377. putu32(bin[4:], uint32(len(bin)))
  378. bin[8] = byte(spec.id)
  379. // [9] = 0
  380. // [10:12] = 0
  381. putu32(bin[12:], uint32(len(spec.entries)))
  382. for i, x := range spec.entries {
  383. putu32(bin[16+i*4:], x)
  384. }
  385. for _, typ := range spec.types {
  386. b, err := typ.MarshalBinary()
  387. if err != nil {
  388. return nil, err
  389. }
  390. bin = append(bin, b...)
  391. }
  392. return bin, nil
  393. }
  394. // Type provides a collection of entries for a specific device configuration.
  395. type Type struct {
  396. chunkHeader
  397. id uint8
  398. res0 uint8 // must be 0
  399. res1 uint16 // must be 0
  400. entryCount uint32 // number of uint32 entry configuration masks that follow
  401. entriesStart uint32 // offset from header where Entry data starts
  402. // configuration this collection of entries is designed for
  403. config struct {
  404. size uint32
  405. imsi struct {
  406. mcc uint16 // mobile country code
  407. mnc uint16 // mobile network code
  408. }
  409. locale struct {
  410. language uint16
  411. country uint16
  412. }
  413. screenType struct {
  414. orientation uint8
  415. touchscreen uint8
  416. density uint16
  417. }
  418. input struct {
  419. keyboard uint8
  420. navigation uint8
  421. inputFlags uint8
  422. inputPad0 uint8
  423. }
  424. screenSize struct {
  425. width uint16
  426. height uint16
  427. }
  428. version struct {
  429. sdk uint16
  430. minor uint16 // always 0
  431. }
  432. screenConfig struct {
  433. layout uint8
  434. uiMode uint8
  435. smallestWidthDP uint16
  436. }
  437. screenSizeDP struct {
  438. width uint16
  439. height uint16
  440. }
  441. }
  442. indices []uint32 // values that map to typePool
  443. entries []*Entry
  444. }
  445. func (typ *Type) UnmarshalBinary(bin []byte) error {
  446. if err := (&typ.chunkHeader).UnmarshalBinary(bin); err != nil {
  447. return err
  448. }
  449. if typ.typ != ResTableType {
  450. return errWrongType(typ.typ, ResTableType)
  451. }
  452. typ.id = uint8(bin[8])
  453. typ.res0 = uint8(bin[9])
  454. typ.res1 = btou16(bin[10:])
  455. typ.entryCount = btou32(bin[12:])
  456. typ.entriesStart = btou32(bin[16:])
  457. if typ.res0 != 0 || typ.res1 != 0 {
  458. return fmt.Errorf("res0 res1 not zero")
  459. }
  460. typ.config.size = btou32(bin[20:])
  461. typ.config.imsi.mcc = btou16(bin[24:])
  462. typ.config.imsi.mnc = btou16(bin[26:])
  463. typ.config.locale.language = btou16(bin[28:])
  464. typ.config.locale.country = btou16(bin[30:])
  465. typ.config.screenType.orientation = uint8(bin[32])
  466. typ.config.screenType.touchscreen = uint8(bin[33])
  467. typ.config.screenType.density = btou16(bin[34:])
  468. typ.config.input.keyboard = uint8(bin[36])
  469. typ.config.input.navigation = uint8(bin[37])
  470. typ.config.input.inputFlags = uint8(bin[38])
  471. typ.config.input.inputPad0 = uint8(bin[39])
  472. typ.config.screenSize.width = btou16(bin[40:])
  473. typ.config.screenSize.height = btou16(bin[42:])
  474. typ.config.version.sdk = btou16(bin[44:])
  475. typ.config.version.minor = btou16(bin[46:])
  476. typ.config.screenConfig.layout = uint8(bin[48])
  477. typ.config.screenConfig.uiMode = uint8(bin[49])
  478. typ.config.screenConfig.smallestWidthDP = btou16(bin[50:])
  479. typ.config.screenSizeDP.width = btou16(bin[52:])
  480. typ.config.screenSizeDP.height = btou16(bin[54:])
  481. // fmt.Println("language/country:", u16tos(typ.config.locale.language), u16tos(typ.config.locale.country))
  482. buf := bin[typ.headerByteSize:typ.entriesStart]
  483. if len(buf) != 4*int(typ.entryCount) {
  484. return fmt.Errorf("index buffer len[%v] doesn't match entryCount[%v]", len(buf), typ.entryCount)
  485. }
  486. typ.indices = make([]uint32, typ.entryCount)
  487. for i := range typ.indices {
  488. typ.indices[i] = btou32(buf[i*4:])
  489. }
  490. typ.entries = make([]*Entry, typ.entryCount)
  491. for i, x := range typ.indices {
  492. if x == NoEntry {
  493. continue
  494. }
  495. nt := &Entry{}
  496. if err := nt.UnmarshalBinary(bin[typ.entriesStart+x:]); err != nil {
  497. return err
  498. }
  499. typ.entries[i] = nt
  500. }
  501. return nil
  502. }
  503. func (typ *Type) MarshalBinary() ([]byte, error) {
  504. bin := make([]byte, 56+len(typ.entries)*4)
  505. putu16(bin, uint16(ResTableType))
  506. putu16(bin[2:], 56)
  507. bin[8] = byte(typ.id)
  508. // [9] = 0
  509. // [10:12] = 0
  510. putu32(bin[12:], uint32(len(typ.entries)))
  511. putu32(bin[16:], uint32(56+len(typ.entries)*4))
  512. // assure typ.config.size is always written as 36; extended configuration beyond supported
  513. // API level is not supported by this marshal implementation but will be forward-compatible.
  514. putu32(bin[20:], 36)
  515. putu16(bin[24:], typ.config.imsi.mcc)
  516. putu16(bin[26:], typ.config.imsi.mnc)
  517. putu16(bin[28:], typ.config.locale.language)
  518. putu16(bin[30:], typ.config.locale.country)
  519. bin[32] = typ.config.screenType.orientation
  520. bin[33] = typ.config.screenType.touchscreen
  521. putu16(bin[34:], typ.config.screenType.density)
  522. bin[36] = typ.config.input.keyboard
  523. bin[37] = typ.config.input.navigation
  524. bin[38] = typ.config.input.inputFlags
  525. bin[39] = typ.config.input.inputPad0
  526. putu16(bin[40:], typ.config.screenSize.width)
  527. putu16(bin[42:], typ.config.screenSize.height)
  528. putu16(bin[44:], typ.config.version.sdk)
  529. putu16(bin[46:], typ.config.version.minor)
  530. bin[48] = typ.config.screenConfig.layout
  531. bin[49] = typ.config.screenConfig.uiMode
  532. putu16(bin[50:], typ.config.screenConfig.smallestWidthDP)
  533. putu16(bin[52:], typ.config.screenSizeDP.width)
  534. putu16(bin[54:], typ.config.screenSizeDP.height)
  535. var ntbin []byte
  536. for i, nt := range typ.entries {
  537. if nt == nil { // NoEntry
  538. putu32(bin[56+i*4:], NoEntry)
  539. continue
  540. }
  541. putu32(bin[56+i*4:], uint32(len(ntbin)))
  542. b, err := nt.MarshalBinary()
  543. if err != nil {
  544. return nil, err
  545. }
  546. ntbin = append(ntbin, b...)
  547. }
  548. bin = append(bin, ntbin...)
  549. putu32(bin[4:], uint32(len(bin)))
  550. return bin, nil
  551. }
  552. type StagedAliasEntry struct {
  553. stagedID uint32
  554. finalizedID uint32
  555. }
  556. func (ae *StagedAliasEntry) MarshalBinary() ([]byte, error) {
  557. bin := make([]byte, 8)
  558. putu32(bin, ae.stagedID)
  559. putu32(bin[4:], ae.finalizedID)
  560. return bin, nil
  561. }
  562. func (ae *StagedAliasEntry) UnmarshalBinary(bin []byte) error {
  563. ae.stagedID = btou32(bin)
  564. ae.finalizedID = btou32(bin[4:])
  565. return nil
  566. }
  567. type StagedAlias struct {
  568. chunkHeader
  569. count uint32
  570. entries []StagedAliasEntry
  571. }
  572. func (a *StagedAlias) UnmarshalBinary(bin []byte) error {
  573. if err := (&a.chunkHeader).UnmarshalBinary(bin); err != nil {
  574. return err
  575. }
  576. if a.typ != ResTableStagedAlias {
  577. return errWrongType(a.typ, ResTableStagedAlias)
  578. }
  579. a.count = btou32(bin[8:])
  580. a.entries = make([]StagedAliasEntry, a.count)
  581. for i := range a.entries {
  582. if err := a.entries[i].UnmarshalBinary(bin[12+i*8:]); err != nil {
  583. return err
  584. }
  585. }
  586. return nil
  587. }
  588. func (a *StagedAlias) MarshalBinary() ([]byte, error) {
  589. chunkHeaderBin, err := a.chunkHeader.MarshalBinary()
  590. if err != nil {
  591. return nil, err
  592. }
  593. countBin := make([]byte, 4)
  594. putu32(countBin, a.count)
  595. bin := append(chunkHeaderBin, countBin...)
  596. for _, entry := range a.entries {
  597. entryBin, err := entry.MarshalBinary()
  598. if err != nil {
  599. return nil, err
  600. }
  601. bin = append(bin, entryBin...)
  602. }
  603. return bin, nil
  604. }
  605. // Entry is a resource key typically followed by a value or resource map.
  606. type Entry struct {
  607. size uint16
  608. flags uint16
  609. key PoolRef // ref into key pool
  610. // only filled if this is a map entry; when size is 16
  611. parent TableRef // id of parent mapping or zero if none
  612. count uint32 // name and value pairs that follow for FlagComplex
  613. values []*Value
  614. }
  615. func (nt *Entry) UnmarshalBinary(bin []byte) error {
  616. nt.size = btou16(bin)
  617. nt.flags = btou16(bin[2:])
  618. nt.key = PoolRef(btou32(bin[4:]))
  619. if nt.size == 16 {
  620. nt.parent = TableRef(btou32(bin[8:]))
  621. nt.count = btou32(bin[12:])
  622. nt.values = make([]*Value, nt.count)
  623. for i := range nt.values {
  624. val := &Value{}
  625. if err := val.UnmarshalBinary(bin[16+i*12:]); err != nil {
  626. return err
  627. }
  628. nt.values[i] = val
  629. }
  630. } else {
  631. data := &Data{}
  632. if err := data.UnmarshalBinary(bin[8:]); err != nil {
  633. return err
  634. }
  635. // TODO boxing data not strictly correct as binary repr isn't of Value.
  636. nt.values = append(nt.values, &Value{0, data})
  637. }
  638. return nil
  639. }
  640. func (nt *Entry) MarshalBinary() ([]byte, error) {
  641. bin := make([]byte, 8)
  642. sz := nt.size
  643. if sz == 0 {
  644. sz = 8
  645. }
  646. putu16(bin, sz)
  647. putu16(bin[2:], nt.flags)
  648. putu32(bin[4:], uint32(nt.key))
  649. if sz == 16 {
  650. bin = append(bin, make([]byte, 8+len(nt.values)*12)...)
  651. putu32(bin[8:], uint32(nt.parent))
  652. putu32(bin[12:], uint32(len(nt.values)))
  653. for i, val := range nt.values {
  654. b, err := val.MarshalBinary()
  655. if err != nil {
  656. return nil, err
  657. }
  658. copy(bin[16+i*12:], b)
  659. }
  660. } else {
  661. b, err := nt.values[0].data.MarshalBinary()
  662. if err != nil {
  663. return nil, err
  664. }
  665. bin = append(bin, b...)
  666. }
  667. return bin, nil
  668. }
  669. type Value struct {
  670. name TableRef
  671. data *Data
  672. }
  673. func (val *Value) UnmarshalBinary(bin []byte) error {
  674. val.name = TableRef(btou32(bin))
  675. val.data = &Data{}
  676. return val.data.UnmarshalBinary(bin[4:])
  677. }
  678. func (val *Value) MarshalBinary() ([]byte, error) {
  679. bin := make([]byte, 12)
  680. putu32(bin, uint32(val.name))
  681. b, err := val.data.MarshalBinary()
  682. if err != nil {
  683. return nil, err
  684. }
  685. copy(bin[4:], b)
  686. return bin, nil
  687. }
  688. type DataType uint8
  689. // explicitly defined for clarity and resolvability with apt source
  690. const (
  691. DataNull DataType = 0x00 // either 0 or 1 for resource undefined or empty
  692. DataReference DataType = 0x01 // ResTable_ref, a reference to another resource table entry
  693. DataAttribute DataType = 0x02 // attribute resource identifier
  694. DataString DataType = 0x03 // index into the containing resource table's global value string pool
  695. DataFloat DataType = 0x04 // single-precision floating point number
  696. DataDimension DataType = 0x05 // complex number encoding a dimension value, such as "100in"
  697. DataFraction DataType = 0x06 // complex number encoding a fraction of a container
  698. DataDynamicReference DataType = 0x07 // dynamic ResTable_ref, which needs to be resolved before it can be used like a TYPE_REFERENCE.
  699. DataIntDec DataType = 0x10 // raw integer value of the form n..n
  700. DataIntHex DataType = 0x11 // raw integer value of the form 0xn..n
  701. DataIntBool DataType = 0x12 // either 0 or 1, for input "false" or "true"
  702. DataIntColorARGB8 DataType = 0x1c // raw integer value of the form #aarrggbb
  703. DataIntColorRGB8 DataType = 0x1d // raw integer value of the form #rrggbb
  704. DataIntColorARGB4 DataType = 0x1e // raw integer value of the form #argb
  705. DataIntColorRGB4 DataType = 0x1f // raw integer value of the form #rgb
  706. )
  707. type Data struct {
  708. ByteSize uint16
  709. Res0 uint8 // always 0, useful for debugging bad read offsets
  710. Type DataType
  711. Value uint32
  712. }
  713. func (d *Data) UnmarshalBinary(bin []byte) error {
  714. d.ByteSize = btou16(bin)
  715. d.Res0 = uint8(bin[2])
  716. d.Type = DataType(bin[3])
  717. d.Value = btou32(bin[4:])
  718. return nil
  719. }
  720. func (d *Data) MarshalBinary() ([]byte, error) {
  721. bin := make([]byte, 8)
  722. putu16(bin, 8)
  723. bin[2] = byte(d.Res0)
  724. bin[3] = byte(d.Type)
  725. putu32(bin[4:], d.Value)
  726. return bin, nil
  727. }