table.go 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. package android_binary
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "io"
  6. "strconv"
  7. "strings"
  8. "unsafe"
  9. )
  10. // ResID is ID for resources.
  11. type ResID uint32
  12. // TableFile is a resource table file.
  13. type TableFile struct {
  14. stringPool *ResStringPool
  15. tablePackages map[uint32]*TablePackage
  16. }
  17. // ResTableHeader is a header of TableFile.
  18. type ResTableHeader struct {
  19. Header ResChunkHeader
  20. PackageCount uint32
  21. }
  22. // ResTablePackage is a header of table packages.
  23. type ResTablePackage struct {
  24. Header ResChunkHeader
  25. ID uint32
  26. Name [128]uint16
  27. TypeStrings uint32
  28. LastPublicType uint32
  29. KeyStrings uint32
  30. LastPublicKey uint32
  31. }
  32. // TablePackage is a table package.
  33. type TablePackage struct {
  34. Header ResTablePackage
  35. TypeStrings *ResStringPool
  36. KeyStrings *ResStringPool
  37. TableTypes []*TableType
  38. }
  39. // ResTableType is a type of a table.
  40. type ResTableType struct {
  41. Header ResChunkHeader
  42. ID uint8
  43. Res0 uint8
  44. Res1 uint16
  45. EntryCount uint32
  46. EntriesStart uint32
  47. Config ResTableConfig
  48. }
  49. // ScreenLayout describes screen layout.
  50. type ScreenLayout uint8
  51. // ScreenLayout bits
  52. const (
  53. MaskScreenSize ScreenLayout = 0x0f
  54. ScreenSizeAny ScreenLayout = 0x01
  55. ScreenSizeSmall ScreenLayout = 0x02
  56. ScreenSizeNormal ScreenLayout = 0x03
  57. ScreenSizeLarge ScreenLayout = 0x04
  58. ScreenSizeXLarge ScreenLayout = 0x05
  59. MaskScreenLong ScreenLayout = 0x30
  60. ShiftScreenLong = 4
  61. ScreenLongAny ScreenLayout = 0x00
  62. ScreenLongNo ScreenLayout = 0x10
  63. ScreenLongYes ScreenLayout = 0x20
  64. MaskLayoutDir ScreenLayout = 0xC0
  65. ShiftLayoutDir = 6
  66. LayoutDirAny ScreenLayout = 0x00
  67. LayoutDirLTR ScreenLayout = 0x40
  68. LayoutDirRTL ScreenLayout = 0x80
  69. )
  70. // UIMode describes UI mode.
  71. type UIMode uint8
  72. // UIMode bits
  73. const (
  74. MaskUIModeType UIMode = 0x0f
  75. UIModeTypeAny UIMode = 0x01
  76. UIModeTypeNormal UIMode = 0x02
  77. UIModeTypeDesk UIMode = 0x03
  78. UIModeTypeCar UIMode = 0x04
  79. MaskUIModeNight UIMode = 0x30
  80. ShiftUIModeNight = 4
  81. UIModeNightAny UIMode = 0x00
  82. UIModeNightNo UIMode = 0x10
  83. UIModeNightYes UIMode = 0x20
  84. )
  85. // InputFlags are input flags.
  86. type InputFlags uint8
  87. // input flags
  88. const (
  89. MaskKeysHidden InputFlags = 0x03
  90. KeysHiddenAny InputFlags = 0x00
  91. KeysHiddenNo InputFlags = 0x01
  92. KeysHiddenYes InputFlags = 0x02
  93. KeysHiddenSoft InputFlags = 0x03
  94. MaskNavHidden InputFlags = 0x0c
  95. NavHiddenAny InputFlags = 0x00
  96. NavHiddenNo InputFlags = 0x04
  97. NavHiddenYes InputFlags = 0x08
  98. )
  99. // ResTableConfig is a configuration of a table.
  100. type ResTableConfig struct {
  101. Size uint32
  102. // imsi
  103. Mcc uint16
  104. Mnc uint16
  105. // locale
  106. Language [2]uint8
  107. Country [2]uint8
  108. // screen type
  109. Orientation uint8
  110. Touchscreen uint8
  111. Density uint16
  112. // inout
  113. Keyboard uint8
  114. Navigation uint8
  115. InputFlags InputFlags
  116. InputPad0 uint8
  117. // screen size
  118. ScreenWidth uint16
  119. ScreenHeight uint16
  120. // version
  121. SDKVersion uint16
  122. MinorVersion uint16
  123. // screen config
  124. ScreenLayout ScreenLayout
  125. UIMode UIMode
  126. SmallestScreenWidthDp uint16
  127. // screen size dp
  128. ScreenWidthDp uint16
  129. ScreenHeightDp uint16
  130. }
  131. // TableType is a collection of resource entries for a particular resource data type.
  132. type TableType struct {
  133. Header *ResTableType
  134. Entries []TableEntry
  135. }
  136. // ResTableEntry is the beginning of information about an entry in the resource table.
  137. type ResTableEntry struct {
  138. Size uint16
  139. Flags uint16
  140. Key ResStringPoolRef
  141. }
  142. // TableEntry is a entry in a resource table.
  143. type TableEntry struct {
  144. Key *ResTableEntry
  145. Value *ResValue
  146. Flags uint32
  147. }
  148. // ResTableTypeSpec is specification of the resources defined by a particular type.
  149. type ResTableTypeSpec struct {
  150. Header ResChunkHeader
  151. ID uint8
  152. Res0 uint8
  153. Res1 uint16
  154. EntryCount uint32
  155. }
  156. // IsResID returns whether s is ResId.
  157. func IsResID(s string) bool {
  158. return strings.HasPrefix(s, "@0x")
  159. }
  160. // ParseResID parses ResId.
  161. func ParseResID(s string) (ResID, error) {
  162. if !IsResID(s) {
  163. return 0, fmt.Errorf("androidbinary: %s is not ResID", s)
  164. }
  165. id, err := strconv.ParseUint(s[3:], 16, 32)
  166. if err != nil {
  167. return 0, err
  168. }
  169. return ResID(id), nil
  170. }
  171. func (id ResID) String() string {
  172. return fmt.Sprintf("@0x%08X", uint32(id))
  173. }
  174. // Package returns the package index of id.
  175. func (id ResID) Package() uint32 {
  176. return uint32(id) >> 24
  177. }
  178. // Type returns the type index of id.
  179. func (id ResID) Type() int {
  180. return (int(id) >> 16) & 0xFF
  181. }
  182. // Entry returns the entry index of id.
  183. func (id ResID) Entry() int {
  184. return int(id) & 0xFFFF
  185. }
  186. // NewTableFile returns new TableFile.
  187. func NewTableFile(r io.ReaderAt) (*TableFile, error) {
  188. f := new(TableFile)
  189. sr := io.NewSectionReader(r, 0, 1<<63-1)
  190. header := new(ResTableHeader)
  191. binary.Read(sr, binary.LittleEndian, header)
  192. f.tablePackages = make(map[uint32]*TablePackage)
  193. offset := int64(header.Header.HeaderSize)
  194. for offset < int64(header.Header.Size) {
  195. chunkHeader, err := f.readChunk(sr, offset)
  196. if err != nil {
  197. return nil, err
  198. }
  199. offset += int64(chunkHeader.Size)
  200. }
  201. return f, nil
  202. }
  203. func (f *TableFile) findPackage(id uint32) *TablePackage {
  204. if f == nil {
  205. return nil
  206. }
  207. return f.tablePackages[id]
  208. }
  209. func (p *TablePackage) findEntry(typeIndex, entryIndex int, config *ResTableConfig) TableEntry {
  210. var best *TableType
  211. for _, t := range p.TableTypes {
  212. switch {
  213. case int(t.Header.ID) != typeIndex:
  214. // nothing to do
  215. case !t.Header.Config.Match(config):
  216. // nothing to do
  217. case entryIndex >= len(t.Entries):
  218. // nothing to do
  219. case t.Entries[entryIndex].Value == nil:
  220. // nothing to do
  221. case best == nil || t.Header.Config.IsBetterThan(&best.Header.Config, config):
  222. best = t
  223. }
  224. }
  225. if best == nil || entryIndex >= len(best.Entries) {
  226. return TableEntry{}
  227. }
  228. return best.Entries[entryIndex]
  229. }
  230. // GetResource returns a resource referenced by id.
  231. func (f *TableFile) GetResource(id ResID, config *ResTableConfig) (any, error) {
  232. p := f.findPackage(id.Package())
  233. if p == nil {
  234. return nil, fmt.Errorf("androidbinary: package 0x%02X not found", id.Package())
  235. }
  236. e := p.findEntry(id.Type(), id.Entry(), config)
  237. v := e.Value
  238. if v == nil {
  239. return nil, fmt.Errorf("androidbinary: entry 0x%04X not found", id.Entry())
  240. }
  241. switch v.DataType {
  242. case TypeNull:
  243. return nil, nil
  244. case TypeString:
  245. return f.GetString(ResStringPoolRef(v.Data)), nil
  246. case TypeIntDec:
  247. return v.Data, nil
  248. case TypeIntHex:
  249. return v.Data, nil
  250. case TypeIntBoolean:
  251. return v.Data != 0, nil
  252. }
  253. return v.Data, nil
  254. }
  255. // GetString returns a string referenced by ref.
  256. func (f *TableFile) GetString(ref ResStringPoolRef) string {
  257. return f.stringPool.GetString(ref)
  258. }
  259. func (f *TableFile) readChunk(r io.ReaderAt, offset int64) (*ResChunkHeader, error) {
  260. sr := io.NewSectionReader(r, offset, 1<<63-1-offset)
  261. chunkHeader := &ResChunkHeader{}
  262. if _, err := sr.Seek(0, io.SeekStart); err != nil {
  263. return nil, err
  264. }
  265. if err := binary.Read(sr, binary.LittleEndian, chunkHeader); err != nil {
  266. return nil, err
  267. }
  268. var err error
  269. if _, err := sr.Seek(0, io.SeekStart); err != nil {
  270. return nil, err
  271. }
  272. switch chunkHeader.Type {
  273. case ResStringPoolChunkType:
  274. f.stringPool, err = readStringPool(sr)
  275. case ResTablePackageType:
  276. var tablePackage *TablePackage
  277. tablePackage, err = readTablePackage(sr)
  278. f.tablePackages[tablePackage.Header.ID] = tablePackage
  279. }
  280. if err != nil {
  281. return nil, err
  282. }
  283. return chunkHeader, nil
  284. }
  285. func readTablePackage(sr *io.SectionReader) (*TablePackage, error) {
  286. tablePackage := new(TablePackage)
  287. header := new(ResTablePackage)
  288. if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
  289. return nil, err
  290. }
  291. tablePackage.Header = *header
  292. srTypes := io.NewSectionReader(sr, int64(header.TypeStrings), int64(header.Header.Size-header.TypeStrings))
  293. if typeStrings, err := readStringPool(srTypes); err == nil {
  294. tablePackage.TypeStrings = typeStrings
  295. } else {
  296. return nil, err
  297. }
  298. srKeys := io.NewSectionReader(sr, int64(header.KeyStrings), int64(header.Header.Size-header.KeyStrings))
  299. if keyStrings, err := readStringPool(srKeys); err == nil {
  300. tablePackage.KeyStrings = keyStrings
  301. } else {
  302. return nil, err
  303. }
  304. offset := int64(header.Header.HeaderSize)
  305. for offset < int64(header.Header.Size) {
  306. chunkHeader := &ResChunkHeader{}
  307. if _, err := sr.Seek(offset, io.SeekStart); err != nil {
  308. return nil, err
  309. }
  310. if err := binary.Read(sr, binary.LittleEndian, chunkHeader); err != nil {
  311. return nil, err
  312. }
  313. var err error
  314. chunkReader := io.NewSectionReader(sr, offset, int64(chunkHeader.Size))
  315. if _, err := sr.Seek(offset, io.SeekStart); err != nil {
  316. return nil, err
  317. }
  318. switch chunkHeader.Type {
  319. case ResTableTypeType:
  320. var tableType *TableType
  321. tableType, err = readTableType(chunkHeader, chunkReader)
  322. tablePackage.TableTypes = append(tablePackage.TableTypes, tableType)
  323. case ResTableTypeSpecType:
  324. _, err = readTableTypeSpec(chunkReader)
  325. }
  326. if err != nil {
  327. return nil, err
  328. }
  329. offset += int64(chunkHeader.Size)
  330. }
  331. return tablePackage, nil
  332. }
  333. func readTableType(chunkHeader *ResChunkHeader, sr *io.SectionReader) (*TableType, error) {
  334. // TableType header may be omitted
  335. header := new(ResTableType)
  336. if _, err := sr.Seek(0, io.SeekStart); err != nil {
  337. return nil, err
  338. }
  339. buf, err := newZeroFilledReader(sr, int64(chunkHeader.HeaderSize), int64(unsafe.Sizeof(*header)))
  340. if err != nil {
  341. return nil, err
  342. }
  343. if err := binary.Read(buf, binary.LittleEndian, header); err != nil {
  344. return nil, err
  345. }
  346. entryIndexes := make([]uint32, header.EntryCount)
  347. if _, err := sr.Seek(int64(header.Header.HeaderSize), io.SeekStart); err != nil {
  348. return nil, err
  349. }
  350. if err := binary.Read(sr, binary.LittleEndian, entryIndexes); err != nil {
  351. return nil, err
  352. }
  353. entries := make([]TableEntry, header.EntryCount)
  354. for i, index := range entryIndexes {
  355. if index == 0xFFFFFFFF {
  356. continue
  357. }
  358. if _, err := sr.Seek(int64(header.EntriesStart+index), io.SeekStart); err != nil {
  359. return nil, err
  360. }
  361. var key ResTableEntry
  362. binary.Read(sr, binary.LittleEndian, &key)
  363. entries[i].Key = &key
  364. var val ResValue
  365. binary.Read(sr, binary.LittleEndian, &val)
  366. entries[i].Value = &val
  367. }
  368. return &TableType{
  369. header,
  370. entries,
  371. }, nil
  372. }
  373. func readTableTypeSpec(sr *io.SectionReader) ([]uint32, error) {
  374. header := new(ResTableTypeSpec)
  375. if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
  376. return nil, err
  377. }
  378. flags := make([]uint32, header.EntryCount)
  379. if _, err := sr.Seek(int64(header.Header.HeaderSize), io.SeekStart); err != nil {
  380. return nil, err
  381. }
  382. if err := binary.Read(sr, binary.LittleEndian, flags); err != nil {
  383. return nil, err
  384. }
  385. return flags, nil
  386. }
  387. // IsMoreSpecificThan returns true if c is more specific than o.
  388. func (c *ResTableConfig) IsMoreSpecificThan(o *ResTableConfig) bool {
  389. // nil ResTableConfig is never more specific than any ResTableConfig
  390. if c == nil {
  391. return false
  392. }
  393. if o == nil {
  394. return false
  395. }
  396. // imsi
  397. if c.Mcc != o.Mcc {
  398. if c.Mcc == 0 {
  399. return false
  400. }
  401. if o.Mnc == 0 {
  402. return true
  403. }
  404. }
  405. if c.Mnc != o.Mnc {
  406. if c.Mnc == 0 {
  407. return false
  408. }
  409. if o.Mnc == 0 {
  410. return true
  411. }
  412. }
  413. // locale
  414. if diff := c.IsLocaleMoreSpecificThan(o); diff < 0 {
  415. return false
  416. } else if diff > 0 {
  417. return true
  418. }
  419. // screen layout
  420. if c.ScreenLayout != 0 || o.ScreenLayout != 0 {
  421. if ((c.ScreenLayout ^ o.ScreenLayout) & MaskLayoutDir) != 0 {
  422. if (c.ScreenLayout & MaskLayoutDir) == 0 {
  423. return false
  424. }
  425. if (o.ScreenLayout & MaskLayoutDir) == 0 {
  426. return true
  427. }
  428. }
  429. }
  430. // smallest screen width dp
  431. if c.SmallestScreenWidthDp != 0 || o.SmallestScreenWidthDp != 0 {
  432. if c.SmallestScreenWidthDp != o.SmallestScreenWidthDp {
  433. if c.SmallestScreenWidthDp == 0 {
  434. return false
  435. }
  436. if o.SmallestScreenWidthDp == 0 {
  437. return true
  438. }
  439. }
  440. }
  441. // screen size dp
  442. if c.ScreenWidthDp != 0 || o.ScreenWidthDp != 0 ||
  443. c.ScreenHeightDp != 0 || o.ScreenHeightDp != 0 {
  444. if c.ScreenWidthDp != o.ScreenWidthDp {
  445. if c.ScreenWidthDp == 0 {
  446. return false
  447. }
  448. if o.ScreenWidthDp == 0 {
  449. return true
  450. }
  451. }
  452. if c.ScreenHeightDp != o.ScreenHeightDp {
  453. if c.ScreenHeightDp == 0 {
  454. return false
  455. }
  456. if o.ScreenHeightDp == 0 {
  457. return true
  458. }
  459. }
  460. }
  461. // screen layout
  462. if c.ScreenLayout != 0 || o.ScreenLayout != 0 {
  463. if ((c.ScreenLayout ^ o.ScreenLayout) & MaskScreenSize) != 0 {
  464. if (c.ScreenLayout & MaskScreenSize) == 0 {
  465. return false
  466. }
  467. if (o.ScreenLayout & MaskScreenSize) == 0 {
  468. return true
  469. }
  470. }
  471. if ((c.ScreenLayout ^ o.ScreenLayout) & MaskScreenLong) != 0 {
  472. if (c.ScreenLayout & MaskScreenLong) == 0 {
  473. return false
  474. }
  475. if (o.ScreenLayout & MaskScreenLong) == 0 {
  476. return true
  477. }
  478. }
  479. }
  480. // orientation
  481. if c.Orientation != o.Orientation {
  482. if c.Orientation == 0 {
  483. return false
  484. }
  485. if o.Orientation == 0 {
  486. return true
  487. }
  488. }
  489. // uimode
  490. if c.UIMode != 0 || o.UIMode != 0 {
  491. diff := c.UIMode ^ o.UIMode
  492. if (diff & MaskUIModeType) != 0 {
  493. if (c.UIMode & MaskUIModeType) == 0 {
  494. return false
  495. }
  496. if (o.UIMode & MaskUIModeType) == 0 {
  497. return true
  498. }
  499. }
  500. if (diff & MaskUIModeNight) != 0 {
  501. if (c.UIMode & MaskUIModeNight) == 0 {
  502. return false
  503. }
  504. if (o.UIMode & MaskUIModeNight) == 0 {
  505. return true
  506. }
  507. }
  508. }
  509. // touchscreen
  510. if c.Touchscreen != o.Touchscreen {
  511. if c.Touchscreen == 0 {
  512. return false
  513. }
  514. if o.Touchscreen == 0 {
  515. return true
  516. }
  517. }
  518. // input
  519. if c.InputFlags != 0 || o.InputFlags != 0 {
  520. myKeysHidden := c.InputFlags & MaskKeysHidden
  521. oKeysHidden := o.InputFlags & MaskKeysHidden
  522. if (myKeysHidden ^ oKeysHidden) != 0 {
  523. if myKeysHidden == 0 {
  524. return false
  525. }
  526. if oKeysHidden == 0 {
  527. return true
  528. }
  529. }
  530. myNavHidden := c.InputFlags & MaskNavHidden
  531. oNavHidden := o.InputFlags & MaskNavHidden
  532. if (myNavHidden ^ oNavHidden) != 0 {
  533. if myNavHidden == 0 {
  534. return false
  535. }
  536. if oNavHidden == 0 {
  537. return true
  538. }
  539. }
  540. }
  541. if c.Keyboard != o.Keyboard {
  542. if c.Keyboard == 0 {
  543. return false
  544. }
  545. if o.Keyboard == 0 {
  546. return true
  547. }
  548. }
  549. if c.Navigation != o.Navigation {
  550. if c.Navigation == 0 {
  551. return false
  552. }
  553. if o.Navigation == 0 {
  554. return true
  555. }
  556. }
  557. // screen size
  558. if c.ScreenWidth != 0 || o.ScreenWidth != 0 ||
  559. c.ScreenHeight != 0 || o.ScreenHeight != 0 {
  560. if c.ScreenWidth != o.ScreenWidth {
  561. if c.ScreenWidth == 0 {
  562. return false
  563. }
  564. if o.ScreenWidth == 0 {
  565. return true
  566. }
  567. }
  568. if c.ScreenHeight != o.ScreenHeight {
  569. if c.ScreenHeight == 0 {
  570. return false
  571. }
  572. if o.ScreenHeight == 0 {
  573. return true
  574. }
  575. }
  576. }
  577. //version
  578. if c.SDKVersion != o.SDKVersion {
  579. if c.SDKVersion == 0 {
  580. return false
  581. }
  582. if o.SDKVersion == 0 {
  583. return true
  584. }
  585. }
  586. if c.MinorVersion != o.MinorVersion {
  587. if c.MinorVersion == 0 {
  588. return false
  589. }
  590. if o.MinorVersion == 0 {
  591. return true
  592. }
  593. }
  594. return false
  595. }
  596. // IsBetterThan returns true if c is better than o for the r configuration.
  597. func (c *ResTableConfig) IsBetterThan(o *ResTableConfig, r *ResTableConfig) bool {
  598. if r == nil {
  599. return c.IsMoreSpecificThan(o)
  600. }
  601. // nil ResTableConfig is never better than any ResTableConfig
  602. if c == nil {
  603. return false
  604. }
  605. if o == nil {
  606. return false
  607. }
  608. // imsi
  609. if c.Mcc != 0 || c.Mnc != 0 || o.Mcc != 0 || o.Mnc != 0 {
  610. if c.Mcc != o.Mcc && r.Mcc != 0 {
  611. return c.Mcc != 0
  612. }
  613. if c.Mnc != o.Mnc && r.Mnc != 0 {
  614. return c.Mnc != 0
  615. }
  616. }
  617. // locale
  618. if c.IsLocaleBetterThan(o, r) {
  619. return true
  620. }
  621. // screen layout
  622. if c.ScreenLayout != 0 || o.ScreenLayout != 0 {
  623. myLayoutdir := c.ScreenLayout & MaskLayoutDir
  624. oLayoutdir := o.ScreenLayout & MaskLayoutDir
  625. if (myLayoutdir^oLayoutdir) != 0 && (r.ScreenLayout&MaskLayoutDir) != 0 {
  626. return myLayoutdir > oLayoutdir
  627. }
  628. }
  629. // smallest screen width dp
  630. if c.SmallestScreenWidthDp != 0 || o.SmallestScreenWidthDp != 0 {
  631. if c.SmallestScreenWidthDp != o.SmallestScreenWidthDp {
  632. return c.SmallestScreenWidthDp > o.SmallestScreenWidthDp
  633. }
  634. }
  635. // screen size dp
  636. if c.ScreenWidthDp != 0 || c.ScreenHeightDp != 0 || o.ScreenWidthDp != 0 || o.ScreenHeightDp != 0 {
  637. myDelta := 0
  638. otherDelta := 0
  639. if r.ScreenWidthDp != 0 {
  640. myDelta += int(r.ScreenWidthDp) - int(c.ScreenWidthDp)
  641. otherDelta += int(r.ScreenWidthDp) - int(o.ScreenWidthDp)
  642. }
  643. if r.ScreenHeightDp != 0 {
  644. myDelta += int(r.ScreenHeightDp) - int(c.ScreenHeightDp)
  645. otherDelta += int(r.ScreenHeightDp) - int(o.ScreenHeightDp)
  646. }
  647. if myDelta != otherDelta {
  648. return myDelta < otherDelta
  649. }
  650. }
  651. // screen layout
  652. if c.ScreenLayout != 0 || o.ScreenLayout != 0 {
  653. mySL := c.ScreenLayout & MaskScreenSize
  654. oSL := o.ScreenLayout & MaskScreenSize
  655. if (mySL^oSL) != 0 && (r.ScreenLayout&MaskScreenSize) != 0 {
  656. fixedMySL := mySL
  657. fixedOSL := oSL
  658. if (r.ScreenLayout & MaskScreenSize) >= ScreenSizeNormal {
  659. if fixedMySL == 0 {
  660. fixedMySL = ScreenSizeNormal
  661. }
  662. if fixedOSL == 0 {
  663. fixedOSL = ScreenSizeNormal
  664. }
  665. }
  666. if fixedMySL == fixedOSL {
  667. return mySL != 0
  668. }
  669. return fixedMySL > fixedOSL
  670. }
  671. if ((c.ScreenLayout^o.ScreenLayout)&MaskScreenLong) != 0 &&
  672. (r.ScreenLayout&MaskScreenLong) != 0 {
  673. return (c.ScreenLayout & MaskScreenLong) != 0
  674. }
  675. }
  676. // orientation
  677. if c.Orientation != o.Orientation && r.Orientation != 0 {
  678. return c.Orientation != 0
  679. }
  680. // uimode
  681. if c.UIMode != 0 || o.UIMode != 0 {
  682. diff := c.UIMode ^ o.UIMode
  683. if (diff&MaskUIModeType) != 0 && (r.UIMode&MaskUIModeType) != 0 {
  684. return (c.UIMode & MaskUIModeType) != 0
  685. }
  686. if (diff&MaskUIModeNight) != 0 && (r.UIMode&MaskUIModeNight) != 0 {
  687. return (c.UIMode & MaskUIModeNight) != 0
  688. }
  689. }
  690. // screen type
  691. if c.Density != o.Density {
  692. h := int(c.Density)
  693. if h == 0 {
  694. h = 160
  695. }
  696. l := int(o.Density)
  697. if l == 0 {
  698. l = 160
  699. }
  700. blmBigger := true
  701. if l > h {
  702. h, l = l, h
  703. blmBigger = false
  704. }
  705. reqValue := int(r.Density)
  706. if reqValue == 0 {
  707. reqValue = 160
  708. }
  709. if reqValue >= h {
  710. return blmBigger
  711. }
  712. if l >= reqValue {
  713. return !blmBigger
  714. }
  715. if (2*l-reqValue)*h > reqValue*reqValue {
  716. return !blmBigger
  717. }
  718. return blmBigger
  719. }
  720. if c.Touchscreen != o.Touchscreen && r.Touchscreen != 0 {
  721. return c.Touchscreen != 0
  722. }
  723. // input
  724. if c.InputFlags != 0 || o.InputFlags != 0 {
  725. myKeysHidden := c.InputFlags & MaskKeysHidden
  726. oKeysHidden := o.InputFlags & MaskKeysHidden
  727. reqKeysHidden := r.InputFlags & MaskKeysHidden
  728. if myKeysHidden != oKeysHidden && reqKeysHidden != 0 {
  729. switch {
  730. case myKeysHidden == 0:
  731. return false
  732. case oKeysHidden == 0:
  733. return true
  734. case reqKeysHidden == myKeysHidden:
  735. return true
  736. case reqKeysHidden == oKeysHidden:
  737. return false
  738. }
  739. }
  740. myNavHidden := c.InputFlags & MaskNavHidden
  741. oNavHidden := o.InputFlags & MaskNavHidden
  742. reqNavHidden := r.InputFlags & MaskNavHidden
  743. if myNavHidden != oNavHidden && reqNavHidden != 0 {
  744. switch {
  745. case myNavHidden == 0:
  746. return false
  747. case oNavHidden == 0:
  748. return true
  749. }
  750. }
  751. }
  752. if c.Keyboard != o.Keyboard && r.Keyboard != 0 {
  753. return c.Keyboard != 0
  754. }
  755. if c.Navigation != o.Navigation && r.Navigation != 0 {
  756. return c.Navigation != 0
  757. }
  758. // screen size
  759. if c.ScreenWidth != 0 || c.ScreenHeight != 0 || o.ScreenWidth != 0 || o.ScreenHeight != 0 {
  760. myDelta := 0
  761. otherDelta := 0
  762. if r.ScreenWidth != 0 {
  763. myDelta += int(r.ScreenWidth) - int(c.ScreenWidth)
  764. otherDelta += int(r.ScreenWidth) - int(o.ScreenWidth)
  765. }
  766. if r.ScreenHeight != 0 {
  767. myDelta += int(r.ScreenHeight) - int(c.ScreenHeight)
  768. otherDelta += int(r.ScreenHeight) - int(o.ScreenHeight)
  769. }
  770. if myDelta != otherDelta {
  771. return myDelta < otherDelta
  772. }
  773. }
  774. // version
  775. if c.SDKVersion != 0 || o.MinorVersion != 0 {
  776. if c.SDKVersion != o.SDKVersion && r.SDKVersion != 0 {
  777. return c.SDKVersion > o.SDKVersion
  778. }
  779. if c.MinorVersion != o.MinorVersion && r.MinorVersion != 0 {
  780. return c.MinorVersion != 0
  781. }
  782. }
  783. return false
  784. }
  785. // IsLocaleMoreSpecificThan a positive integer if this config is more specific than o,
  786. // a negative integer if |o| is more specific
  787. // and 0 if they're equally specific.
  788. func (c *ResTableConfig) IsLocaleMoreSpecificThan(o *ResTableConfig) int {
  789. if (c.Language != [2]uint8{} || c.Country != [2]uint8{}) || (o.Language != [2]uint8{} || o.Country != [2]uint8{}) {
  790. if c.Language != o.Language {
  791. if c.Language == [2]uint8{} {
  792. return -1
  793. }
  794. if o.Language == [2]uint8{} {
  795. return 1
  796. }
  797. }
  798. if c.Country != o.Country {
  799. if c.Country == [2]uint8{} {
  800. return -1
  801. }
  802. if o.Country == [2]uint8{} {
  803. return 1
  804. }
  805. }
  806. }
  807. return 0
  808. }
  809. // IsLocaleBetterThan returns true if c is a better locale match than o for the r configuration.
  810. func (c *ResTableConfig) IsLocaleBetterThan(o *ResTableConfig, r *ResTableConfig) bool {
  811. if r.Language == [2]uint8{} && r.Country == [2]uint8{} {
  812. // The request doesn't have a locale, so no resource is better
  813. // than the other.
  814. return false
  815. }
  816. if c.Language == [2]uint8{} && c.Country == [2]uint8{} && o.Language == [2]uint8{} && o.Country == [2]uint8{} {
  817. // The locales parts of both resources are empty, so no one is better
  818. // than the other.
  819. return false
  820. }
  821. if c.Language != o.Language {
  822. // The languages of the two resources are not the same.
  823. // the US English resource have traditionally lived for most apps.
  824. if r.Language == [2]uint8{'e', 'n'} {
  825. if r.Country == [2]uint8{'U', 'S'} {
  826. if c.Language != [2]uint8{} {
  827. return c.Country == [2]uint8{} || c.Country == [2]uint8{'U', 'S'}
  828. }
  829. return !(c.Country == [2]uint8{} || c.Country == [2]uint8{'U', 'S'})
  830. }
  831. }
  832. return c.Language != [2]uint8{}
  833. }
  834. if c.Country != o.Country {
  835. return c.Country != [2]uint8{}
  836. }
  837. return false
  838. }
  839. // Match returns true if c can be considered a match for the parameters in settings.
  840. func (c *ResTableConfig) Match(settings *ResTableConfig) bool {
  841. // nil ResTableConfig always matches.
  842. if settings == nil {
  843. return true
  844. } else if c == nil {
  845. return *settings == ResTableConfig{}
  846. }
  847. // match imsi
  848. if settings.Mcc == 0 {
  849. if c.Mcc != 0 {
  850. return false
  851. }
  852. } else {
  853. if c.Mcc != 0 && c.Mcc != settings.Mcc {
  854. return false
  855. }
  856. }
  857. if settings.Mnc == 0 {
  858. if c.Mnc != 0 {
  859. return false
  860. }
  861. } else {
  862. if c.Mnc != 0 && c.Mnc != settings.Mnc {
  863. return false
  864. }
  865. }
  866. // match locale
  867. if c.Language != [2]uint8{0, 0} {
  868. // Don't consider country and variants when deciding matches.
  869. // If two configs differ only in their country and variant,
  870. // they can be weeded out in the isMoreSpecificThan test.
  871. if c.Language != settings.Language {
  872. return false
  873. }
  874. if c.Country != [2]uint8{0, 0} {
  875. if c.Country != settings.Country {
  876. return false
  877. }
  878. }
  879. }
  880. // screen layout
  881. layoutDir := c.ScreenLayout & MaskLayoutDir
  882. setLayoutDir := settings.ScreenLayout & MaskLayoutDir
  883. if layoutDir != 0 && layoutDir != setLayoutDir {
  884. return false
  885. }
  886. screenSize := c.ScreenLayout & MaskScreenSize
  887. setScreenSize := settings.ScreenLayout & MaskScreenSize
  888. if screenSize != 0 && screenSize > setScreenSize {
  889. return false
  890. }
  891. screenLong := c.ScreenLayout & MaskScreenLong
  892. setScreenLong := settings.ScreenLayout & MaskScreenLong
  893. if screenLong != 0 && screenLong != setScreenLong {
  894. return false
  895. }
  896. // ui mode
  897. uiModeType := c.UIMode & MaskUIModeType
  898. setUIModeType := settings.UIMode & MaskUIModeType
  899. if uiModeType != 0 && uiModeType != setUIModeType {
  900. return false
  901. }
  902. uiModeNight := c.UIMode & MaskUIModeNight
  903. setUIModeNight := settings.UIMode & MaskUIModeNight
  904. if uiModeNight != 0 && uiModeNight != setUIModeNight {
  905. return false
  906. }
  907. // smallest screen width dp
  908. if c.SmallestScreenWidthDp != 0 &&
  909. c.SmallestScreenWidthDp > settings.SmallestScreenWidthDp {
  910. return false
  911. }
  912. // screen size dp
  913. if c.ScreenWidthDp != 0 &&
  914. c.ScreenWidthDp > settings.ScreenWidthDp {
  915. return false
  916. }
  917. if c.ScreenHeightDp != 0 &&
  918. c.ScreenHeightDp > settings.ScreenHeightDp {
  919. return false
  920. }
  921. // screen type
  922. if c.Orientation != 0 && c.Orientation != settings.Orientation {
  923. return false
  924. }
  925. if c.Touchscreen != 0 && c.Touchscreen != settings.Touchscreen {
  926. return false
  927. }
  928. // input
  929. if c.InputFlags != 0 {
  930. myKeysHidden := c.InputFlags & MaskKeysHidden
  931. oKeysHidden := settings.InputFlags & MaskKeysHidden
  932. if myKeysHidden != 0 && myKeysHidden != oKeysHidden {
  933. if myKeysHidden != KeysHiddenNo || oKeysHidden != KeysHiddenSoft {
  934. return false
  935. }
  936. }
  937. myNavHidden := c.InputFlags & MaskNavHidden
  938. oNavHidden := settings.InputFlags & MaskNavHidden
  939. if myNavHidden != 0 && myNavHidden != oNavHidden {
  940. return false
  941. }
  942. }
  943. if c.Keyboard != 0 && c.Keyboard != settings.Keyboard {
  944. return false
  945. }
  946. if c.Navigation != 0 && c.Navigation != settings.Navigation {
  947. return false
  948. }
  949. // screen size
  950. if c.ScreenWidth != 0 &&
  951. c.ScreenWidth > settings.ScreenWidth {
  952. return false
  953. }
  954. if c.ScreenHeight != 0 &&
  955. c.ScreenHeight > settings.ScreenHeight {
  956. return false
  957. }
  958. // version
  959. if settings.SDKVersion != 0 && c.SDKVersion != 0 &&
  960. c.SDKVersion > settings.SDKVersion {
  961. return false
  962. }
  963. if settings.MinorVersion != 0 && c.MinorVersion != 0 &&
  964. c.MinorVersion != settings.MinorVersion {
  965. return false
  966. }
  967. return true
  968. }
  969. // Locale returns the locale of the configuration.
  970. func (c *ResTableConfig) Locale() string {
  971. if c.Language[0] == 0 {
  972. return ""
  973. }
  974. if c.Country[0] == 0 {
  975. return fmt.Sprintf("%c%c", c.Language[0], c.Language[1])
  976. }
  977. return fmt.Sprintf("%c%c-%c%c", c.Language[0], c.Language[1], c.Country[0], c.Country[1])
  978. }