type.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. package android_binary
  2. import (
  3. "encoding/xml"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. )
  8. type injector interface {
  9. inject(table *TableFile, config *ResTableConfig)
  10. }
  11. var injectorType = reflect.TypeOf((*injector)(nil)).Elem()
  12. func inject(val reflect.Value, table *TableFile, config *ResTableConfig) {
  13. if val.Kind() == reflect.Ptr {
  14. if val.IsNil() {
  15. return
  16. }
  17. val = val.Elem()
  18. }
  19. if val.CanInterface() && val.Type().Implements(injectorType) {
  20. val.Interface().(injector).inject(table, config)
  21. return
  22. }
  23. if val.CanAddr() {
  24. pv := val.Addr()
  25. if pv.CanInterface() && pv.Type().Implements(injectorType) {
  26. pv.Interface().(injector).inject(table, config)
  27. return
  28. }
  29. }
  30. switch val.Kind() {
  31. default:
  32. // ignore other types
  33. return
  34. case reflect.Slice, reflect.Array:
  35. l := val.Len()
  36. for i := 0; i < l; i++ {
  37. inject(val.Index(i), table, config)
  38. }
  39. return
  40. case reflect.Struct:
  41. l := val.NumField()
  42. for i := 0; i < l; i++ {
  43. inject(val.Field(i), table, config)
  44. }
  45. }
  46. }
  47. // Bool is a boolean value in XML file.
  48. // It may be an immediate value or a reference.
  49. type Bool struct {
  50. value string
  51. table *TableFile
  52. config *ResTableConfig
  53. }
  54. // WithTableFile ties TableFile to the Bool.
  55. func (v Bool) WithTableFile(table *TableFile) Bool {
  56. return Bool{
  57. value: v.value,
  58. table: table,
  59. config: v.config,
  60. }
  61. }
  62. // WithResTableConfig ties ResTableConfig to the Bool.
  63. func (v Bool) WithResTableConfig(config *ResTableConfig) Bool {
  64. return Bool{
  65. value: v.value,
  66. table: v.table,
  67. config: config,
  68. }
  69. }
  70. func (v *Bool) inject(table *TableFile, config *ResTableConfig) {
  71. v.table = table
  72. v.config = config
  73. }
  74. // SetBool sets a boolean value.
  75. func (v *Bool) SetBool(value bool) {
  76. v.value = strconv.FormatBool(value)
  77. }
  78. // SetResID sets a boolean value with the resource id.
  79. func (v *Bool) SetResID(resID ResID) {
  80. v.value = resID.String()
  81. }
  82. // UnmarshalXMLAttr implements xml.UnmarshalerAttr.
  83. func (v *Bool) UnmarshalXMLAttr(attr xml.Attr) error {
  84. v.value = attr.Value
  85. return nil
  86. }
  87. // MarshalXMLAttr implements xml.MarshalerAttr.
  88. func (v Bool) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
  89. if v.value == "" {
  90. // return the zero value of bool
  91. return xml.Attr{
  92. Name: name,
  93. Value: "false",
  94. }, nil
  95. }
  96. return xml.Attr{
  97. Name: name,
  98. Value: v.value,
  99. }, nil
  100. }
  101. // Bool returns the boolean value.
  102. // It resolves the reference if needed.
  103. func (v Bool) Bool() (bool, error) {
  104. if v.value == "" {
  105. return false, nil
  106. }
  107. if !IsResID(v.value) {
  108. return strconv.ParseBool(v.value)
  109. }
  110. id, err := ParseResID(v.value)
  111. if err != nil {
  112. return false, err
  113. }
  114. value, err := v.table.GetResource(id, v.config)
  115. if err != nil {
  116. return false, err
  117. }
  118. ret, ok := value.(bool)
  119. if !ok {
  120. return false, fmt.Errorf("invalid type: %T", value)
  121. }
  122. return ret, nil
  123. }
  124. // MustBool is same as Bool, but it panics if it fails to parse the value.
  125. func (v Bool) MustBool() bool {
  126. ret, err := v.Bool()
  127. if err != nil {
  128. panic(err)
  129. }
  130. return ret
  131. }
  132. // Int32 is an integer value in XML file.
  133. // It may be an immediate value or a reference.
  134. type Int32 struct {
  135. value string
  136. table *TableFile
  137. config *ResTableConfig
  138. }
  139. // WithTableFile ties TableFile to the Bool.
  140. func (v Int32) WithTableFile(table *TableFile) Int32 {
  141. return Int32{
  142. value: v.value,
  143. table: table,
  144. config: v.config,
  145. }
  146. }
  147. // WithResTableConfig ties ResTableConfig to the Bool.
  148. func (v Int32) WithResTableConfig(config *ResTableConfig) Bool {
  149. return Bool{
  150. value: v.value,
  151. table: v.table,
  152. config: config,
  153. }
  154. }
  155. func (v *Int32) inject(table *TableFile, config *ResTableConfig) {
  156. v.table = table
  157. v.config = config
  158. }
  159. // SetInt32 sets an integer value.
  160. func (v *Int32) SetInt32(value int32) {
  161. v.value = strconv.FormatInt(int64(value), 10)
  162. }
  163. // SetResID sets a boolean value with the resource id.
  164. func (v *Int32) SetResID(resID ResID) {
  165. v.value = resID.String()
  166. }
  167. // UnmarshalXMLAttr implements xml.UnmarshalerAttr.
  168. func (v *Int32) UnmarshalXMLAttr(attr xml.Attr) error {
  169. v.value = attr.Value
  170. return nil
  171. }
  172. // MarshalXMLAttr implements xml.MarshalerAttr.
  173. func (v Int32) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
  174. if v.value == "" {
  175. // return the zero value of int32
  176. return xml.Attr{
  177. Name: name,
  178. Value: "0",
  179. }, nil
  180. }
  181. return xml.Attr{
  182. Name: name,
  183. Value: v.value,
  184. }, nil
  185. }
  186. // Int32 returns the integer value.
  187. // It resolves the reference if needed.
  188. func (v Int32) Int32() (int32, error) {
  189. if v.value == "" {
  190. return 0, nil
  191. }
  192. if !IsResID(v.value) {
  193. v, err := strconv.ParseInt(v.value, 10, 32)
  194. return int32(v), err
  195. }
  196. id, err := ParseResID(v.value)
  197. if err != nil {
  198. return 0, err
  199. }
  200. value, err := v.table.GetResource(id, v.config)
  201. if err != nil {
  202. return 0, err
  203. }
  204. ret, ok := value.(uint32)
  205. if !ok {
  206. return 0, fmt.Errorf("invalid type: %T", value)
  207. }
  208. return int32(ret), nil
  209. }
  210. // MustInt32 is same as Int32, but it panics if it fails to parse the value.
  211. func (v Int32) MustInt32() int32 {
  212. ret, err := v.Int32()
  213. if err != nil {
  214. panic(err)
  215. }
  216. return ret
  217. }
  218. // String is a boolean value in XML file.
  219. // It may be an immediate value or a reference.
  220. type String struct {
  221. value string
  222. table *TableFile
  223. config *ResTableConfig
  224. }
  225. // WithTableFile ties TableFile to the Bool.
  226. func (v String) WithTableFile(table *TableFile) String {
  227. return String{
  228. value: v.value,
  229. table: table,
  230. config: v.config,
  231. }
  232. }
  233. // WithResTableConfig ties ResTableConfig to the Bool.
  234. func (v String) WithResTableConfig(config *ResTableConfig) String {
  235. return String{
  236. value: v.value,
  237. table: v.table,
  238. config: config,
  239. }
  240. }
  241. func (v *String) inject(table *TableFile, config *ResTableConfig) {
  242. v.table = table
  243. v.config = config
  244. }
  245. // SetString sets a string value.
  246. func (v *String) SetString(value string) {
  247. v.value = value
  248. }
  249. // SetResID sets a boolean value with the resource id.
  250. func (v *String) SetResID(resID ResID) {
  251. v.value = resID.String()
  252. }
  253. // UnmarshalXMLAttr implements xml.UnmarshalerAttr.
  254. func (v *String) UnmarshalXMLAttr(attr xml.Attr) error {
  255. v.value = attr.Value
  256. return nil
  257. }
  258. // MarshalXMLAttr implements xml.MarshalerAttr.
  259. func (v String) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
  260. return xml.Attr{
  261. Name: name,
  262. Value: v.value,
  263. }, nil
  264. }
  265. // String returns the string value.
  266. // It resolves the reference if needed.
  267. func (v String) String() (string, error) {
  268. if !IsResID(v.value) {
  269. return v.value, nil
  270. }
  271. id, err := ParseResID(v.value)
  272. if err != nil {
  273. return "", err
  274. }
  275. value, err := v.table.GetResource(id, v.config)
  276. if err != nil {
  277. return "", err
  278. }
  279. //todo 读取套娃
  280. switch value.(type) {
  281. case string:
  282. return value.(string), nil
  283. case uint32:
  284. return fmt.Sprintf("%d", value.(uint32)), nil
  285. default:
  286. return "", nil
  287. }
  288. }
  289. // MustString is same as String, but it panics if it fails to parse the value.
  290. func (v String) MustString() string {
  291. ret, err := v.String()
  292. if err != nil {
  293. panic(err)
  294. }
  295. return ret
  296. }