brlyt.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/xml"
  6. "io"
  7. "io/ioutil"
  8. )
  9. // Header represents the header of our BRLYT
  10. type Header struct {
  11. Magic [4]byte
  12. BOM uint32
  13. FileSize uint32
  14. HeaderLen uint16
  15. SectionCount uint16
  16. }
  17. // SectionTypes are known parts of a BRLYT.
  18. type SectionTypes [4]byte
  19. var (
  20. headerMagic SectionTypes = [4]byte{'R', 'L', 'Y', 'T'}
  21. SectionTypeLYT SectionTypes = [4]byte{'l', 'y', 't', '1'}
  22. SectionTypeTXL SectionTypes = [4]byte{'t', 'x', 'l', '1'}
  23. SectionTypeFNL SectionTypes = [4]byte{'f', 'n', 'l', '1'}
  24. SectionTypeMAT SectionTypes = [4]byte{'m', 'a', 't', '1'}
  25. SectionTypePAN SectionTypes = [4]byte{'p', 'a', 'n', '1'}
  26. SectionTypePAS SectionTypes = [4]byte{'p', 'a', 's', '1'}
  27. SectionTypePAE SectionTypes = [4]byte{'p', 'a', 'e', '1'}
  28. SectionTypeBND SectionTypes = [4]byte{'b', 'n', 'd', '1'}
  29. SectionTypePIC SectionTypes = [4]byte{'p', 'i', 'c', '1'}
  30. SectionTypeTXT SectionTypes = [4]byte{'t', 'x', 't', '1'}
  31. SectionTypeWND SectionTypes = [4]byte{'w', 'n', 'd', '1'}
  32. SectionTypeGRP SectionTypes = [4]byte{'g', 'r', 'p', '1'}
  33. SectionTypeGRS SectionTypes = [4]byte{'g', 'r', 's', '1'}
  34. SectionTypeGRE SectionTypes = [4]byte{'g', 'r', 'e', '1'}
  35. )
  36. type SectionHeader struct {
  37. Type SectionTypes
  38. Size uint32
  39. }
  40. type BRLYTWriter struct {
  41. *bytes.Buffer
  42. }
  43. func ParseBRLYT(fileName string) ([]byte, error) {
  44. contents, err := ioutil.ReadFile(fileName)
  45. if err != nil {
  46. panic(err)
  47. }
  48. // Create a new reader
  49. readable := bytes.NewReader(contents)
  50. var header Header
  51. err = binary.Read(readable, binary.BigEndian, &header)
  52. if err != nil {
  53. panic(err)
  54. }
  55. if !bytes.Equal(headerMagic[:], header.Magic[:]) {
  56. return nil, ErrInvalidFileMagic
  57. }
  58. if readable.Size() != int64(header.FileSize) {
  59. return nil, ErrFileSizeMismatch
  60. }
  61. root := Root{
  62. XMLName: xml.Name{},
  63. LYT: LYTNode{},
  64. FNL: nil,
  65. TXL: nil,
  66. Panes: nil,
  67. }
  68. for count := header.SectionCount; count != 0; count-- {
  69. var sectionHeader SectionHeader
  70. err = binary.Read(readable, binary.BigEndian, &sectionHeader)
  71. if err != nil {
  72. return nil, err
  73. }
  74. // Subtract the header size
  75. sectionSize := int(sectionHeader.Size) - 8
  76. if readable.Len() == 0 {
  77. // If our type is one of the section ending types, we can write then finish.
  78. switch sectionHeader.Type {
  79. case SectionTypePAE:
  80. root.ParsePAE()
  81. case SectionTypeGRE:
  82. root.ParseGRE()
  83. }
  84. continue
  85. }
  86. temp := make([]byte, sectionSize)
  87. _, err = readable.Read(temp)
  88. if err != nil {
  89. return nil, err
  90. }
  91. switch sectionHeader.Type {
  92. case SectionTypeLYT:
  93. root.ParseLYT(temp)
  94. case SectionTypeTXL:
  95. root.ParseTXL(temp, sectionHeader.Size)
  96. case SectionTypeFNL:
  97. root.ParseFNL(temp, sectionHeader.Size)
  98. case SectionTypeMAT:
  99. root.ParseMAT(temp, sectionHeader.Size)
  100. case SectionTypePAN:
  101. root.ParsePAN(temp)
  102. case SectionTypeBND:
  103. root.ParseBND(temp)
  104. case SectionTypePIC:
  105. root.ParsePIC(temp)
  106. case SectionTypeTXT:
  107. root.ParseTXT(temp, sectionHeader.Size)
  108. case SectionTypeWND:
  109. root.ParseWND(temp)
  110. case SectionTypePAS:
  111. root.ParsePAS()
  112. case SectionTypePAE:
  113. root.ParsePAE()
  114. case SectionTypeGRP:
  115. root.ParseGRP(temp)
  116. case SectionTypeGRS:
  117. root.ParseGRS()
  118. case SectionTypeGRE:
  119. root.ParseGRE()
  120. }
  121. }
  122. data, err := xml.MarshalIndent(root, "", "\t")
  123. if err != nil {
  124. return nil, err
  125. }
  126. return data, nil
  127. }
  128. func WriteBRLYT(data []byte) ([]byte, error) {
  129. var root Root
  130. err := xml.Unmarshal(data, &root)
  131. if err != nil {
  132. return nil, err
  133. }
  134. writer := BRLYTWriter{bytes.NewBuffer(nil)}
  135. // First write the header
  136. header := Header{
  137. Magic: headerMagic,
  138. BOM: 0xFEFF000A,
  139. FileSize: 0,
  140. HeaderLen: 16,
  141. SectionCount: 0,
  142. }
  143. err = binary.Write(writer, binary.BigEndian, header)
  144. if err != nil {
  145. return nil, err
  146. }
  147. sectionCount := len(root.Panes)
  148. // Write the LYT1 section
  149. writer.WriteLYT(root)
  150. sectionCount += 1
  151. if root.TXL != nil {
  152. // Write TXL section
  153. writer.WriteTXL(root)
  154. sectionCount += 1
  155. }
  156. if root.FNL != nil {
  157. // Write FNL section
  158. writer.WriteFNL(root)
  159. sectionCount += 1
  160. }
  161. // Write MAT section
  162. writer.WriteMAT(root)
  163. sectionCount += 1
  164. for _, pane := range root.Panes {
  165. // Please bear with me, we must check which pane is not nil
  166. if pane.Pane != nil {
  167. writer.WritePane(*pane.Pane)
  168. }
  169. if pane.PAS != nil {
  170. writer.WritePAS()
  171. }
  172. if pane.PAE != nil {
  173. writer.WritePAE()
  174. }
  175. if pane.BND != nil {
  176. writer.WriteBND(*pane.BND)
  177. }
  178. if pane.PIC != nil {
  179. writer.WritePIC(*pane.PIC)
  180. }
  181. if pane.TXT != nil {
  182. writer.WriteTXT(*pane.TXT)
  183. }
  184. if pane.WND != nil {
  185. writer.WriteWND(*pane.WND)
  186. }
  187. if pane.GRP != nil {
  188. writer.WriteGRP(*pane.GRP)
  189. }
  190. if pane.GRS != nil {
  191. writer.WriteGRS()
  192. }
  193. if pane.GRE != nil {
  194. writer.WriteGRE()
  195. }
  196. }
  197. binary.BigEndian.PutUint32(writer.Bytes()[8:12], uint32(writer.Len()))
  198. binary.BigEndian.PutUint16(writer.Bytes()[14:16], uint16(sectionCount))
  199. return writer.Bytes(), nil
  200. }
  201. func write(writer io.Writer, data interface{}) {
  202. err := binary.Write(writer, binary.BigEndian, data)
  203. if err != nil {
  204. panic(err)
  205. }
  206. }