mirror of https://github.com/tidwall/tile38.git
117 lines
3.9 KiB
Go
117 lines
3.9 KiB
Go
|
package ndr
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
/*
|
||
|
Serialization Version 1
|
||
|
https://msdn.microsoft.com/en-us/library/cc243563.aspx
|
||
|
|
||
|
Common Header - https://msdn.microsoft.com/en-us/library/cc243890.aspx
|
||
|
8 bytes in total:
|
||
|
- First byte - Version: Must equal 1
|
||
|
- Second byte - 1st 4 bits: Endianess (0=Big; 1=Little); 2nd 4 bits: Character Encoding (0=ASCII; 1=EBCDIC)
|
||
|
- 3rd - Floating point representation (This does not seem to be the case in examples for Microsoft test sources)
|
||
|
- 4th - Common Header Length: Must equal 8
|
||
|
- 5th - 8th - Filler: MUST be set to 0xcccccccc on marshaling, and SHOULD be ignored during unmarshaling.
|
||
|
|
||
|
Private Header - https://msdn.microsoft.com/en-us/library/cc243919.aspx
|
||
|
8 bytes in total:
|
||
|
- First 4 bytes - Indicates the length of a serialized top-level type in the octet stream. It MUST include the padding length and exclude the header itself.
|
||
|
- Second 4 bytes - Filler: MUST be set to 0 (zero) during marshaling, and SHOULD be ignored during unmarshaling.
|
||
|
*/
|
||
|
|
||
|
const (
|
||
|
protocolVersion uint8 = 1
|
||
|
commonHeaderBytes uint16 = 8
|
||
|
bigEndian = 0
|
||
|
littleEndian = 1
|
||
|
ascii uint8 = 0
|
||
|
ebcdic uint8 = 1
|
||
|
ieee uint8 = 0
|
||
|
vax uint8 = 1
|
||
|
cray uint8 = 2
|
||
|
ibm uint8 = 3
|
||
|
)
|
||
|
|
||
|
// CommonHeader implements the NDR common header: https://msdn.microsoft.com/en-us/library/cc243889.aspx
|
||
|
type CommonHeader struct {
|
||
|
Version uint8
|
||
|
Endianness binary.ByteOrder
|
||
|
CharacterEncoding uint8
|
||
|
FloatRepresentation uint8
|
||
|
HeaderLength uint16
|
||
|
Filler []byte
|
||
|
}
|
||
|
|
||
|
// PrivateHeader implements the NDR private header: https://msdn.microsoft.com/en-us/library/cc243919.aspx
|
||
|
type PrivateHeader struct {
|
||
|
ObjectBufferLength uint32
|
||
|
Filler []byte
|
||
|
}
|
||
|
|
||
|
func (dec *Decoder) readCommonHeader() error {
|
||
|
// Version
|
||
|
vb, err := dec.r.ReadByte()
|
||
|
if err != nil {
|
||
|
return Malformed{EText: "could not read first byte of common header for version"}
|
||
|
}
|
||
|
dec.ch.Version = uint8(vb)
|
||
|
if dec.ch.Version != protocolVersion {
|
||
|
return Malformed{EText: fmt.Sprintf("byte stream does not indicate a RPC Type serialization of version %v", protocolVersion)}
|
||
|
}
|
||
|
// Read Endianness & Character Encoding
|
||
|
eb, err := dec.r.ReadByte()
|
||
|
if err != nil {
|
||
|
return Malformed{EText: "could not read second byte of common header for endianness"}
|
||
|
}
|
||
|
endian := int(eb >> 4 & 0xF)
|
||
|
if endian != 0 && endian != 1 {
|
||
|
return Malformed{EText: "common header does not indicate a valid endianness"}
|
||
|
}
|
||
|
dec.ch.CharacterEncoding = uint8(vb & 0xF)
|
||
|
if dec.ch.CharacterEncoding != 0 && dec.ch.CharacterEncoding != 1 {
|
||
|
return Malformed{EText: "common header does not indicate a valid character encoding"}
|
||
|
}
|
||
|
switch endian {
|
||
|
case littleEndian:
|
||
|
dec.ch.Endianness = binary.LittleEndian
|
||
|
case bigEndian:
|
||
|
dec.ch.Endianness = binary.BigEndian
|
||
|
}
|
||
|
// Common header length
|
||
|
lb, err := dec.readBytes(2)
|
||
|
if err != nil {
|
||
|
return Malformed{EText: fmt.Sprintf("could not read common header length: %v", err)}
|
||
|
}
|
||
|
dec.ch.HeaderLength = dec.ch.Endianness.Uint16(lb)
|
||
|
if dec.ch.HeaderLength != commonHeaderBytes {
|
||
|
return Malformed{EText: "common header does not indicate a valid length"}
|
||
|
}
|
||
|
// Filler bytes
|
||
|
dec.ch.Filler, err = dec.readBytes(4)
|
||
|
if err != nil {
|
||
|
return Malformed{EText: fmt.Sprintf("could not read common header filler: %v", err)}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (dec *Decoder) readPrivateHeader() error {
|
||
|
// The next 8 bytes after the common header comprise the RPC type marshalling private header for constructed types.
|
||
|
err := binary.Read(dec.r, dec.ch.Endianness, &dec.ph.ObjectBufferLength)
|
||
|
if err != nil {
|
||
|
return Malformed{EText: "could not read private header object buffer length"}
|
||
|
}
|
||
|
if dec.ph.ObjectBufferLength%8 != 0 {
|
||
|
return Malformed{EText: "object buffer length not a multiple of 8"}
|
||
|
}
|
||
|
// Filler bytes
|
||
|
dec.ph.Filler, err = dec.readBytes(4)
|
||
|
if err != nil {
|
||
|
return Malformed{EText: fmt.Sprintf("could not read private header filler: %v", err)}
|
||
|
}
|
||
|
return nil
|
||
|
}
|