real.go 3.2 KB

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