mirror of https://github.com/tidwall/tile38.git
212 lines
5.2 KiB
Go
212 lines
5.2 KiB
Go
|
package ndr
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/binary"
|
||
|
"math"
|
||
|
)
|
||
|
|
||
|
// Byte sizes of primitive types
|
||
|
const (
|
||
|
SizeBool = 1
|
||
|
SizeChar = 1
|
||
|
SizeUint8 = 1
|
||
|
SizeUint16 = 2
|
||
|
SizeUint32 = 4
|
||
|
SizeUint64 = 8
|
||
|
SizeEnum = 2
|
||
|
SizeSingle = 4
|
||
|
SizeDouble = 8
|
||
|
SizePtr = 4
|
||
|
)
|
||
|
|
||
|
// Bool is an NDR Boolean which is a logical quantity that assumes one of two values: TRUE or FALSE.
|
||
|
// NDR represents a Boolean as one octet.
|
||
|
// It represents a value of FALSE as a zero octet, an octet in which every bit is reset.
|
||
|
// It represents a value of TRUE as a non-zero octet, an octet in which one or more bits are set.
|
||
|
|
||
|
// Char is an NDR character.
|
||
|
// NDR represents a character as one octet.
|
||
|
// Characters have two representation formats: ASCII and EBCDIC.
|
||
|
|
||
|
// USmall is an unsigned 8 bit integer
|
||
|
|
||
|
// UShort is an unsigned 16 bit integer
|
||
|
|
||
|
// ULong is an unsigned 32 bit integer
|
||
|
|
||
|
// UHyper is an unsigned 64 bit integer
|
||
|
|
||
|
// Small is an signed 8 bit integer
|
||
|
|
||
|
// Short is an signed 16 bit integer
|
||
|
|
||
|
// Long is an signed 32 bit integer
|
||
|
|
||
|
// Hyper is an signed 64 bit integer
|
||
|
|
||
|
// Enum is the NDR representation of enumerated types as signed short integers (2 octets)
|
||
|
|
||
|
// Single is an NDR defined single-precision floating-point data type
|
||
|
|
||
|
// Double is an NDR defined double-precision floating-point data type
|
||
|
|
||
|
// readBool reads a byte representing a boolean.
|
||
|
// NDR represents a Boolean as one octet.
|
||
|
// It represents a value of FALSE as a zero octet, an octet in which every bit is reset.
|
||
|
// It represents a value of TRUE as a non-zero octet, an octet in which one or more bits are set.
|
||
|
func (dec *Decoder) readBool() (bool, error) {
|
||
|
i, err := dec.readUint8()
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
if i != 0 {
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
// readChar reads bytes representing a 8bit ASCII integer cast to a rune.
|
||
|
func (dec *Decoder) readChar() (rune, error) {
|
||
|
var r rune
|
||
|
a, err := dec.readUint8()
|
||
|
if err != nil {
|
||
|
return r, err
|
||
|
}
|
||
|
return rune(a), nil
|
||
|
}
|
||
|
|
||
|
// readUint8 reads bytes representing a 8bit unsigned integer.
|
||
|
func (dec *Decoder) readUint8() (uint8, error) {
|
||
|
b, err := dec.r.ReadByte()
|
||
|
if err != nil {
|
||
|
return uint8(0), err
|
||
|
}
|
||
|
return uint8(b), nil
|
||
|
}
|
||
|
|
||
|
// readUint16 reads bytes representing a 16bit unsigned integer.
|
||
|
func (dec *Decoder) readUint16() (uint16, error) {
|
||
|
dec.ensureAlignment(SizeUint16)
|
||
|
b, err := dec.readBytes(SizeUint16)
|
||
|
if err != nil {
|
||
|
return uint16(0), err
|
||
|
}
|
||
|
return dec.ch.Endianness.Uint16(b), nil
|
||
|
}
|
||
|
|
||
|
// readUint32 reads bytes representing a 32bit unsigned integer.
|
||
|
func (dec *Decoder) readUint32() (uint32, error) {
|
||
|
dec.ensureAlignment(SizeUint32)
|
||
|
b, err := dec.readBytes(SizeUint32)
|
||
|
if err != nil {
|
||
|
return uint32(0), err
|
||
|
}
|
||
|
return dec.ch.Endianness.Uint32(b), nil
|
||
|
}
|
||
|
|
||
|
// readUint32 reads bytes representing a 32bit unsigned integer.
|
||
|
func (dec *Decoder) readUint64() (uint64, error) {
|
||
|
dec.ensureAlignment(SizeUint64)
|
||
|
b, err := dec.readBytes(SizeUint64)
|
||
|
if err != nil {
|
||
|
return uint64(0), err
|
||
|
}
|
||
|
return dec.ch.Endianness.Uint64(b), nil
|
||
|
}
|
||
|
|
||
|
func (dec *Decoder) readInt8() (int8, error) {
|
||
|
dec.ensureAlignment(SizeUint8)
|
||
|
b, err := dec.readBytes(SizeUint8)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
var i int8
|
||
|
buf := bytes.NewReader(b)
|
||
|
err = binary.Read(buf, dec.ch.Endianness, &i)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
return i, nil
|
||
|
}
|
||
|
|
||
|
func (dec *Decoder) readInt16() (int16, error) {
|
||
|
dec.ensureAlignment(SizeUint16)
|
||
|
b, err := dec.readBytes(SizeUint16)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
var i int16
|
||
|
buf := bytes.NewReader(b)
|
||
|
err = binary.Read(buf, dec.ch.Endianness, &i)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
return i, nil
|
||
|
}
|
||
|
|
||
|
func (dec *Decoder) readInt32() (int32, error) {
|
||
|
dec.ensureAlignment(SizeUint32)
|
||
|
b, err := dec.readBytes(SizeUint32)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
var i int32
|
||
|
buf := bytes.NewReader(b)
|
||
|
err = binary.Read(buf, dec.ch.Endianness, &i)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
return i, nil
|
||
|
}
|
||
|
|
||
|
func (dec *Decoder) readInt64() (int64, error) {
|
||
|
dec.ensureAlignment(SizeUint64)
|
||
|
b, err := dec.readBytes(SizeUint64)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
var i int64
|
||
|
buf := bytes.NewReader(b)
|
||
|
err = binary.Read(buf, dec.ch.Endianness, &i)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
return i, nil
|
||
|
}
|
||
|
|
||
|
// https://en.wikipedia.org/wiki/IEEE_754-1985
|
||
|
func (dec *Decoder) readFloat32() (f float32, err error) {
|
||
|
dec.ensureAlignment(SizeSingle)
|
||
|
b, err := dec.readBytes(SizeSingle)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
bits := dec.ch.Endianness.Uint32(b)
|
||
|
f = math.Float32frombits(bits)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (dec *Decoder) readFloat64() (f float64, err error) {
|
||
|
dec.ensureAlignment(SizeDouble)
|
||
|
b, err := dec.readBytes(SizeDouble)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
bits := dec.ch.Endianness.Uint64(b)
|
||
|
f = math.Float64frombits(bits)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// NDR enforces NDR alignment of primitive data; that is, any primitive of size n octets is aligned at a octet stream
|
||
|
// index that is a multiple of n. (In this version of NDR, n is one of {1, 2, 4, 8}.) An octet stream index indicates
|
||
|
// the number of an octet in an octet stream when octets are numbered, beginning with 0, from the first octet in the
|
||
|
// stream. Where necessary, an alignment gap, consisting of octets of unspecified value, precedes the representation
|
||
|
// of a primitive. The gap is of the smallest size sufficient to align the primitive.
|
||
|
func (dec *Decoder) ensureAlignment(n int) {
|
||
|
p := dec.size - dec.r.Buffered()
|
||
|
if s := p % n; s != 0 {
|
||
|
dec.r.Discard(n - s)
|
||
|
}
|
||
|
}
|