2020-02-23 14:36:57 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-11-24 18:10:52 +00:00
|
|
|
if isCaselessLitValue(lv, b) {
|
2020-02-23 14:36:57 +00:00
|
|
|
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
|
|
|
|
}
|