mirror of
https://github.com/unidoc/unipdf.git
synced 2025-04-29 13:48:54 +08:00
104 lines
2.9 KiB
Go
104 lines
2.9 KiB
Go
package parseutils
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
"strconv"
|
|
|
|
"github.com/unidoc/unipdf/v3/common"
|
|
)
|
|
|
|
// ParseNumber parses a numeric objects from a buffered stream.
|
|
// Section 7.3.3.
|
|
// Integer or Float.
|
|
//
|
|
// An integer shall be written as one or more decimal digits optionally
|
|
// preceded by a sign. The value shall be interpreted as a signed
|
|
// decimal integer and shall be converted to an integer object.
|
|
//
|
|
// A real value shall be written as one or more decimal digits with an
|
|
// optional sign and a leading, trailing, or embedded PERIOD (2Eh)
|
|
// (decimal point). The value shall be interpreted as a real number
|
|
// and shall be converted to a real object.
|
|
//
|
|
// Regarding exponential numbers: 7.3.3 Numeric Objects:
|
|
// A conforming writer shall not use the PostScript syntax for numbers
|
|
// with non-decimal radices (such as 16#FFFE) or in exponential format
|
|
// (such as 6.02E23).
|
|
// Nonetheless, we sometimes get numbers with exponential format, so
|
|
// we will support it in the reader (no confusion with other types, so
|
|
// no compromise).
|
|
func ParseNumber(bufr *bufio.Reader) (interface{}, error) {
|
|
isFloat := false
|
|
allowSigns := true
|
|
var r bytes.Buffer
|
|
for {
|
|
if common.Log.IsLogLevel(common.LogLevelTrace) {
|
|
common.Log.Trace("Parsing number \"%s\"", r.String())
|
|
}
|
|
bb, err := bufr.Peek(1)
|
|
if err == io.EOF {
|
|
// GH: EOF handling. Handle EOF like end of line. Can happen with
|
|
// encoded object streams that the object is at the end.
|
|
// In other cases, we will get the EOF error elsewhere at any rate.
|
|
break // Handle like EOF
|
|
}
|
|
if err != nil {
|
|
common.Log.Debug("ERROR %s", err)
|
|
return nil, err
|
|
}
|
|
if allowSigns && (bb[0] == '-' || bb[0] == '+') {
|
|
// Only appear in the beginning, otherwise serves as a delimiter.
|
|
b, _ := bufr.ReadByte()
|
|
r.WriteByte(b)
|
|
allowSigns = false // Only allowed in beginning, and after e (exponential).
|
|
} else if IsDecimalDigit(bb[0]) {
|
|
b, _ := bufr.ReadByte()
|
|
r.WriteByte(b)
|
|
} else if bb[0] == '.' {
|
|
b, _ := bufr.ReadByte()
|
|
r.WriteByte(b)
|
|
isFloat = true
|
|
} else if bb[0] == 'e' || bb[0] == 'E' {
|
|
// Exponential number format.
|
|
b, _ := bufr.ReadByte()
|
|
r.WriteByte(b)
|
|
isFloat = true
|
|
allowSigns = true
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
var o interface{}
|
|
if isFloat {
|
|
fVal, err := strconv.ParseFloat(r.String(), 64)
|
|
if err != nil {
|
|
common.Log.Debug("Error parsing number %v err=%v. Using 0.0. Output may be incorrect", r.String(), err)
|
|
fVal = 0.0
|
|
err = nil
|
|
}
|
|
o = fVal
|
|
} else {
|
|
intVal, err := strconv.ParseInt(r.String(), 10, 64)
|
|
if err != nil {
|
|
common.Log.Debug("Error parsing number %v err=%v. Using 0. Output may be incorrect", r.String(), err)
|
|
intVal = 0
|
|
err = nil
|
|
}
|
|
o = intVal
|
|
}
|
|
|
|
return o, nil
|
|
}
|
|
|
|
// IsDecimalDigit checks if the character is a part of a decimal number string.
|
|
func IsDecimalDigit(c byte) bool {
|
|
if c >= '0' && c <= '9' {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|