gini.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // Copyright 2017 gf Author(https://github.com/gogf/gf). 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. "errors"
  12. "fmt"
  13. "github.com/gogf/gf/internal/json"
  14. "io"
  15. "strings"
  16. )
  17. // Decode converts INI format to map.
  18. func Decode(data []byte) (res map[string]interface{}, err error) {
  19. res = make(map[string]interface{})
  20. fieldMap := make(map[string]interface{})
  21. a := bytes.NewReader(data)
  22. r := bufio.NewReader(a)
  23. var section string
  24. var lastSection string
  25. var haveSection bool
  26. for {
  27. line, err := r.ReadString('\n')
  28. if err != nil {
  29. if err == io.EOF {
  30. break
  31. }
  32. return nil, err
  33. }
  34. lineStr := strings.TrimSpace(string(line))
  35. if len(lineStr) == 0 {
  36. continue
  37. }
  38. if lineStr[0] == ';' || lineStr[0] == '#' {
  39. continue
  40. }
  41. sectionBeginPos := strings.Index(lineStr, "[")
  42. sectionEndPos := strings.Index(lineStr, "]")
  43. if sectionBeginPos >= 0 && sectionEndPos >= 2 {
  44. section = lineStr[sectionBeginPos+1 : sectionEndPos]
  45. if lastSection == "" {
  46. lastSection = section
  47. } else if lastSection != section {
  48. lastSection = section
  49. fieldMap = make(map[string]interface{})
  50. }
  51. haveSection = true
  52. } else if haveSection == false {
  53. continue
  54. }
  55. if strings.Contains(lineStr, "=") && haveSection {
  56. values := strings.Split(lineStr, "=")
  57. fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], ""))
  58. res[section] = fieldMap
  59. }
  60. }
  61. if haveSection == false {
  62. return nil, errors.New("failed to parse INI file, section not found")
  63. }
  64. return res, nil
  65. }
  66. // Encode converts map to INI format.
  67. func Encode(data map[string]interface{}) (res []byte, err error) {
  68. w := new(bytes.Buffer)
  69. w.WriteString("; this ini file is produced by package gini\n")
  70. for k, v := range data {
  71. n, err := w.WriteString(fmt.Sprintf("[%s]\n", k))
  72. if err != nil || n == 0 {
  73. return nil, fmt.Errorf("write data failed. %v", err)
  74. }
  75. for kk, vv := range v.(map[string]interface{}) {
  76. n, err := w.WriteString(fmt.Sprintf("%s=%s\n", kk, vv.(string)))
  77. if err != nil || n == 0 {
  78. return nil, fmt.Errorf("write data failed. %v", err)
  79. }
  80. }
  81. }
  82. res = make([]byte, w.Len())
  83. n, err := w.Read(res)
  84. if err != nil || n == 0 {
  85. return nil, fmt.Errorf("write data failed. %v", err)
  86. }
  87. return res, nil
  88. }
  89. // ToJson convert INI format to JSON.
  90. func ToJson(data []byte) (res []byte, err error) {
  91. iniMap, err := Decode(data)
  92. if err != nil {
  93. return nil, err
  94. }
  95. return json.Marshal(iniMap)
  96. }