285 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			285 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
package ini
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
)
 | 
						|
 | 
						|
// getStringValue will return a quoted string and the amount
 | 
						|
// of bytes read
 | 
						|
//
 | 
						|
// an error will be returned if the string is not properly formatted
 | 
						|
func getStringValue(b []rune) (int, error) {
 | 
						|
	if b[0] != '"' {
 | 
						|
		return 0, NewParseError("strings must start with '\"'")
 | 
						|
	}
 | 
						|
 | 
						|
	endQuote := false
 | 
						|
	i := 1
 | 
						|
 | 
						|
	for ; i < len(b) && !endQuote; i++ {
 | 
						|
		if escaped := isEscaped(b[:i], b[i]); b[i] == '"' && !escaped {
 | 
						|
			endQuote = true
 | 
						|
			break
 | 
						|
		} else if escaped {
 | 
						|
			/*c, err := getEscapedByte(b[i])
 | 
						|
			if err != nil {
 | 
						|
				return 0, err
 | 
						|
			}
 | 
						|
 | 
						|
			b[i-1] = c
 | 
						|
			b = append(b[:i], b[i+1:]...)
 | 
						|
			i--*/
 | 
						|
 | 
						|
			continue
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if !endQuote {
 | 
						|
		return 0, NewParseError("missing '\"' in string value")
 | 
						|
	}
 | 
						|
 | 
						|
	return i + 1, nil
 | 
						|
}
 | 
						|
 | 
						|
// getBoolValue will return a boolean and the amount
 | 
						|
// of bytes read
 | 
						|
//
 | 
						|
// an error will be returned if the boolean is not of a correct
 | 
						|
// value
 | 
						|
func getBoolValue(b []rune) (int, error) {
 | 
						|
	if len(b) < 4 {
 | 
						|
		return 0, NewParseError("invalid boolean value")
 | 
						|
	}
 | 
						|
 | 
						|
	n := 0
 | 
						|
	for _, lv := range literalValues {
 | 
						|
		if len(lv) > len(b) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if isCaselessLitValue(lv, b) {
 | 
						|
			n = len(lv)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if n == 0 {
 | 
						|
		return 0, NewParseError("invalid boolean value")
 | 
						|
	}
 | 
						|
 | 
						|
	return n, nil
 | 
						|
}
 | 
						|
 | 
						|
// getNumericalValue will return a numerical string, the amount
 | 
						|
// of bytes read, and the base of the number
 | 
						|
//
 | 
						|
// an error will be returned if the number is not of a correct
 | 
						|
// value
 | 
						|
func getNumericalValue(b []rune) (int, int, error) {
 | 
						|
	if !isDigit(b[0]) {
 | 
						|
		return 0, 0, NewParseError("invalid digit value")
 | 
						|
	}
 | 
						|
 | 
						|
	i := 0
 | 
						|
	helper := numberHelper{}
 | 
						|
 | 
						|
loop:
 | 
						|
	for negativeIndex := 0; i < len(b); i++ {
 | 
						|
		negativeIndex++
 | 
						|
 | 
						|
		if !isDigit(b[i]) {
 | 
						|
			switch b[i] {
 | 
						|
			case '-':
 | 
						|
				if helper.IsNegative() || negativeIndex != 1 {
 | 
						|
					return 0, 0, NewParseError("parse error '-'")
 | 
						|
				}
 | 
						|
 | 
						|
				n := getNegativeNumber(b[i:])
 | 
						|
				i += (n - 1)
 | 
						|
				helper.Determine(b[i])
 | 
						|
				continue
 | 
						|
			case '.':
 | 
						|
				if err := helper.Determine(b[i]); err != nil {
 | 
						|
					return 0, 0, err
 | 
						|
				}
 | 
						|
			case 'e', 'E':
 | 
						|
				if err := helper.Determine(b[i]); err != nil {
 | 
						|
					return 0, 0, err
 | 
						|
				}
 | 
						|
 | 
						|
				negativeIndex = 0
 | 
						|
			case 'b':
 | 
						|
				if helper.numberFormat == hex {
 | 
						|
					break
 | 
						|
				}
 | 
						|
				fallthrough
 | 
						|
			case 'o', 'x':
 | 
						|
				if i == 0 && b[i] != '0' {
 | 
						|
					return 0, 0, NewParseError("incorrect base format, expected leading '0'")
 | 
						|
				}
 | 
						|
 | 
						|
				if i != 1 {
 | 
						|
					return 0, 0, NewParseError(fmt.Sprintf("incorrect base format found %s at %d index", string(b[i]), i))
 | 
						|
				}
 | 
						|
 | 
						|
				if err := helper.Determine(b[i]); err != nil {
 | 
						|
					return 0, 0, err
 | 
						|
				}
 | 
						|
			default:
 | 
						|
				if isWhitespace(b[i]) {
 | 
						|
					break loop
 | 
						|
				}
 | 
						|
 | 
						|
				if isNewline(b[i:]) {
 | 
						|
					break loop
 | 
						|
				}
 | 
						|
 | 
						|
				if !(helper.numberFormat == hex && isHexByte(b[i])) {
 | 
						|
					if i+2 < len(b) && !isNewline(b[i:i+2]) {
 | 
						|
						return 0, 0, NewParseError("invalid numerical character")
 | 
						|
					} else if !isNewline([]rune{b[i]}) {
 | 
						|
						return 0, 0, NewParseError("invalid numerical character")
 | 
						|
					}
 | 
						|
 | 
						|
					break loop
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return helper.Base(), i, nil
 | 
						|
}
 | 
						|
 | 
						|
// isDigit will return whether or not something is an integer
 | 
						|
func isDigit(b rune) bool {
 | 
						|
	return b >= '0' && b <= '9'
 | 
						|
}
 | 
						|
 | 
						|
func hasExponent(v []rune) bool {
 | 
						|
	return contains(v, 'e') || contains(v, 'E')
 | 
						|
}
 | 
						|
 | 
						|
func isBinaryByte(b rune) bool {
 | 
						|
	switch b {
 | 
						|
	case '0', '1':
 | 
						|
		return true
 | 
						|
	default:
 | 
						|
		return false
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func isOctalByte(b rune) bool {
 | 
						|
	switch b {
 | 
						|
	case '0', '1', '2', '3', '4', '5', '6', '7':
 | 
						|
		return true
 | 
						|
	default:
 | 
						|
		return false
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func isHexByte(b rune) bool {
 | 
						|
	if isDigit(b) {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	return (b >= 'A' && b <= 'F') ||
 | 
						|
		(b >= 'a' && b <= 'f')
 | 
						|
}
 | 
						|
 | 
						|
func getValue(b []rune) (int, error) {
 | 
						|
	i := 0
 | 
						|
 | 
						|
	for i < len(b) {
 | 
						|
		if isNewline(b[i:]) {
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		if isOp(b[i:]) {
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		valid, n, err := isValid(b[i:])
 | 
						|
		if err != nil {
 | 
						|
			return 0, err
 | 
						|
		}
 | 
						|
 | 
						|
		if !valid {
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		i += n
 | 
						|
	}
 | 
						|
 | 
						|
	return i, nil
 | 
						|
}
 | 
						|
 | 
						|
// getNegativeNumber will return a negative number from a
 | 
						|
// byte slice. This will iterate through all characters until
 | 
						|
// a non-digit has been found.
 | 
						|
func getNegativeNumber(b []rune) int {
 | 
						|
	if b[0] != '-' {
 | 
						|
		return 0
 | 
						|
	}
 | 
						|
 | 
						|
	i := 1
 | 
						|
	for ; i < len(b); i++ {
 | 
						|
		if !isDigit(b[i]) {
 | 
						|
			return i
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return i
 | 
						|
}
 | 
						|
 | 
						|
// isEscaped will return whether or not the character is an escaped
 | 
						|
// character.
 | 
						|
func isEscaped(value []rune, b rune) bool {
 | 
						|
	if len(value) == 0 {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch b {
 | 
						|
	case '\'': // single quote
 | 
						|
	case '"': // quote
 | 
						|
	case 'n': // newline
 | 
						|
	case 't': // tab
 | 
						|
	case '\\': // backslash
 | 
						|
	default:
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	return value[len(value)-1] == '\\'
 | 
						|
}
 | 
						|
 | 
						|
func getEscapedByte(b rune) (rune, error) {
 | 
						|
	switch b {
 | 
						|
	case '\'': // single quote
 | 
						|
		return '\'', nil
 | 
						|
	case '"': // quote
 | 
						|
		return '"', nil
 | 
						|
	case 'n': // newline
 | 
						|
		return '\n', nil
 | 
						|
	case 't': // table
 | 
						|
		return '\t', nil
 | 
						|
	case '\\': // backslash
 | 
						|
		return '\\', nil
 | 
						|
	default:
 | 
						|
		return b, NewParseError(fmt.Sprintf("invalid escaped character %c", b))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func removeEscapedCharacters(b []rune) []rune {
 | 
						|
	for i := 0; i < len(b); i++ {
 | 
						|
		if isEscaped(b[:i], b[i]) {
 | 
						|
			c, err := getEscapedByte(b[i])
 | 
						|
			if err != nil {
 | 
						|
				return b
 | 
						|
			}
 | 
						|
 | 
						|
			b[i-1] = c
 | 
						|
			b = append(b[:i], b[i+1:]...)
 | 
						|
			i--
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return b
 | 
						|
}
 |