1 package ber
2
3 import (
4 "bytes"
5 "errors"
6 "fmt"
7 "math"
8 "strconv"
9 "strings"
10 )
11
12 func encodeFloat(v float64) []byte {
13 switch {
14 case math.IsInf(v, 1):
15 return []byte{0x40}
16 case math.IsInf(v, -1):
17 return []byte{0x41}
18 case math.IsNaN(v):
19 return []byte{0x42}
20 case v == 0.0:
21 if math.Signbit(v) {
22 return []byte{0x43}
23 }
24 return []byte{}
25 default:
26
27 value := []byte(strconv.FormatFloat(v, 'G', -1, 64))
28 var ret []byte
29 if bytes.Contains(value, []byte{'E'}) {
30 ret = []byte{0x03}
31 } else {
32 ret = []byte{0x02}
33 }
34 ret = append(ret, value...)
35 return ret
36 }
37 }
38
39 func ParseReal(v []byte) (val float64, err error) {
40 if len(v) == 0 {
41 return 0.0, nil
42 }
43 switch {
44 case v[0]&0x80 == 0x80:
45 val, err = parseBinaryFloat(v)
46 case v[0]&0xC0 == 0x40:
47 val, err = parseSpecialFloat(v)
48 case v[0]&0xC0 == 0x0:
49 val, err = parseDecimalFloat(v)
50 default:
51 return 0.0, fmt.Errorf("invalid info block")
52 }
53 if err != nil {
54 return 0.0, err
55 }
56
57 if val == 0.0 && !math.Signbit(val) {
58 return 0.0, errors.New("REAL value +0 must be encoded with zero-length value block")
59 }
60 return val, nil
61 }
62
63 func parseBinaryFloat(v []byte) (float64, error) {
64 var info byte
65 var buf []byte
66
67 info, v = v[0], v[1:]
68
69 var base int
70 switch info & 0x30 {
71 case 0x00:
72 base = 2
73 case 0x10:
74 base = 8
75 case 0x20:
76 base = 16
77 case 0x30:
78 return 0.0, errors.New("bits 6 and 5 of information octet for REAL are equal to 11")
79 }
80
81 scale := uint((info & 0x0c) >> 2)
82
83 var expLen int
84 switch info & 0x03 {
85 case 0x00:
86 expLen = 1
87 case 0x01:
88 expLen = 2
89 case 0x02:
90 expLen = 3
91 case 0x03:
92 if len(v) < 2 {
93 return 0.0, errors.New("invalid data")
94 }
95 expLen = int(v[0])
96 if expLen > 8 {
97 return 0.0, errors.New("too big value of exponent")
98 }
99 v = v[1:]
100 }
101 if expLen > len(v) {
102 return 0.0, errors.New("too big value of exponent")
103 }
104 buf, v = v[:expLen], v[expLen:]
105 exponent, err := ParseInt64(buf)
106 if err != nil {
107 return 0.0, err
108 }
109
110 if len(v) > 8 {
111 return 0.0, errors.New("too big value of mantissa")
112 }
113
114 mant, err := ParseInt64(v)
115 if err != nil {
116 return 0.0, err
117 }
118 mantissa := mant << scale
119
120 if info&0x40 == 0x40 {
121 mantissa = -mantissa
122 }
123
124 return float64(mantissa) * math.Pow(float64(base), float64(exponent)), nil
125 }
126
127 func parseDecimalFloat(v []byte) (val float64, err error) {
128 switch v[0] & 0x3F {
129 case 0x01:
130 var iVal int64
131 iVal, err = strconv.ParseInt(strings.TrimLeft(string(v[1:]), " "), 10, 64)
132 val = float64(iVal)
133 case 0x02, 0x03:
134 val, err = strconv.ParseFloat(strings.Replace(strings.TrimLeft(string(v[1:]), " "), ",", ".", -1), 64)
135 default:
136 err = errors.New("incorrect NR form")
137 }
138 if err != nil {
139 return 0.0, err
140 }
141
142 if val == 0.0 && math.Signbit(val) {
143 return 0.0, errors.New("REAL value -0 must be encoded as a special value")
144 }
145 return val, nil
146 }
147
148 func parseSpecialFloat(v []byte) (float64, error) {
149 if len(v) != 1 {
150 return 0.0, errors.New(`encoding of "special value" must not contain exponent and mantissa`)
151 }
152 switch v[0] {
153 case 0x40:
154 return math.Inf(1), nil
155 case 0x41:
156 return math.Inf(-1), nil
157 case 0x42:
158 return math.NaN(), nil
159 case 0x43:
160 return math.Copysign(0, -1), nil
161 }
162 return 0.0, errors.New(`encoding of "special value" not from ASN.1 standard`)
163 }
164
View as plain text