...

Source file src/github.com/go-asn1-ber/asn1-ber/real.go

Documentation: github.com/go-asn1-ber/asn1-ber

     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  		// we take the easy part ;-)
    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: // NR form 1
   130  		var iVal int64
   131  		iVal, err = strconv.ParseInt(strings.TrimLeft(string(v[1:]), " "), 10, 64)
   132  		val = float64(iVal)
   133  	case 0x02, 0x03: // NR form 2, 3
   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