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