xml.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. package android_binary
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/xml"
  6. "fmt"
  7. "io"
  8. "reflect"
  9. )
  10. // XMLFile is an XML file expressed in binary format.
  11. type XMLFile struct {
  12. stringPool *ResStringPool
  13. resourceMap []uint32
  14. notPrecessedNS map[ResStringPoolRef]ResStringPoolRef
  15. namespaces map[ResStringPoolRef]ResStringPoolRef
  16. xmlBuffer bytes.Buffer
  17. }
  18. // ResXMLTreeNode is basic XML tree node.
  19. type ResXMLTreeNode struct {
  20. Header ResChunkHeader
  21. LineNumber uint32
  22. Comment ResStringPoolRef
  23. }
  24. // ResXMLTreeNamespaceExt is extended XML tree node for namespace start/end nodes.
  25. type ResXMLTreeNamespaceExt struct {
  26. Prefix ResStringPoolRef
  27. URI ResStringPoolRef
  28. }
  29. // ResXMLTreeAttrExt is extended XML tree node for start tags -- includes attribute.
  30. type ResXMLTreeAttrExt struct {
  31. NS ResStringPoolRef
  32. Name ResStringPoolRef
  33. AttributeStart uint16
  34. AttributeSize uint16
  35. AttributeCount uint16
  36. IDIndex uint16
  37. ClassIndex uint16
  38. StyleIndex uint16
  39. }
  40. // ResXMLTreeAttribute is an attribute of start tags.
  41. type ResXMLTreeAttribute struct {
  42. NS ResStringPoolRef
  43. Name ResStringPoolRef
  44. RawValue ResStringPoolRef
  45. TypedValue ResValue
  46. }
  47. // ResXMLTreeEndElementExt is extended XML tree node for element start/end nodes.
  48. type ResXMLTreeEndElementExt struct {
  49. NS ResStringPoolRef
  50. Name ResStringPoolRef
  51. }
  52. // NewXMLFile returns a new XMLFile.
  53. func NewXMLFile(r io.ReaderAt) (*XMLFile, error) {
  54. f := new(XMLFile)
  55. sr := io.NewSectionReader(r, 0, 1<<63-1)
  56. fmt.Fprintf(&f.xmlBuffer, xml.Header)
  57. header := new(ResChunkHeader)
  58. if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
  59. return nil, err
  60. }
  61. offset := int64(header.HeaderSize)
  62. for offset < int64(header.Size) {
  63. chunkHeader, err := f.readChunk(r, offset)
  64. if err != nil {
  65. return nil, err
  66. }
  67. offset += int64(chunkHeader.Size)
  68. }
  69. return f, nil
  70. }
  71. // Reader returns a reader of XML file expressed in text format.
  72. func (f *XMLFile) Reader() *bytes.Reader {
  73. return bytes.NewReader(f.xmlBuffer.Bytes())
  74. }
  75. // Decode decodes XML file and stores the result in the value pointed to by v.
  76. // To resolve the resource references, Decode also stores default TableFile and ResTableConfig in the value pointed to by v.
  77. func (f *XMLFile) Decode(v any, table *TableFile, config *ResTableConfig) error {
  78. decoder := xml.NewDecoder(f.Reader())
  79. if err := decoder.Decode(v); err != nil {
  80. return err
  81. }
  82. inject(reflect.ValueOf(v), table, config)
  83. return nil
  84. }
  85. func (f *XMLFile) readChunk(r io.ReaderAt, offset int64) (*ResChunkHeader, error) {
  86. sr := io.NewSectionReader(r, offset, 1<<63-1-offset)
  87. chunkHeader := &ResChunkHeader{}
  88. if _, err := sr.Seek(0, io.SeekStart); err != nil {
  89. return nil, err
  90. }
  91. if err := binary.Read(sr, binary.LittleEndian, chunkHeader); err != nil {
  92. return nil, err
  93. }
  94. var err error
  95. if _, err := sr.Seek(0, io.SeekStart); err != nil {
  96. return nil, err
  97. }
  98. switch chunkHeader.Type {
  99. case ResStringPoolChunkType:
  100. f.stringPool, err = readStringPool(sr)
  101. case ResXMLStartNamespaceType:
  102. err = f.readStartNamespace(sr)
  103. case ResXMLEndNamespaceType:
  104. err = f.readEndNamespace(sr)
  105. case ResXMLStartElementType:
  106. err = f.readStartElement(sr)
  107. case ResXMLEndElementType:
  108. err = f.readEndElement(sr)
  109. }
  110. if err != nil {
  111. return nil, err
  112. }
  113. return chunkHeader, nil
  114. }
  115. // GetString returns a string referenced by ref.
  116. func (f *XMLFile) GetString(ref ResStringPoolRef) string {
  117. return f.stringPool.GetString(ref)
  118. }
  119. func (f *XMLFile) readStartNamespace(sr *io.SectionReader) error {
  120. header := new(ResXMLTreeNode)
  121. if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
  122. return err
  123. }
  124. if _, err := sr.Seek(int64(header.Header.HeaderSize), io.SeekStart); err != nil {
  125. return err
  126. }
  127. namespace := new(ResXMLTreeNamespaceExt)
  128. if err := binary.Read(sr, binary.LittleEndian, namespace); err != nil {
  129. return err
  130. }
  131. if f.notPrecessedNS == nil {
  132. f.notPrecessedNS = make(map[ResStringPoolRef]ResStringPoolRef)
  133. }
  134. f.notPrecessedNS[namespace.URI] = namespace.Prefix
  135. if f.namespaces == nil {
  136. f.namespaces = make(map[ResStringPoolRef]ResStringPoolRef)
  137. }
  138. f.namespaces[namespace.URI] = namespace.Prefix
  139. return nil
  140. }
  141. func (f *XMLFile) readEndNamespace(sr *io.SectionReader) error {
  142. header := new(ResXMLTreeNode)
  143. if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
  144. return err
  145. }
  146. if _, err := sr.Seek(int64(header.Header.HeaderSize), io.SeekStart); err != nil {
  147. return err
  148. }
  149. namespace := new(ResXMLTreeNamespaceExt)
  150. if err := binary.Read(sr, binary.LittleEndian, namespace); err != nil {
  151. return err
  152. }
  153. delete(f.namespaces, namespace.URI)
  154. return nil
  155. }
  156. func (f *XMLFile) addNamespacePrefix(ns, name ResStringPoolRef) string {
  157. if ns != NilResStringPoolRef {
  158. prefix := f.GetString(f.namespaces[ns])
  159. return fmt.Sprintf("%s:%s", prefix, f.GetString(name))
  160. }
  161. return f.GetString(name)
  162. }
  163. func (f *XMLFile) readStartElement(sr *io.SectionReader) error {
  164. header := new(ResXMLTreeNode)
  165. if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
  166. return err
  167. }
  168. if _, err := sr.Seek(int64(header.Header.HeaderSize), io.SeekStart); err != nil {
  169. return err
  170. }
  171. ext := new(ResXMLTreeAttrExt)
  172. if err := binary.Read(sr, binary.LittleEndian, ext); err != nil {
  173. return nil
  174. }
  175. fmt.Fprintf(&f.xmlBuffer, "<%s", f.addNamespacePrefix(ext.NS, ext.Name))
  176. // output XML namespaces
  177. if f.notPrecessedNS != nil {
  178. for uri, prefix := range f.notPrecessedNS {
  179. fmt.Fprintf(&f.xmlBuffer, " xmlns:%s=\"", f.GetString(prefix))
  180. xml.Escape(&f.xmlBuffer, []byte(f.GetString(uri)))
  181. fmt.Fprint(&f.xmlBuffer, "\"")
  182. }
  183. f.notPrecessedNS = nil
  184. }
  185. // process attributes
  186. offset := int64(ext.AttributeStart + header.Header.HeaderSize)
  187. for i := 0; i < int(ext.AttributeCount); i++ {
  188. if _, err := sr.Seek(offset, io.SeekStart); err != nil {
  189. return err
  190. }
  191. attr := new(ResXMLTreeAttribute)
  192. binary.Read(sr, binary.LittleEndian, attr)
  193. var value string
  194. if attr.RawValue != NilResStringPoolRef {
  195. value = f.GetString(attr.RawValue)
  196. } else {
  197. data := attr.TypedValue.Data
  198. switch attr.TypedValue.DataType {
  199. case TypeNull:
  200. value = ""
  201. case TypeReference:
  202. value = fmt.Sprintf("@0x%08X", data)
  203. case TypeIntDec:
  204. value = fmt.Sprintf("%d", data)
  205. case TypeIntHex:
  206. value = fmt.Sprintf("0x%08X", data)
  207. case TypeIntBoolean:
  208. if data != 0 {
  209. value = "true"
  210. } else {
  211. value = "false"
  212. }
  213. default:
  214. value = fmt.Sprintf("@0x%08X", data)
  215. }
  216. }
  217. fmt.Fprintf(&f.xmlBuffer, " %s=\"", f.addNamespacePrefix(attr.NS, attr.Name))
  218. xml.Escape(&f.xmlBuffer, []byte(value))
  219. fmt.Fprint(&f.xmlBuffer, "\"")
  220. offset += int64(ext.AttributeSize)
  221. }
  222. fmt.Fprint(&f.xmlBuffer, ">")
  223. return nil
  224. }
  225. func (f *XMLFile) readEndElement(sr *io.SectionReader) error {
  226. header := new(ResXMLTreeNode)
  227. if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
  228. return err
  229. }
  230. if _, err := sr.Seek(int64(header.Header.HeaderSize), io.SeekStart); err != nil {
  231. return err
  232. }
  233. ext := new(ResXMLTreeEndElementExt)
  234. if err := binary.Read(sr, binary.LittleEndian, ext); err != nil {
  235. return err
  236. }
  237. fmt.Fprintf(&f.xmlBuffer, "</%s>", f.addNamespacePrefix(ext.NS, ext.Name))
  238. return nil
  239. }