summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-asn1-ber/asn1-ber/real.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-asn1-ber/asn1-ber/real.go')
-rw-r--r--vendor/github.com/go-asn1-ber/asn1-ber/real.go157
1 files changed, 157 insertions, 0 deletions
diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/real.go b/vendor/github.com/go-asn1-ber/asn1-ber/real.go
new file mode 100644
index 00000000..610a003a
--- /dev/null
+++ b/vendor/github.com/go-asn1-ber/asn1-ber/real.go
@@ -0,0 +1,157 @@
+package ber
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+)
+
+func encodeFloat(v float64) []byte {
+ switch {
+ case math.IsInf(v, 1):
+ return []byte{0x40}
+ case math.IsInf(v, -1):
+ return []byte{0x41}
+ case math.IsNaN(v):
+ return []byte{0x42}
+ case v == 0.0:
+ if math.Signbit(v) {
+ return []byte{0x43}
+ }
+ return []byte{}
+ default:
+ // we take the easy part ;-)
+ value := []byte(strconv.FormatFloat(v, 'G', -1, 64))
+ var ret []byte
+ if bytes.Contains(value, []byte{'E'}) {
+ ret = []byte{0x03}
+ } else {
+ ret = []byte{0x02}
+ }
+ ret = append(ret, value...)
+ return ret
+ }
+}
+
+func ParseReal(v []byte) (val float64, err error) {
+ if len(v) == 0 {
+ return 0.0, nil
+ }
+ switch {
+ case v[0]&0x80 == 0x80:
+ val, err = parseBinaryFloat(v)
+ case v[0]&0xC0 == 0x40:
+ val, err = parseSpecialFloat(v)
+ case v[0]&0xC0 == 0x0:
+ val, err = parseDecimalFloat(v)
+ default:
+ return 0.0, fmt.Errorf("invalid info block")
+ }
+ if err != nil {
+ return 0.0, err
+ }
+
+ if val == 0.0 && !math.Signbit(val) {
+ return 0.0, errors.New("REAL value +0 must be encoded with zero-length value block")
+ }
+ return val, nil
+}
+
+func parseBinaryFloat(v []byte) (float64, error) {
+ var info byte
+ var buf []byte
+
+ info, v = v[0], v[1:]
+
+ var base int
+ switch info & 0x30 {
+ case 0x00:
+ base = 2
+ case 0x10:
+ base = 8
+ case 0x20:
+ base = 16
+ case 0x30:
+ return 0.0, errors.New("bits 6 and 5 of information octet for REAL are equal to 11")
+ }
+
+ scale := uint((info & 0x0c) >> 2)
+
+ var expLen int
+ switch info & 0x03 {
+ case 0x00:
+ expLen = 1
+ case 0x01:
+ expLen = 2
+ case 0x02:
+ expLen = 3
+ case 0x03:
+ expLen = int(v[0])
+ if expLen > 8 {
+ return 0.0, errors.New("too big value of exponent")
+ }
+ v = v[1:]
+ }
+ buf, v = v[:expLen], v[expLen:]
+ exponent, err := ParseInt64(buf)
+ if err != nil {
+ return 0.0, err
+ }
+
+ if len(v) > 8 {
+ return 0.0, errors.New("too big value of mantissa")
+ }
+
+ mant, err := ParseInt64(v)
+ if err != nil {
+ return 0.0, err
+ }
+ mantissa := mant << scale
+
+ if info&0x40 == 0x40 {
+ mantissa = -mantissa
+ }
+
+ return float64(mantissa) * math.Pow(float64(base), float64(exponent)), nil
+}
+
+func parseDecimalFloat(v []byte) (val float64, err error) {
+ switch v[0] & 0x3F {
+ case 0x01: // NR form 1
+ var iVal int64
+ iVal, err = strconv.ParseInt(strings.TrimLeft(string(v[1:]), " "), 10, 64)
+ val = float64(iVal)
+ case 0x02, 0x03: // NR form 2, 3
+ val, err = strconv.ParseFloat(strings.Replace(strings.TrimLeft(string(v[1:]), " "), ",", ".", -1), 64)
+ default:
+ err = errors.New("incorrect NR form")
+ }
+ if err != nil {
+ return 0.0, err
+ }
+
+ if val == 0.0 && math.Signbit(val) {
+ return 0.0, errors.New("REAL value -0 must be encoded as a special value")
+ }
+ return val, nil
+}
+
+func parseSpecialFloat(v []byte) (float64, error) {
+ if len(v) != 1 {
+ return 0.0, errors.New(`encoding of "special value" must not contain exponent and mantissa`)
+ }
+ switch v[0] {
+ case 0x40:
+ return math.Inf(1), nil
+ case 0x41:
+ return math.Inf(-1), nil
+ case 0x42:
+ return math.NaN(), nil
+ case 0x43:
+ return math.Copysign(0, -1), nil
+ }
+ return 0.0, errors.New(`encoding of "special value" not from ASN.1 standard`)
+}