123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- package android_binary
- import (
- "encoding/xml"
- "fmt"
- "reflect"
- "strconv"
- )
- type injector interface {
- inject(table *TableFile, config *ResTableConfig)
- }
- var injectorType = reflect.TypeOf((*injector)(nil)).Elem()
- func inject(val reflect.Value, table *TableFile, config *ResTableConfig) {
- if val.Kind() == reflect.Ptr {
- if val.IsNil() {
- return
- }
- val = val.Elem()
- }
- if val.CanInterface() && val.Type().Implements(injectorType) {
- val.Interface().(injector).inject(table, config)
- return
- }
- if val.CanAddr() {
- pv := val.Addr()
- if pv.CanInterface() && pv.Type().Implements(injectorType) {
- pv.Interface().(injector).inject(table, config)
- return
- }
- }
- switch val.Kind() {
- default:
- // ignore other types
- return
- case reflect.Slice, reflect.Array:
- l := val.Len()
- for i := 0; i < l; i++ {
- inject(val.Index(i), table, config)
- }
- return
- case reflect.Struct:
- l := val.NumField()
- for i := 0; i < l; i++ {
- inject(val.Field(i), table, config)
- }
- }
- }
- // Bool is a boolean value in XML file.
- // It may be an immediate value or a reference.
- type Bool struct {
- value string
- table *TableFile
- config *ResTableConfig
- }
- // WithTableFile ties TableFile to the Bool.
- func (v Bool) WithTableFile(table *TableFile) Bool {
- return Bool{
- value: v.value,
- table: table,
- config: v.config,
- }
- }
- // WithResTableConfig ties ResTableConfig to the Bool.
- func (v Bool) WithResTableConfig(config *ResTableConfig) Bool {
- return Bool{
- value: v.value,
- table: v.table,
- config: config,
- }
- }
- func (v *Bool) inject(table *TableFile, config *ResTableConfig) {
- v.table = table
- v.config = config
- }
- // SetBool sets a boolean value.
- func (v *Bool) SetBool(value bool) {
- v.value = strconv.FormatBool(value)
- }
- // SetResID sets a boolean value with the resource id.
- func (v *Bool) SetResID(resID ResID) {
- v.value = resID.String()
- }
- // UnmarshalXMLAttr implements xml.UnmarshalerAttr.
- func (v *Bool) UnmarshalXMLAttr(attr xml.Attr) error {
- v.value = attr.Value
- return nil
- }
- // MarshalXMLAttr implements xml.MarshalerAttr.
- func (v Bool) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
- if v.value == "" {
- // return the zero value of bool
- return xml.Attr{
- Name: name,
- Value: "false",
- }, nil
- }
- return xml.Attr{
- Name: name,
- Value: v.value,
- }, nil
- }
- // Bool returns the boolean value.
- // It resolves the reference if needed.
- func (v Bool) Bool() (bool, error) {
- if v.value == "" {
- return false, nil
- }
- if !IsResID(v.value) {
- return strconv.ParseBool(v.value)
- }
- id, err := ParseResID(v.value)
- if err != nil {
- return false, err
- }
- value, err := v.table.GetResource(id, v.config)
- if err != nil {
- return false, err
- }
- ret, ok := value.(bool)
- if !ok {
- return false, fmt.Errorf("invalid type: %T", value)
- }
- return ret, nil
- }
- // MustBool is same as Bool, but it panics if it fails to parse the value.
- func (v Bool) MustBool() bool {
- ret, err := v.Bool()
- if err != nil {
- panic(err)
- }
- return ret
- }
- // Int32 is an integer value in XML file.
- // It may be an immediate value or a reference.
- type Int32 struct {
- value string
- table *TableFile
- config *ResTableConfig
- }
- // WithTableFile ties TableFile to the Bool.
- func (v Int32) WithTableFile(table *TableFile) Int32 {
- return Int32{
- value: v.value,
- table: table,
- config: v.config,
- }
- }
- // WithResTableConfig ties ResTableConfig to the Bool.
- func (v Int32) WithResTableConfig(config *ResTableConfig) Bool {
- return Bool{
- value: v.value,
- table: v.table,
- config: config,
- }
- }
- func (v *Int32) inject(table *TableFile, config *ResTableConfig) {
- v.table = table
- v.config = config
- }
- // SetInt32 sets an integer value.
- func (v *Int32) SetInt32(value int32) {
- v.value = strconv.FormatInt(int64(value), 10)
- }
- // SetResID sets a boolean value with the resource id.
- func (v *Int32) SetResID(resID ResID) {
- v.value = resID.String()
- }
- // UnmarshalXMLAttr implements xml.UnmarshalerAttr.
- func (v *Int32) UnmarshalXMLAttr(attr xml.Attr) error {
- v.value = attr.Value
- return nil
- }
- // MarshalXMLAttr implements xml.MarshalerAttr.
- func (v Int32) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
- if v.value == "" {
- // return the zero value of int32
- return xml.Attr{
- Name: name,
- Value: "0",
- }, nil
- }
- return xml.Attr{
- Name: name,
- Value: v.value,
- }, nil
- }
- // Int32 returns the integer value.
- // It resolves the reference if needed.
- func (v Int32) Int32() (int32, error) {
- if v.value == "" {
- return 0, nil
- }
- if !IsResID(v.value) {
- v, err := strconv.ParseInt(v.value, 10, 32)
- return int32(v), err
- }
- id, err := ParseResID(v.value)
- if err != nil {
- return 0, err
- }
- value, err := v.table.GetResource(id, v.config)
- if err != nil {
- return 0, err
- }
- ret, ok := value.(uint32)
- if !ok {
- return 0, fmt.Errorf("invalid type: %T", value)
- }
- return int32(ret), nil
- }
- // MustInt32 is same as Int32, but it panics if it fails to parse the value.
- func (v Int32) MustInt32() int32 {
- ret, err := v.Int32()
- if err != nil {
- panic(err)
- }
- return ret
- }
- // String is a boolean value in XML file.
- // It may be an immediate value or a reference.
- type String struct {
- value string
- table *TableFile
- config *ResTableConfig
- }
- // WithTableFile ties TableFile to the Bool.
- func (v String) WithTableFile(table *TableFile) String {
- return String{
- value: v.value,
- table: table,
- config: v.config,
- }
- }
- // WithResTableConfig ties ResTableConfig to the Bool.
- func (v String) WithResTableConfig(config *ResTableConfig) String {
- return String{
- value: v.value,
- table: v.table,
- config: config,
- }
- }
- func (v *String) inject(table *TableFile, config *ResTableConfig) {
- v.table = table
- v.config = config
- }
- // SetString sets a string value.
- func (v *String) SetString(value string) {
- v.value = value
- }
- // SetResID sets a boolean value with the resource id.
- func (v *String) SetResID(resID ResID) {
- v.value = resID.String()
- }
- // UnmarshalXMLAttr implements xml.UnmarshalerAttr.
- func (v *String) UnmarshalXMLAttr(attr xml.Attr) error {
- v.value = attr.Value
- return nil
- }
- // MarshalXMLAttr implements xml.MarshalerAttr.
- func (v String) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
- return xml.Attr{
- Name: name,
- Value: v.value,
- }, nil
- }
- // String returns the string value.
- // It resolves the reference if needed.
- func (v String) String() (string, error) {
- if !IsResID(v.value) {
- return v.value, nil
- }
- id, err := ParseResID(v.value)
- if err != nil {
- return "", err
- }
- value, err := v.table.GetResource(id, v.config)
- if err != nil {
- return "", err
- }
- //todo 读取套娃
- switch value.(type) {
- case string:
- return value.(string), nil
- case uint32:
- return fmt.Sprintf("%d", value.(uint32)), nil
- default:
- return "", nil
- }
- }
- // MustString is same as String, but it panics if it fails to parse the value.
- func (v String) MustString() string {
- ret, err := v.String()
- if err != nil {
- panic(err)
- }
- return ret
- }
|