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