add missing package

This commit is contained in:
codeskyblue
2017-05-09 17:17:53 +08:00
parent 892546343a
commit e063187656
6 changed files with 1471 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
language: go
go:
- 1.0
- 1.1
- 1.2

21
vendor/github.com/codeskyblue/androidbinary/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Ichinose Shogo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

29
vendor/github.com/codeskyblue/androidbinary/README.md generated vendored Normal file
View File

@@ -0,0 +1,29 @@
androidbinary
=====
[![Build Status](https://travis-ci.org/shogo82148/androidbinary.svg?branch=master)](https://travis-ci.org/shogo82148/androidbinary)
Android binary file parser
## Parse XML binary
``` go
package main
import (
"fmt"
"github.com/shogo82148/androidbinary"
"os"
)
func main() {
f, _ := os.Open("AndroidManifest")
xml, _ := androidbinary.NewXMLFile(f)
reader := xml.Reader()
// read XML from reader
}
```
## License
This software is released under the MIT License, see LICENSE.

236
vendor/github.com/codeskyblue/androidbinary/common.go generated vendored Normal file
View File

@@ -0,0 +1,236 @@
package androidbinary
import (
"bytes"
"encoding/binary"
"io"
"os"
"unicode/utf16"
)
const (
RES_NULL_TYPE = 0x0000
RES_STRING_POOL_TYPE = 0x0001
RES_TABLE_TYPE = 0x0002
RES_XML_TYPE = 0x0003
// Chunk types in RES_XML_TYPE
RES_XML_FIRST_CHUNK_TYPE = 0x0100
RES_XML_START_NAMESPACE_TYPE = 0x0100
RES_XML_END_NAMESPACE_TYPE = 0x0101
RES_XML_START_ELEMENT_TYPE = 0x0102
RES_XML_END_ELEMENT_TYPE = 0x0103
RES_XML_CDATA_TYPE = 0x0104
RES_XML_LAST_CHUNK_TYPE = 0x017f
// This contains a uint32_t array mapping strings in the string
// pool back to resource identifiers. It is optional.
RES_XML_RESOURCE_MAP_TYPE = 0x0180
// Chunk types in RES_TABLE_TYPE
RES_TABLE_PACKAGE_TYPE = 0x0200
RES_TABLE_TYPE_TYPE = 0x0201
RES_TABLE_TYPE_SPEC_TYPE = 0x0202
)
type ResChunkHeader struct {
Type uint16
HeaderSize uint16
Size uint32
}
const SORTED_FLAG = 1 << 0
const UTF8_FLAG = 1 << 8
type ResStringPoolHeader struct {
Header ResChunkHeader
StringCount uint32
StyleCount uint32
Flags uint32
StringStart uint32
StylesStart uint32
}
type ResStringPool struct {
Header ResStringPoolHeader
Strings []string
Styles []string
}
const NilResStringPoolRef = ResStringPoolRef(0xFFFFFFFF)
type ResStringPoolRef uint32
const (
TYPE_NULL = 0x00
TYPE_REFERENCE = 0x01
TYPE_ATTRIBUTE = 0x02
TYPE_STRING = 0x03
TYPE_FLOAT = 0x04
TYPE_DIMENSION = 0x05
TYPE_FRACTION = 0x06
TYPE_FIRST_INT = 0x10
TYPE_INT_DEC = 0x10
TYPE_INT_HEX = 0x11
TYPE_INT_BOOLEAN = 0x12
TYPE_FIRST_COLOR_INT = 0x1c
TYPE_INT_COLOR_ARGB8 = 0x1c
TYPE_INT_COLOR_RGB8 = 0x1d
TYPE_INT_COLOR_ARGB4 = 0x1e
TYPE_INT_COLOR_RGB4 = 0x1f
TYPE_LAST_COLOR_INT = 0x1f
TYPE_LAST_INT = 0x1f
)
type ResValue struct {
Size uint16
Res0 uint8
DataType uint8
Data uint32
}
func (pool *ResStringPool) GetString(ref ResStringPoolRef) string {
return pool.Strings[int(ref)]
}
func readStringPool(sr *io.SectionReader) (*ResStringPool, error) {
sp := new(ResStringPool)
if err := binary.Read(sr, binary.LittleEndian, &sp.Header); err != nil {
return nil, err
}
stringStarts := make([]uint32, sp.Header.StringCount)
if err := binary.Read(sr, binary.LittleEndian, stringStarts); err != nil {
return nil, err
}
styleStarts := make([]uint32, sp.Header.StyleCount)
if err := binary.Read(sr, binary.LittleEndian, styleStarts); err != nil {
return nil, err
}
sp.Strings = make([]string, sp.Header.StringCount)
for i, start := range stringStarts {
var str string
var err error
sr.Seek(int64(sp.Header.StringStart+start), os.SEEK_SET)
if (sp.Header.Flags & UTF8_FLAG) == 0 {
str, err = readUTF16(sr)
} else {
str, err = readUTF8(sr)
}
if err != nil {
return nil, err
}
sp.Strings[i] = str
}
sp.Styles = make([]string, sp.Header.StyleCount)
for i, start := range styleStarts {
var str string
var err error
sr.Seek(int64(sp.Header.StylesStart+start), os.SEEK_SET)
if (sp.Header.Flags & UTF8_FLAG) == 0 {
str, err = readUTF16(sr)
} else {
str, err = readUTF8(sr)
}
if err != nil {
return nil, err
}
sp.Styles[i] = str
}
return sp, nil
}
func readUTF16(sr *io.SectionReader) (string, error) {
// read lenth of string
size, err := readUTF16length(sr)
if err != nil {
return "", nil
}
// read string value
buf := make([]uint16, size)
if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
return "", err
}
return string(utf16.Decode(buf)), nil
}
func readUTF16length(sr *io.SectionReader) (int, error) {
var size int
var first, second uint16
if err := binary.Read(sr, binary.LittleEndian, &first); err != nil {
return 0, err
}
if (first & 0x8000) != 0 {
if err := binary.Read(sr, binary.LittleEndian, &second); err != nil {
return 0, err
}
size = (int(first&0x7FFF) << 16) + int(second)
} else {
size = int(first)
}
return size, nil
}
func readUTF8(sr *io.SectionReader) (string, error) {
// skip utf16 length
_, err := readUTF8length(sr)
if err != nil {
return "", err
}
// read lenth of string
size, err := readUTF8length(sr)
if err != nil {
return "", err
}
buf := make([]uint8, size)
if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
return "", err
}
return string(buf), nil
}
func readUTF8length(sr *io.SectionReader) (int, error) {
var size int
var first, second uint8
if err := binary.Read(sr, binary.LittleEndian, &first); err != nil {
return 0, err
}
if (first & 0x80) != 0 {
if err := binary.Read(sr, binary.LittleEndian, &second); err != nil {
return 0, err
}
size = (int(first&0x7F) << 8) + int(second)
} else {
size = int(first)
}
return size, nil
}
func newZeroFilledReader(r io.Reader, actual int64, expected int64) (io.Reader, error) {
if actual >= expected {
// no need to fill
return r, nil
}
// read `actual' bytes from r, and
buf := new(bytes.Buffer)
if _, err := io.CopyN(buf, r, actual); err != nil {
return nil, err
}
// fill zero until `expected' bytes
for i := actual; i < expected; i++ {
if err := buf.WriteByte(0x00); err != nil {
return nil, err
}
}
return buf, nil
}

