gini.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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. "io"
  13. "strings"
  14. "github.com/gogf/gf/v2/errors/gcode"
  15. "github.com/gogf/gf/v2/errors/gerror"
  16. "github.com/gogf/gf/v2/internal/json"
  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. var (
  22. fieldMap = make(map[string]interface{})
  23. bytesReader = bytes.NewReader(data)
  24. bufioReader = bufio.NewReader(bytesReader)
  25. section string
  26. lastSection string
  27. haveSection bool
  28. line string
  29. )
  30. for {
  31. line, err = bufioReader.ReadString('\n')
  32. if err != nil {
  33. if err == io.EOF {
  34. break
  35. }
  36. err = gerror.Wrapf(err, `bufioReader.ReadString failed`)
  37. return nil, err
  38. }
  39. if line = strings.TrimSpace(line); len(line) == 0 {
  40. continue
  41. }
  42. if line[0] == ';' || line[0] == '#' {
  43. continue
  44. }
  45. var (
  46. sectionBeginPos = strings.Index(line, "[")
  47. sectionEndPos = strings.Index(line, "]")
  48. )
  49. if sectionBeginPos >= 0 && sectionEndPos >= 2 {
  50. section = line[sectionBeginPos+1 : sectionEndPos]
  51. if lastSection == "" {
  52. lastSection = section
  53. } else if lastSection != section {
  54. lastSection = section
  55. fieldMap = make(map[string]interface{})
  56. }
  57. haveSection = true
  58. } else if !haveSection {
  59. continue
  60. }
  61. if strings.Contains(line, "=") && haveSection {
  62. values := strings.Split(line, "=")
  63. fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], "="))
  64. res[section] = fieldMap
  65. }
  66. }
  67. if !haveSection {
  68. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "failed to parse INI file, section not found")
  69. }
  70. return res, nil
  71. }
  72. // Encode converts map to INI format.
  73. func Encode(data map[string]interface{}) (res []byte, err error) {
  74. var (
  75. n int
  76. w = new(bytes.Buffer)
  77. m map[string]interface{}
  78. ok bool
  79. )
  80. for section, item := range data {
  81. // Section key-value pairs.
  82. if m, ok = item.(map[string]interface{}); ok {
  83. n, err = w.WriteString(fmt.Sprintf("[%s]\n", section))
  84. if err != nil || n == 0 {
  85. return nil, gerror.Wrapf(err, "w.WriteString failed")
  86. }
  87. for k, v := range m {
  88. if n, err = w.WriteString(fmt.Sprintf("%s=%v\n", k, v)); err != nil || n == 0 {
  89. return nil, gerror.Wrapf(err, "w.WriteString failed")
  90. }
  91. }
  92. continue
  93. }
  94. // Simple key-value pairs.
  95. for k, v := range data {
  96. if n, err = w.WriteString(fmt.Sprintf("%s=%v\n", k, v)); err != nil || n == 0 {
  97. return nil, gerror.Wrapf(err, "w.WriteString failed")
  98. }
  99. }
  100. break
  101. }
  102. res = make([]byte, w.Len())
  103. if n, err = w.Read(res); err != nil || n == 0 {
  104. return nil, gerror.Wrapf(err, "w.Read failed")
  105. }
  106. return res, nil
  107. }
  108. // ToJson convert INI format to JSON.
  109. func ToJson(data []byte) (res []byte, err error) {
  110. iniMap, err := Decode(data)
  111. if err != nil {
  112. return nil, err
  113. }
  114. return json.Marshal(iniMap)
  115. }