gini.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. // Package gini provides accessing and converting for INI content.
  7. package gini
  8. import (
  9. "bufio"
  10. "bytes"
  11. "fmt"
  12. "github.com/gogf/gf/errors/gcode"
  13. "github.com/gogf/gf/errors/gerror"
  14. "github.com/gogf/gf/internal/json"
  15. "io"
  16. "strings"
  17. )
  18. // Decode converts INI format to map.
  19. func Decode(data []byte) (res map[string]interface{}, err error) {
  20. res = make(map[string]interface{})
  21. fieldMap := make(map[string]interface{})
  22. a := bytes.NewReader(data)
  23. r := bufio.NewReader(a)
  24. var section string
  25. var lastSection string
  26. var haveSection bool
  27. for {
  28. line, err := r.ReadString('\n')
  29. if err != nil {
  30. if err == io.EOF {
  31. break
  32. }
  33. return nil, err
  34. }
  35. lineStr := strings.TrimSpace(string(line))
  36. if len(lineStr) == 0 {
  37. continue
  38. }
  39. if lineStr[0] == ';' || lineStr[0] == '#' {
  40. continue
  41. }
  42. sectionBeginPos := strings.Index(lineStr, "[")
  43. sectionEndPos := strings.Index(lineStr, "]")
  44. if sectionBeginPos >= 0 && sectionEndPos >= 2 {
  45. section = lineStr[sectionBeginPos+1 : sectionEndPos]
  46. if lastSection == "" {
  47. lastSection = section
  48. } else if lastSection != section {
  49. lastSection = section
  50. fieldMap = make(map[string]interface{})
  51. }
  52. haveSection = true
  53. } else if haveSection == false {
  54. continue
  55. }
  56. if strings.Contains(lineStr, "=") && haveSection {
  57. values := strings.Split(lineStr, "=")
  58. fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], ""))
  59. res[section] = fieldMap
  60. }
  61. }
  62. if haveSection == false {
  63. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "failed to parse INI file, section not found")
  64. }
  65. return res, nil
  66. }
  67. // Encode converts map to INI format.
  68. func Encode(data map[string]interface{}) (res []byte, err error) {
  69. w := new(bytes.Buffer)
  70. w.WriteString("; this ini file is produced by package gini\n")
  71. for k, v := range data {
  72. n, err := w.WriteString(fmt.Sprintf("[%s]\n", k))
  73. if err != nil || n == 0 {
  74. return nil, fmt.Errorf("write data failed. %v", err)
  75. }
  76. for kk, vv := range v.(map[string]interface{}) {
  77. n, err := w.WriteString(fmt.Sprintf("%s=%s\n", kk, vv.(string)))
  78. if err != nil || n == 0 {
  79. return nil, fmt.Errorf("write data failed. %v", err)
  80. }
  81. }
  82. }
  83. res = make([]byte, w.Len())
  84. n, err := w.Read(res)
  85. if err != nil || n == 0 {
  86. return nil, fmt.Errorf("write data failed. %v", err)
  87. }
  88. return res, nil
  89. }
  90. // ToJson convert INI format to JSON.
  91. func ToJson(data []byte) (res []byte, err error) {
  92. iniMap, err := Decode(data)
  93. if err != nil {
  94. return nil, err
  95. }
  96. return json.Marshal(iniMap)
  97. }