node.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Package xpj reads and writes MPC Sample project files (.xpj).
  2. //
  3. // A project file is a gzip stream holding five header lines and one JSON
  4. // document. The JSON is held as an ordered tree: objects keep their key order
  5. // and numbers keep their original text, so a file that is read and written
  6. // back unchanged is byte-identical after decompression. The package knows
  7. // nothing about pads, samples or sequences.
  8. package xpj
  9. import (
  10. "fmt"
  11. "math"
  12. "strconv"
  13. "strings"
  14. )
  15. // Kind is the JSON type of a Node.
  16. type Kind int
  17. const (
  18. Null Kind = iota
  19. Bool
  20. Number
  21. String
  22. Array
  23. Object
  24. )
  25. func (k Kind) String() string {
  26. switch k {
  27. case Null:
  28. return "null"
  29. case Bool:
  30. return "bool"
  31. case Number:
  32. return "number"
  33. case String:
  34. return "string"
  35. case Array:
  36. return "array"
  37. case Object:
  38. return "object"
  39. }
  40. return fmt.Sprintf("Kind(%d)", int(k))
  41. }
  42. // Node is one JSON value.
  43. type Node struct {
  44. Kind Kind
  45. // Text is the decoded value of a String, or the literal text of a Number.
  46. Text string
  47. Bool bool
  48. Items []*Node // Array elements
  49. Members []Member // Object members, in file order
  50. }
  51. // Member is one key/value pair of an object.
  52. type Member struct {
  53. Key string
  54. Value *Node
  55. }
  56. // NewNull returns a null node.
  57. func NewNull() *Node { return &Node{Kind: Null} }
  58. // NewBool returns a boolean node.
  59. func NewBool(b bool) *Node { return &Node{Kind: Bool, Bool: b} }
  60. // NewString returns a string node.
  61. func NewString(s string) *Node { return &Node{Kind: String, Text: s} }
  62. // NewInt returns a number node written as an integer, e.g. 4.
  63. func NewInt(i int64) *Node { return &Node{Kind: Number, Text: strconv.FormatInt(i, 10)} }
  64. // NewFloat returns a number node for a float field. It is always written with
  65. // a decimal point or exponent (96.0, never 96), in the shortest form that
  66. // reads back as the same float64. It panics on NaN or infinity, which JSON
  67. // cannot hold.
  68. func NewFloat(f float64) *Node { return &Node{Kind: Number, Text: FormatFloat(f)} }
  69. // NewFloat32 is NewFloat for a field the device stores as a 32-bit float:
  70. // the value is rounded to float32 first, then printed as a float64
  71. // (12.4 is written as 12.399999618530273).
  72. func NewFloat32(f float64) *Node { return NewFloat(float64(float32(f))) }
  73. // NewArray returns an array node holding items.
  74. func NewArray(items ...*Node) *Node { return &Node{Kind: Array, Items: items} }
  75. // NewObject returns an empty object node.
  76. func NewObject() *Node { return &Node{Kind: Object} }
  77. // FormatFloat prints f the way the reference writer (Python's repr) does:
  78. // shortest round-trip digits, plain notation for exponents from -4 to 15
  79. // with at least one digit after the point, otherwise d.ddde±XX.
  80. func FormatFloat(f float64) string {
  81. if math.IsNaN(f) || math.IsInf(f, 0) {
  82. panic("xpj: cannot write NaN or infinity")
  83. }
  84. s := strconv.FormatFloat(f, 'e', -1, 64) // e.g. -1.2345e+01
  85. mant, expStr, _ := strings.Cut(s, "e")
  86. exp, _ := strconv.Atoi(expStr)
  87. neg := strings.HasPrefix(mant, "-")
  88. digits := strings.Replace(strings.TrimPrefix(mant, "-"), ".", "", 1)
  89. var out string
  90. if exp < -4 || exp >= 16 {
  91. out = digits[:1]
  92. if len(digits) > 1 {
  93. out += "." + digits[1:]
  94. }
  95. sign := "+"
  96. if exp < 0 {
  97. sign, exp = "-", -exp
  98. }
  99. out += fmt.Sprintf("e%s%02d", sign, exp)
  100. } else if exp < 0 {
  101. out = "0." + strings.Repeat("0", -exp-1) + digits
  102. } else if exp+1 >= len(digits) {
  103. out = digits + strings.Repeat("0", exp+1-len(digits)) + ".0"
  104. } else {
  105. out = digits[:exp+1] + "." + digits[exp+1:]
  106. }
  107. if neg {
  108. out = "-" + out
  109. }
  110. return out
  111. }
  112. // Int returns the value of a Number node as an integer.
  113. func (n *Node) Int() (int64, error) {
  114. if n.Kind != Number {
  115. return 0, fmt.Errorf("xpj: %s is not a number", n.Kind)
  116. }
  117. if i, err := strconv.ParseInt(n.Text, 10, 64); err == nil {
  118. return i, nil
  119. }
  120. f, err := strconv.ParseFloat(n.Text, 64)
  121. if err != nil || f != math.Trunc(f) || math.Abs(f) > 1<<53 {
  122. return 0, fmt.Errorf("xpj: %s is not an integer", n.Text)
  123. }
  124. return int64(f), nil
  125. }
  126. // Float returns the value of a Number node.
  127. func (n *Node) Float() (float64, error) {
  128. if n.Kind != Number {
  129. return 0, fmt.Errorf("xpj: %s is not a number", n.Kind)
  130. }
  131. return strconv.ParseFloat(n.Text, 64)
  132. }
  133. // Lookup returns the value of the first member called key, or nil if n is not
  134. // an object or has no such member.
  135. func (n *Node) Lookup(key string) *Node {
  136. if n == nil || n.Kind != Object {
  137. return nil
  138. }
  139. for _, m := range n.Members {
  140. if m.Key == key {
  141. return m.Value
  142. }
  143. }
  144. return nil
  145. }
  146. // SetKey replaces the value of the first member called key, keeping its
  147. // position, or appends a new member if there is none.
  148. func (n *Node) SetKey(key string, v *Node) error {
  149. if n.Kind != Object {
  150. return fmt.Errorf("xpj: cannot set key %q on %s", key, n.Kind)
  151. }
  152. for i := range n.Members {
  153. if n.Members[i].Key == key {
  154. n.Members[i].Value = v
  155. return nil
  156. }
  157. }
  158. n.Members = append(n.Members, Member{Key: key, Value: v})
  159. return nil
  160. }
  161. // DeleteKey removes the first member called key and reports whether it was there.
  162. func (n *Node) DeleteKey(key string) bool {
  163. if n.Kind != Object {
  164. return false
  165. }
  166. for i, m := range n.Members {
  167. if m.Key == key {
  168. n.Members = append(n.Members[:i], n.Members[i+1:]...)
  169. return true
  170. }
  171. }
  172. return false
  173. }
  174. // Insert puts v into an array at index i (0 <= i <= len), shifting later items.
  175. func (n *Node) Insert(i int, v *Node) error {
  176. if n.Kind != Array {
  177. return fmt.Errorf("xpj: cannot insert into %s", n.Kind)
  178. }
  179. if i < 0 || i > len(n.Items) {
  180. return fmt.Errorf("xpj: insert index %d out of range [0,%d]", i, len(n.Items))
  181. }
  182. n.Items = append(n.Items, nil)
  183. copy(n.Items[i+1:], n.Items[i:])
  184. n.Items[i] = v
  185. return nil
  186. }
  187. // Append adds v to the end of an array.
  188. func (n *Node) Append(v *Node) error { return n.Insert(len(n.Items), v) }
  189. // Remove deletes the array item at index i.
  190. func (n *Node) Remove(i int) error {
  191. if n.Kind != Array {
  192. return fmt.Errorf("xpj: cannot remove from %s", n.Kind)
  193. }
  194. if i < 0 || i >= len(n.Items) {
  195. return fmt.Errorf("xpj: remove index %d out of range [0,%d)", i, len(n.Items))
  196. }
  197. n.Items = append(n.Items[:i], n.Items[i+1:]...)
  198. return nil
  199. }
  200. // Clone returns a deep copy of n.
  201. func (n *Node) Clone() *Node {
  202. if n == nil {
  203. return nil
  204. }
  205. c := &Node{Kind: n.Kind, Text: n.Text, Bool: n.Bool}
  206. if n.Items != nil {
  207. c.Items = make([]*Node, len(n.Items))
  208. for i, it := range n.Items {
  209. c.Items[i] = it.Clone()
  210. }
  211. }
  212. if n.Members != nil {
  213. c.Members = make([]Member, len(n.Members))
  214. for i, m := range n.Members {
  215. c.Members[i] = Member{Key: m.Key, Value: m.Value.Clone()}
  216. }
  217. }
  218. return c
  219. }