942
vendor/github.com/codeskyblue/androidbinary/table.go generated vendored Normal file
View File

@@ -0,0 +1,942 @@
package androidbinary
import (
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"unsafe"
)
type ResId uint32
type TableFile struct {
stringPool *ResStringPool
tablePackages map[uint32]*TablePackage
}
type ResTableHeader struct {
Header ResChunkHeader
PackageCount uint32
}
type ResTablePackage struct {
Header ResChunkHeader
Id uint32
Name [128]uint16
TypeStrings uint32
LastPublicType uint32
KeyStrings uint32
LastPublicKey uint32
}
type TablePackage struct {
Header ResTablePackage
TypeStrings *ResStringPool
KeyStrings *ResStringPool
TableTypes []*TableType
}
type ResTableType struct {
Header ResChunkHeader
Id uint8
Res0 uint8
Res1 uint16
EntryCount uint32
EntriesStart uint32
Config ResTableConfig
}
// ScreenLayout bits
const (
MASK_SCREENSIZE = 0x0f
SCREENSIZE_ANY = 0x01
SCREENSIZE_SMALL = 0x02
SCREENSIZE_NORMAL = 0x03
SCREENSIZE_LARGE = 0x04
SCREENSIZE_XLARGE = 0x05
MASK_SCREENLONG = 0x30
SHIFT_SCREENLONG = 4
SCREENLONG_ANY = 0x00
SCREENLONG_NO = 0x10
SCREENLONG_YES = 0x20
MASK_LAYOUTDIR = 0xC0
SHIFT_LAYOUTDIR = 6
LAYOUTDIR_ANY = 0x00
LAYOUTDIR_LTR = 0x40
LAYOUTDIR_RTL = 0x80
)
// UIMode bits
const (
MASK_UI_MODE_TYPE = 0x0f
UI_MODE_TYPE_ANY = 0x01
UI_MODE_TYPE_NORMAL = 0x02
UI_MODE_TYPE_DESK = 0x03
UI_MODE_TYPE_CAR = 0x04
MASK_UI_MODE_NIGHT = 0x30
SHIFT_UI_MODE_NIGHT = 4
UI_MODE_NIGHT_ANY = 0x00
UI_MODE_NIGHT_NO = 0x10
UI_MODE_NIGHT_YES = 0x20
)
// input flags
const (
MASK_KEYSHIDDEN = 0x03
KEYSHIDDEN_ANY = 0x00
KEYSHIDDEN_NO = 0x01
KEYSHIDDEN_YES = 0x02
KEYSHIDDEN_SOFT = 0x03
MASK_NAVHIDDEN = 0x0c
NAVHIDDEN_ANY = 0x00
NAVHIDDEN_NO = 0x04
NAVHIDDEN_YES = 0x08
)
type ResTableConfig struct {
Size uint32
// imsi
Mcc uint16
Mnc uint16
// locale
Language [2]uint8
Country [2]uint8
// screen type
Orientation uint8
Touchscreen uint8
Density uint16
// inout
Keyboard uint8
Navigation uint8
InputFlags uint8
InputPad0 uint8
// screen size
ScreenWidth uint16
ScreenHeight uint16
// version
SDKVersion uint16
MinorVersion uint16
// screen config
ScreenLayout uint8
UIMode uint8
SmallestScreenWidthDp uint16
// screen size dp
ScreenWidthDp uint16
ScreenHeightDp uint16
}
type TableType struct {
Header *ResTableType
Entries []TableEntry
}
type ResTableEntry struct {
Size uint16
Flags uint16
Key ResStringPoolRef
}
type TableEntry struct {
Key *ResTableEntry
Value *ResValue
Flags uint32
}
type ResTableTypeSpec struct {
Header ResChunkHeader
Id uint8
Res0 uint8
Res1 uint16
EntryCount uint32
}
func (id ResId) Package() int {
return int(id) >> 24
}
func (id ResId) Type() int {
return (int(id) >> 16) & 0xFF
}
func (id ResId) Entry() int {
return int(id) & 0xFFFF
}
func NewTableFile(r io.ReaderAt) (*TableFile, error) {
f := new(TableFile)
sr := io.NewSectionReader(r, 0, 1<<63-1)
header := new(ResTableHeader)
binary.Read(sr, binary.LittleEndian, header)
f.tablePackages = make(map[uint32]*TablePackage)
offset := int64(header.Header.HeaderSize)
for offset < int64(header.Header.Size) {
chunkHeader, err := f.readChunk(sr, offset)
if err != nil {
return nil, err
}
offset += int64(chunkHeader.Size)
}
return f, nil
}
func (f *TableFile) findPackage(id int) *TablePackage {
return f.tablePackages[uint32(id)]
}
func (p *TablePackage) findType(id int, config *ResTableConfig) *TableType {
var best *TableType
for _, t := range p.TableTypes {
if int(t.Header.Id) != id {
continue
}
if !t.Header.Config.Match(config) {
continue
}
if best == nil || t.Header.Config.IsBetterThan(&best.Header.Config, config) {
best = t
}
}
return best
}
func (f *TableFile) GetResource(id ResId, config *ResTableConfig) (interface{}, error) {
p := f.findPackage(id.Package())
t := p.findType(id.Type(), config)
e := t.Entries[id.Entry()]
v := e.Value
if v == nil {
return nil, errors.New("get resource error")
}
switch v.DataType {
case TYPE_NULL:
return nil, nil
case TYPE_STRING:
return f.GetString(ResStringPoolRef(v.Data)), nil
case TYPE_INT_DEC:
return v.Data, nil
case TYPE_INT_HEX:
return v.Data, nil
case TYPE_INT_BOOLEAN:
return v.Data != 0, nil
}
return v.Data, nil
}
func (f *TableFile) GetString(ref ResStringPoolRef) string {
return f.stringPool.GetString(ref)
}
func (f *TableFile) readChunk(r io.ReaderAt, offset int64) (*ResChunkHeader, error) {
sr := io.NewSectionReader(r, offset, 1<<63-1-offset)
chunkHeader := &ResChunkHeader{}
sr.Seek(0, os.SEEK_SET)
if err := binary.Read(sr, binary.LittleEndian, chunkHeader); err != nil {
return nil, err
}
var err error
sr.Seek(0, os.SEEK_SET)
switch chunkHeader.Type {
case RES_STRING_POOL_TYPE:
f.stringPool, err = readStringPool(sr)
case RES_TABLE_PACKAGE_TYPE:
var tablePackage *TablePackage
tablePackage, err = readTablePackage(sr)
f.tablePackages[tablePackage.Header.Id] = tablePackage
}
if err != nil {
return nil, err
}
return chunkHeader, nil
}
func readTablePackage(sr *io.SectionReader) (*TablePackage, error) {
tablePackage := new(TablePackage)
header := new(ResTablePackage)
if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
return nil, err
}
tablePackage.Header = *header
srTypes := io.NewSectionReader(sr, int64(header.TypeStrings), int64(header.Header.Size-header.TypeStrings))
if typeStrings, err := readStringPool(srTypes); err == nil {
tablePackage.TypeStrings = typeStrings
} else {
return nil, err
}
srKeys := io.NewSectionReader(sr, int64(header.KeyStrings), int64(header.Header.Size-header.KeyStrings))
if keyStrings, err := readStringPool(srKeys); err == nil {
tablePackage.KeyStrings = keyStrings
} else {
return nil, err
}
offset := int64(header.Header.HeaderSize)
for offset < int64(header.Header.Size) {
chunkHeader := &ResChunkHeader{}
sr.Seek(offset, os.SEEK_SET)
if err := binary.Read(sr, binary.LittleEndian, chunkHeader); err != nil {
return nil, err
}
var err error
chunkReader := io.NewSectionReader(sr, offset, int64(chunkHeader.Size))
sr.Seek(offset, os.SEEK_SET)
switch chunkHeader.Type {
case RES_TABLE_TYPE_TYPE:
var tableType *TableType
tableType, err = readTableType(chunkHeader, chunkReader)
tablePackage.TableTypes = append(tablePackage.TableTypes, tableType)
case RES_TABLE_TYPE_SPEC_TYPE:
_, err = readTableTypeSpec(chunkReader)
}
if err != nil {
return nil, err
}
offset += int64(chunkHeader.Size)
}
return tablePackage, nil
}
func readTableType(chunkHeader *ResChunkHeader, sr *io.SectionReader) (*TableType, error) {
// TableType header may be omitted
header := new(ResTableType)
sr.Seek(0, os.SEEK_SET)
buf, err := newZeroFilledReader(sr, int64(chunkHeader.HeaderSize), int64(unsafe.Sizeof(*header)))
if err != nil {
return nil, err
}
if err := binary.Read(buf, binary.LittleEndian, header); err != nil {
return nil, err
}
entryIndexes := make([]uint32, header.EntryCount)
sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
if err := binary.Read(sr, binary.LittleEndian, entryIndexes); err != nil {
return nil, err
}
entries := make([]TableEntry, header.EntryCount)
for i, index := range entryIndexes {
if index == 0xFFFFFFFF {
continue
}
sr.Seek(int64(header.EntriesStart+index), os.SEEK_SET)
var key ResTableEntry
binary.Read(sr, binary.LittleEndian, &key)
entries[i].Key = &key
var val ResValue
binary.Read(sr, binary.LittleEndian, &val)
entries[i].Value = &val
}
return &TableType{
header,
entries,
}, nil
}
func readTableTypeSpec(sr *io.SectionReader) ([]uint32, error) {
header := new(ResTableTypeSpec)
if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
return nil, err
}
flags := make([]uint32, header.EntryCount)
sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
if err := binary.Read(sr, binary.LittleEndian, flags); err != nil {
return nil, err
}
return flags, nil
}
func (c *ResTableConfig) IsMoreSpecificThan(o *ResTableConfig) bool {
// imsi
if c.Mcc != o.Mcc {
if c.Mcc == 0 {
return false
}
if o.Mnc == 0 {
return true
}
}
if c.Mnc != o.Mnc {
if c.Mnc == 0 {
return false
}
if o.Mnc == 0 {
return true
}
}
// locale
if c.Language[0] != o.Language[0] {
if c.Language[0] == 0 {
return false
}
if o.Language[0] == 0 {
return true
}
}
if c.Country[0] != o.Country[0] {
if c.Country[0] == 0 {
return false
}
if o.Country[0] == 0 {
return true
}
}
// screen layout
if c.ScreenLayout != 0 || o.ScreenLayout != 0 {
if ((c.ScreenLayout ^ o.ScreenLayout) & MASK_LAYOUTDIR) != 0 {
if (c.ScreenLayout & MASK_LAYOUTDIR) == 0 {
return false
}
if (o.ScreenLayout & MASK_LAYOUTDIR) == 0 {
return true
}
}
}
// smallest screen width dp
if c.SmallestScreenWidthDp != 0 || o.SmallestScreenWidthDp != 0 {
if c.SmallestScreenWidthDp != o.SmallestScreenWidthDp {
if c.SmallestScreenWidthDp == 0 {
return false
}
if o.SmallestScreenWidthDp == 0 {
return true
}
}
}
// screen size dp
if c.ScreenWidthDp != 0 || o.ScreenWidthDp != 0 ||
c.ScreenHeightDp != 0 || o.ScreenHeightDp != 0 {
if c.ScreenWidthDp != o.ScreenWidthDp {
if c.ScreenWidthDp == 0 {
return false
}
if o.ScreenWidthDp == 0 {
return true
}
}
if c.ScreenHeightDp != o.ScreenHeightDp {
if c.ScreenHeightDp == 0 {
return false
}
if o.ScreenHeightDp == 0 {
return true
}
}
}
// screen layout
if c.ScreenLayout != 0 || o.ScreenLayout != 0 {
if ((c.ScreenLayout ^ o.ScreenLayout) & MASK_SCREENSIZE) != 0 {
if (c.ScreenLayout & MASK_SCREENSIZE) == 0 {
return false
}
if (o.ScreenLayout & MASK_SCREENSIZE) == 0 {
return true
}
}
if ((c.ScreenLayout ^ o.ScreenLayout) & MASK_SCREENLONG) != 0 {
if (c.ScreenLayout & MASK_SCREENLONG) == 0 {
return false
}
if (o.ScreenLayout & MASK_SCREENLONG) == 0 {
return true
}
}
}
// orientation
if c.Orientation != o.Orientation {
if c.Orientation == 0 {
return false
}
if o.Orientation == 0 {
return true
}
}
// uimode
if c.UIMode != 0 || o.UIMode != 0 {
diff := c.UIMode ^ o.UIMode
if (diff & MASK_UI_MODE_TYPE) != 0 {
if (c.UIMode & MASK_UI_MODE_TYPE) == 0 {
return false
}
if (o.UIMode & MASK_UI_MODE_TYPE) == 0 {
return true
}
}
if (diff & MASK_UI_MODE_NIGHT) != 0 {
if (c.UIMode & MASK_UI_MODE_NIGHT) == 0 {
return false
}
if (o.UIMode & MASK_UI_MODE_NIGHT) == 0 {
return true
}
}
}
// touchscreen
if c.Touchscreen != o.Touchscreen {
if c.Touchscreen == 0 {
return false
}
if o.Touchscreen == 0 {
return true
}
}
// input
if c.InputFlags != 0 || o.InputFlags != 0 {
myKeysHidden := c.InputFlags & MASK_KEYSHIDDEN
oKeysHidden := o.InputFlags & MASK_KEYSHIDDEN
if (myKeysHidden ^ oKeysHidden) != 0 {
if myKeysHidden == 0 {
return false
}
if oKeysHidden == 0 {
return true
}
}
myNavHidden := c.InputFlags & MASK_NAVHIDDEN
oNavHidden := o.InputFlags & MASK_NAVHIDDEN
if (myNavHidden ^ oNavHidden) != 0 {
if myNavHidden == 0 {
return false
}
if oNavHidden == 0 {
return true
}
}
}
if c.Keyboard != o.Keyboard {
if c.Keyboard == 0 {
return false
}
if o.Keyboard == 0 {
return true
}
}
if c.Navigation != o.Navigation {
if c.Navigation == 0 {
return false
}
if o.Navigation == 0 {
return true
}
}
// screen size
if c.ScreenWidth != 0 || o.ScreenWidth != 0 ||
c.ScreenHeight != 0 || o.ScreenHeight != 0 {
if c.ScreenWidth != o.ScreenWidth {
if c.ScreenWidth == 0 {
return false
}
if o.ScreenWidth == 0 {
return true
}
}
if c.ScreenHeight != o.ScreenHeight {
if c.ScreenHeight == 0 {
return false
}
if o.ScreenHeight == 0 {
return true
}
}
}
//version
if c.SDKVersion != o.SDKVersion {
if c.SDKVersion == 0 {
return false
}
if o.SDKVersion == 0 {
return true
}
}
if c.MinorVersion != o.MinorVersion {
if c.MinorVersion == 0 {
return false
}
if o.MinorVersion == 0 {
return true
}
}
return false
}
func (c *ResTableConfig) IsBetterThan(o *ResTableConfig, r *ResTableConfig) bool {
if r == nil {
return c.IsMoreSpecificThan(o)
}
// imsi
if c.Mcc != 0 || c.Mnc != 0 || o.Mcc != 0 || o.Mnc != 0 {
if c.Mcc != o.Mcc && r.Mcc != 0 {
return c.Mcc != 0
}
if c.Mnc != o.Mnc && r.Mnc != 0 {
return c.Mnc != 0
}
}
// locale
if c.Language[0] != 0 || c.Country[0] != 0 || o.Language[0] != 0 || o.Country[0] != 0 {
if c.Language[0] != o.Language[0] && r.Language[0] != 0 {
return c.Language[0] != 0
}
if c.Country[0] != o.Country[0] && r.Country[0] != 0 {
return c.Country[0] != 0
}
}
// screen layout
if c.ScreenLayout != 0 || o.ScreenLayout != 0 {
myLayoutdir := c.ScreenLayout & MASK_LAYOUTDIR
oLayoutdir := o.ScreenLayout & MASK_LAYOUTDIR
if (myLayoutdir^oLayoutdir) != 0 && (r.ScreenLayout&MASK_LAYOUTDIR) != 0 {
return myLayoutdir > oLayoutdir
}
}
// smallest screen width dp
if c.SmallestScreenWidthDp != 0 || o.SmallestScreenWidthDp != 0 {
if c.SmallestScreenWidthDp != o.SmallestScreenWidthDp {
return c.SmallestScreenWidthDp > o.SmallestScreenWidthDp
}
}
// screen size dp
if c.ScreenWidthDp != 0 || c.ScreenHeightDp != 0 || o.ScreenWidthDp != 0 || o.ScreenHeightDp != 0 {
myDelta := 0
otherDelta := 0
if r.ScreenWidthDp != 0 {
myDelta += int(r.ScreenWidthDp) - int(c.ScreenWidthDp)
otherDelta += int(r.ScreenWidthDp) - int(o.ScreenWidthDp)
}
if r.ScreenHeightDp != 0 {
myDelta += int(r.ScreenHeightDp) - int(c.ScreenHeightDp)
otherDelta += int(r.ScreenHeightDp) - int(o.ScreenHeightDp)
}
if myDelta != otherDelta {
return myDelta < otherDelta
}
}
// screen layout
if c.ScreenLayout != 0 || o.ScreenLayout != 0 {
mySL := c.ScreenLayout & MASK_SCREENSIZE
oSL := o.ScreenLayout & MASK_SCREENSIZE
if (mySL^oSL) != 0 && (r.ScreenLayout&MASK_SCREENSIZE) != 0 {
fixedMySL := mySL
fixedOSL := oSL
if (r.ScreenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL {
if fixedMySL == 0 {
fixedMySL = SCREENSIZE_NORMAL
}
if fixedOSL == 0 {
fixedOSL = SCREENSIZE_NORMAL
}
}
if fixedMySL == fixedOSL {
return mySL != 0
} else {
return fixedMySL > fixedOSL
}
}
if ((c.ScreenLayout^o.ScreenLayout)&MASK_SCREENLONG) != 0 &&
(r.ScreenLayout&MASK_SCREENLONG) != 0 {
return (c.ScreenLayout & MASK_SCREENLONG) != 0
}
}
// orientation
if c.Orientation != o.Orientation && r.Orientation != 0 {
return c.Orientation != 0
}
// uimode
if c.UIMode != 0 || o.UIMode != 0 {
diff := c.UIMode ^ o.UIMode
if (diff&MASK_UI_MODE_TYPE) != 0 && (r.UIMode&MASK_UI_MODE_TYPE) != 0 {
return (c.UIMode & MASK_UI_MODE_TYPE) != 0
}
if (diff&MASK_UI_MODE_NIGHT) != 0 && (r.UIMode&MASK_UI_MODE_NIGHT) != 0 {
return (c.UIMode & MASK_UI_MODE_NIGHT) != 0
}
}
// screen type
if c.Density != o.Density {
h := int(c.Density)
if h == 0 {
h = 160
}
l := int(o.Density)
if l == 0 {
l = 160
}
blmBigger := true
if l > h {
h, l = l, h
blmBigger = false
}
reqValue := int(r.Density)
if reqValue == 0 {
reqValue = 160
}
if reqValue >= h {
return blmBigger
}
if l >= reqValue {
return !blmBigger
}
if (2*l-reqValue)*h > reqValue*reqValue {
return !blmBigger
} else {
return blmBigger
}
}
if c.Touchscreen != o.Touchscreen && r.Touchscreen != 0 {
return c.Touchscreen != 0
}
// input
if c.InputFlags != 0 || o.InputFlags != 0 {
myKeysHidden := c.InputFlags & MASK_KEYSHIDDEN
oKeysHidden := o.InputFlags & MASK_KEYSHIDDEN
reqKeysHidden := r.InputFlags & MASK_KEYSHIDDEN
if myKeysHidden != oKeysHidden && reqKeysHidden != 0 {
switch {
case myKeysHidden == 0:
return false
case oKeysHidden == 0:
return true
case reqKeysHidden == myKeysHidden:
return true
case reqKeysHidden == oKeysHidden:
return false
}
}
myNavHidden := c.InputFlags & MASK_NAVHIDDEN
oNavHidden := o.InputFlags & MASK_NAVHIDDEN
reqNavHidden := r.InputFlags & MASK_NAVHIDDEN
if myNavHidden != oNavHidden && reqNavHidden != 0 {
switch {
case myNavHidden == 0:
return false
case oNavHidden == 0:
return true
}
}
}
if c.Keyboard != o.Keyboard && r.Keyboard != 0 {
return c.Keyboard != 0
}
if c.Navigation != o.Navigation && r.Navigation != 0 {
return c.Navigation != 0
}
// screen size
if c.ScreenWidth != 0 || c.ScreenHeight != 0 || o.ScreenWidth != 0 || o.ScreenHeight != 0 {
myDelta := 0
otherDelta := 0
if r.ScreenWidth != 0 {
myDelta += int(r.ScreenWidth) - int(c.ScreenWidth)
otherDelta += int(r.ScreenWidth) - int(o.ScreenWidth)
}
if r.ScreenHeight != 0 {
myDelta += int(r.ScreenHeight) - int(c.ScreenHeight)
otherDelta += int(r.ScreenHeight) - int(o.ScreenHeight)
}
if myDelta != otherDelta {
return myDelta < otherDelta
}
}
// version
if c.SDKVersion != 0 || c.SDKVersion != 0 || o.MinorVersion != 0 || o.MinorVersion != 0 {
if c.SDKVersion != o.SDKVersion && r.SDKVersion != 0 {
return c.SDKVersion > o.SDKVersion
}
if c.MinorVersion != o.MinorVersion && r.MinorVersion != 0 {
return c.MinorVersion != 0
}
}
return false
}
func (c *ResTableConfig) Match(settings *ResTableConfig) bool {
// match imsi
if settings.Mcc == 0 {
if c.Mcc != 0 {
return false
}
} else {
if c.Mcc != 0 && c.Mcc != settings.Mcc {
return false
}
}
if settings.Mnc == 0 {
if c.Mnc != 0 {
return false
}
} else {
if c.Mnc != 0 && c.Mnc != settings.Mnc {
return false
}
}
// match locale
if settings.Language[0] != 0 && c.Language[0] != 0 &&
!(settings.Language[0] == c.Language[0] && settings.Language[1] == c.Language[1]) {
return false
}
if settings.Country[0] != 0 && c.Country[0] != 0 &&
!(settings.Country[0] == c.Country[0] && settings.Country[1] == c.Country[1]) {
return false
}
// screen layout
layoutDir := c.ScreenLayout & MASK_LAYOUTDIR
setLayoutDir := settings.ScreenLayout & MASK_LAYOUTDIR
if layoutDir != 0 && layoutDir != setLayoutDir {
return false
}
screenSize := c.ScreenLayout & MASK_SCREENSIZE
setScreenSize := settings.ScreenLayout & MASK_SCREENSIZE
if screenSize != 0 && screenSize > setScreenSize {
return false
}
screenLong := c.ScreenLayout & MASK_SCREENLONG
setScreenLong := settings.ScreenLayout & MASK_SCREENLONG
if screenLong != 0 && screenLong != setScreenLong {
return false
}
// ui mode
uiModeType := c.UIMode & MASK_UI_MODE_TYPE
setUIModeType := settings.UIMode & MASK_UI_MODE_TYPE
if uiModeType != 0 && uiModeType != setUIModeType {
return false
}
uiModeNight := c.UIMode & MASK_UI_MODE_NIGHT
setUIModeNight := settings.UIMode & MASK_UI_MODE_NIGHT
if uiModeNight != 0 && uiModeNight != setUIModeNight {
return false
}
// smallest screen width dp
if c.SmallestScreenWidthDp != 0 &&
c.SmallestScreenWidthDp > settings.SmallestScreenWidthDp {
return false
}
// screen size dp
if c.ScreenWidthDp != 0 &&
c.ScreenWidthDp > settings.ScreenWidthDp {
return false
}
if c.ScreenHeightDp != 0 &&
c.ScreenHeightDp > settings.ScreenHeightDp {
return false
}
// screen type
if c.Orientation != 0 && c.Orientation != settings.Orientation {
return false
}
if c.Touchscreen != 0 && c.Touchscreen != settings.Touchscreen {
return false
}
// input
if c.InputFlags != 0 {
myKeysHidden := c.InputFlags & MASK_KEYSHIDDEN
oKeysHidden := settings.InputFlags & MASK_KEYSHIDDEN
if myKeysHidden != 0 && myKeysHidden != oKeysHidden {
if myKeysHidden != KEYSHIDDEN_NO || oKeysHidden != KEYSHIDDEN_SOFT {
return false
}
}
myNavHidden := c.InputFlags & MASK_NAVHIDDEN
oNavHidden := settings.InputFlags & MASK_NAVHIDDEN
if myNavHidden != 0 && myNavHidden != oNavHidden {
return false
}
}
if c.Keyboard != 0 && c.Keyboard != settings.Keyboard {
return false
}
if c.Navigation != 0 && c.Navigation != settings.Navigation {
return false
}
// screen size
if c.ScreenWidth != 0 &&
c.ScreenWidth > settings.ScreenWidth {
return false
}
if c.ScreenHeight != 0 &&
c.ScreenHeight > settings.ScreenHeight {
return false
}
// version
if settings.SDKVersion != 0 && c.SDKVersion != 0 &&
c.SDKVersion > settings.SDKVersion {
return false
}
if settings.MinorVersion != 0 && c.MinorVersion != 0 &&
c.MinorVersion != settings.MinorVersion {
return false
}
return true
}
func (c *ResTableConfig) Locale() string {
if c.Language[0] == 0 {
return ""
}
if c.Country[0] == 0 {
return fmt.Sprintf("%c%c", c.Language[0], c.Language[1])
}
return fmt.Sprintf("%c%c-%c%c", c.Language[0], c.Language[1], c.Country[0], c.Country[1])
}

237
vendor/github.com/codeskyblue/androidbinary/xml.go generated vendored Normal file
View File

@@ -0,0 +1,237 @@
package androidbinary
import (
"bytes"
"encoding/binary"
"encoding/xml"
"fmt"
"io"
"os"
)
type XMLFile struct {
stringPool *ResStringPool
resourceMap []uint32
notPrecessedNS map[ResStringPoolRef]ResStringPoolRef
namespaces map[ResStringPoolRef]ResStringPoolRef
xmlBuffer bytes.Buffer
}
type ResXMLTreeNode struct {
Header ResChunkHeader
LineNumber uint32
Comment ResStringPoolRef
}
type ResXMLTreeNamespaceExt struct {
Prefix ResStringPoolRef
Uri ResStringPoolRef
}
type ResXMLTreeAttrExt struct {
NS ResStringPoolRef
Name ResStringPoolRef
AttributeStart uint16
AttributeSize uint16
AttributeCount uint16
IdIndex uint16
ClassIndex uint16
StyleIndex uint16
}
type ResXMLTreeAttribute struct {
NS ResStringPoolRef
Name ResStringPoolRef
RawValue ResStringPoolRef
TypedValue ResValue
}
type ResXMLTreeEndElementExt struct {
NS ResStringPoolRef
Name ResStringPoolRef
}
func NewXMLFile(r io.ReaderAt) (*XMLFile, error) {
f := new(XMLFile)
sr := io.NewSectionReader(r, 0, 1<<63-1)
fmt.Fprintf(&f.xmlBuffer, xml.Header)
header := new(ResChunkHeader)
if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
return nil, err
}
offset := int64(header.HeaderSize)
for offset < int64(header.Size) {
chunkHeader, err := f.readChunk(r, offset)
if err != nil {
return nil, err
}
offset += int64(chunkHeader.Size)
}
return f, nil
}
func (f *XMLFile) Reader() *bytes.Reader {
return bytes.NewReader(f.xmlBuffer.Bytes())
}
func (f *XMLFile) readChunk(r io.ReaderAt, offset int64) (*ResChunkHeader, error) {
sr := io.NewSectionReader(r, offset, 1<<63-1-offset)
chunkHeader := &ResChunkHeader{}
sr.Seek(0, os.SEEK_SET)
if err := binary.Read(sr, binary.LittleEndian, chunkHeader); err != nil {
return nil, err
}
var err error
sr.Seek(0, os.SEEK_SET)
switch chunkHeader.Type {
case RES_STRING_POOL_TYPE:
f.stringPool, err = readStringPool(sr)
case RES_XML_START_NAMESPACE_TYPE:
err = f.readStartNamespace(sr)
case RES_XML_END_NAMESPACE_TYPE:
err = f.readEndNamespace(sr)
case RES_XML_START_ELEMENT_TYPE:
err = f.readStartElement(sr)
case RES_XML_END_ELEMENT_TYPE:
err = f.readEndElement(sr)
}
if err != nil {
return nil, err
}
return chunkHeader, nil
}
func (f *XMLFile) GetString(ref ResStringPoolRef) string {
return f.stringPool.GetString(ref)
}
func (f *XMLFile) readStartNamespace(sr *io.SectionReader) error {
header := new(ResXMLTreeNode)
if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
return err
}
sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
namespace := new(ResXMLTreeNamespaceExt)
if err := binary.Read(sr, binary.LittleEndian, namespace); err != nil {
return err
}
if f.notPrecessedNS == nil {
f.notPrecessedNS = make(map[ResStringPoolRef]ResStringPoolRef)
}
f.notPrecessedNS[namespace.Uri] = namespace.Prefix
if f.namespaces == nil {
f.namespaces = make(map[ResStringPoolRef]ResStringPoolRef)
}
f.namespaces[namespace.Uri] = namespace.Prefix
return nil
}
func (f *XMLFile) readEndNamespace(sr *io.SectionReader) error {
header := new(ResXMLTreeNode)
if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
return err
}
sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
namespace := new(ResXMLTreeNamespaceExt)
if err := binary.Read(sr, binary.LittleEndian, namespace); err != nil {
return err
}
delete(f.namespaces, namespace.Uri)
return nil
}
func (f *XMLFile) addNamespacePrefix(ns, name ResStringPoolRef) string {
if ns != NilResStringPoolRef {
prefix := f.GetString(f.namespaces[ns])
return fmt.Sprintf("%s:%s", prefix, f.GetString(name))
}
return f.GetString(name)
}
func (f *XMLFile) readStartElement(sr *io.SectionReader) error {
header := new(ResXMLTreeNode)
if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
return err
}
sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
ext := new(ResXMLTreeAttrExt)
if err := binary.Read(sr, binary.LittleEndian, ext); err != nil {
return nil
}
fmt.Fprintf(&f.xmlBuffer, "<%s", f.addNamespacePrefix(ext.NS, ext.Name))
// output XML namespaces
if f.notPrecessedNS != nil {
for uri, prefix := range f.notPrecessedNS {
fmt.Fprintf(&f.xmlBuffer, " xmlns:%s=\"", f.GetString(prefix))
xml.Escape(&f.xmlBuffer, []byte(f.GetString(uri)))
fmt.Fprint(&f.xmlBuffer, "\"")
}
f.notPrecessedNS = nil
}
// process attributes
offset := int64(ext.AttributeStart + header.Header.HeaderSize)
for i := 0; i < int(ext.AttributeCount); i++ {
sr.Seek(offset, os.SEEK_SET)
attr := new(ResXMLTreeAttribute)
binary.Read(sr, binary.LittleEndian, attr)
var value string
if attr.RawValue != NilResStringPoolRef {
value = f.GetString(attr.RawValue)
} else {
data := attr.TypedValue.Data
switch attr.TypedValue.DataType {
case TYPE_NULL:
value = ""
case TYPE_REFERENCE:
value = fmt.Sprintf("@0x%08X", data)
case TYPE_INT_DEC:
value = fmt.Sprintf("%d", data)
case TYPE_INT_HEX:
value = fmt.Sprintf("0x%08X", data)
case TYPE_INT_BOOLEAN:
if data != 0 {
value = "true"
} else {
value = "false"
}
default:
value = fmt.Sprintf("@0x%08X", data)
}
}
fmt.Fprintf(&f.xmlBuffer, " %s=\"", f.addNamespacePrefix(attr.NS, attr.Name))
xml.Escape(&f.xmlBuffer, []byte(value))
fmt.Fprint(&f.xmlBuffer, "\"")
offset += int64(ext.AttributeSize)
}
fmt.Fprint(&f.xmlBuffer, ">")
return nil
}
func (f *XMLFile) readEndElement(sr *io.SectionReader) error {
header := new(ResXMLTreeNode)
if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
return err
}
sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
ext := new(ResXMLTreeEndElementExt)
if err := binary.Read(sr, binary.LittleEndian, ext); err != nil {
return err
}
fmt.Fprintf(&f.xmlBuffer, "</%s>", f.addNamespacePrefix(ext.NS, ext.Name))
return nil
}