forked from Deuxfleurs/bottin
200 lines
5.7 KiB
Go
200 lines
5.7 KiB
Go
|
package message
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
type Bytes struct {
|
||
|
offset int
|
||
|
bytes []byte
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) getBytes() []byte {
|
||
|
return bytes.bytes
|
||
|
}
|
||
|
func NewBytes(offset int, bytes []byte) (ret *Bytes) {
|
||
|
return &Bytes{offset: offset, bytes: bytes}
|
||
|
}
|
||
|
|
||
|
func (bytes Bytes) Debug() {
|
||
|
fmt.Printf("Offset: %d, Bytes: %+v\n", bytes.offset, bytes.bytes)
|
||
|
}
|
||
|
|
||
|
// Return a string with the hex dump of the bytes around the current offset
|
||
|
// The current offset byte is put in brackets
|
||
|
// Example: 0x01, [0x02], 0x03
|
||
|
func (bytes *Bytes) DumpCurrentBytes() (ret string) {
|
||
|
var strings [3]string
|
||
|
for i := -1; i <= 1; i++ {
|
||
|
if bytes.offset+i >= 0 && bytes.offset+i < len(bytes.bytes) {
|
||
|
strings[i+1] = fmt.Sprintf("%#x", bytes.bytes[bytes.offset+i])
|
||
|
}
|
||
|
}
|
||
|
ret = fmt.Sprintf("%s, [%s], %s", strings[0], strings[1], strings[2])
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) HasMoreData() bool {
|
||
|
return bytes.offset < len(bytes.bytes)
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) ParseTagAndLength() (ret TagAndLength, err error) {
|
||
|
var offset int
|
||
|
ret, offset, err = ParseTagAndLength(bytes.bytes, bytes.offset)
|
||
|
if err != nil {
|
||
|
err = LdapError{fmt.Sprintf("ParseTagAndLength: %s", err.Error())}
|
||
|
return
|
||
|
} else {
|
||
|
bytes.offset = offset
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) ReadSubBytes(class int, tag int, callback func(bytes *Bytes) error) (err error) {
|
||
|
// Check tag
|
||
|
tagAndLength, err := bytes.ParseTagAndLength()
|
||
|
if err != nil {
|
||
|
return LdapError{fmt.Sprintf("ReadSubBytes:\n%s", err.Error())}
|
||
|
}
|
||
|
err = tagAndLength.Expect(class, tag, isCompound)
|
||
|
if err != nil {
|
||
|
return LdapError{fmt.Sprintf("ReadSubBytes:\n%s", err.Error())}
|
||
|
}
|
||
|
|
||
|
start := bytes.offset
|
||
|
end := bytes.offset + tagAndLength.Length
|
||
|
|
||
|
// Check we got enough bytes to process
|
||
|
if end > len(bytes.bytes) {
|
||
|
return LdapError{fmt.Sprintf("ReadSubBytes: data truncated: expecting %d bytes at offset %d", tagAndLength.Length, bytes.offset)}
|
||
|
}
|
||
|
// Process sub-bytes
|
||
|
subBytes := Bytes{offset: 0, bytes: bytes.bytes[start:end]}
|
||
|
err = callback(&subBytes)
|
||
|
if err != nil {
|
||
|
bytes.offset += subBytes.offset
|
||
|
err = LdapError{fmt.Sprintf("ReadSubBytes:\n%s", err.Error())}
|
||
|
return
|
||
|
}
|
||
|
// Check we got no more bytes to process
|
||
|
if subBytes.HasMoreData() {
|
||
|
return LdapError{fmt.Sprintf("ReadSubBytes: data too long: %d more bytes to read at offset %d", end-bytes.offset, bytes.offset)}
|
||
|
}
|
||
|
// Move offset
|
||
|
bytes.offset = end
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func SizeSubBytes(tag int, callback func() int) (size int) {
|
||
|
size = callback()
|
||
|
size += sizeTagAndLength(tag, size)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) WritePrimitiveSubBytes(class int, tag int, value interface{}) (size int) {
|
||
|
switch value.(type) {
|
||
|
case BOOLEAN:
|
||
|
size = writeBool(bytes, bool(value.(BOOLEAN)))
|
||
|
case INTEGER:
|
||
|
size = writeInt32(bytes, int32(value.(INTEGER)))
|
||
|
case ENUMERATED:
|
||
|
size = writeInt32(bytes, int32(value.(ENUMERATED)))
|
||
|
case OCTETSTRING:
|
||
|
size = writeOctetString(bytes, []byte(string(value.(OCTETSTRING))))
|
||
|
default:
|
||
|
panic(fmt.Sprintf("WritePrimitiveSubBytes: invalid value type %v", value))
|
||
|
}
|
||
|
size += bytes.WriteTagAndLength(class, isNotCompound, tag, size)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) WriteTagAndLength(class int, compound bool, tag int, length int) int {
|
||
|
return writeTagAndLength(bytes, TagAndLength{Class: class, IsCompound: compound, Tag: tag, Length: length})
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) writeString(s string) (size int) {
|
||
|
size = len(s)
|
||
|
start := bytes.offset - size
|
||
|
if start < 0 {
|
||
|
panic("Not enough space for string")
|
||
|
}
|
||
|
copy(bytes.bytes[start:], s)
|
||
|
bytes.offset = start
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) writeBytes(b []byte) (size int) {
|
||
|
size = len(b)
|
||
|
start := bytes.offset - size
|
||
|
if start < 0 {
|
||
|
panic("Not enough space for bytes")
|
||
|
}
|
||
|
copy(bytes.bytes[start:], b)
|
||
|
bytes.offset = start
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Parse tag, length and read the a primitive value
|
||
|
// Supported types are:
|
||
|
// - boolean
|
||
|
// - integer (parsed as int32)
|
||
|
// - enumerated (parsed as int32)
|
||
|
// - UTF8 string
|
||
|
// - Octet string
|
||
|
//
|
||
|
// Parameters:
|
||
|
// - class: the expected class value(classUniversal, classApplication, classContextSpecific)
|
||
|
// - tag: the expected tag value
|
||
|
// - typeTag: the real primitive type to parse (tagBoolean, tagInteger, tagEnym, tagUTF8String, tagOctetString)
|
||
|
//
|
||
|
func (bytes *Bytes) ReadPrimitiveSubBytes(class int, tag int, typeTag int) (value interface{}, err error) {
|
||
|
// Check tag
|
||
|
tagAndLength, err := bytes.ParseTagAndLength()
|
||
|
if err != nil {
|
||
|
err = LdapError{fmt.Sprintf("ReadPrimitiveSubBytes:\n%s", err.Error())}
|
||
|
return
|
||
|
}
|
||
|
err = tagAndLength.Expect(class, tag, isNotCompound)
|
||
|
if err != nil {
|
||
|
err = LdapError{fmt.Sprintf("ReadPrimitiveSubBytes:\n%s", err.Error())}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
start := bytes.offset
|
||
|
end := bytes.offset + tagAndLength.Length
|
||
|
|
||
|
// Check we got enough bytes to process
|
||
|
if end > len(bytes.bytes) {
|
||
|
// err = LdapError{fmt.Sprintf("ReadPrimitiveSubBytes: data truncated: expecting %d bytes at offset %d but only %d bytes are remaining (start: %d, length: %d, end: %d, len(b): %d, bytes: %#+v)", tagAndLength.Length, *b.offset, len(b.bytes)-start, start, tagAndLength.Length, end, len(b.bytes), b.bytes)}
|
||
|
err = LdapError{fmt.Sprintf("ReadPrimitiveSubBytes: data truncated: expecting %d bytes at offset %d but only %d bytes are remaining", tagAndLength.Length, bytes.offset, len(bytes.bytes)-start)}
|
||
|
return
|
||
|
}
|
||
|
// Process sub-bytes
|
||
|
subBytes := bytes.bytes[start:end]
|
||
|
switch typeTag {
|
||
|
case tagBoolean:
|
||
|
value, err = parseBool(subBytes)
|
||
|
case tagInteger:
|
||
|
value, err = parseInt32(subBytes)
|
||
|
case tagEnum:
|
||
|
value, err = parseInt32(subBytes)
|
||
|
case tagOctetString:
|
||
|
value, err = parseOctetString(subBytes)
|
||
|
default:
|
||
|
err = LdapError{fmt.Sprintf("ReadPrimitiveSubBytes: invalid type tag value %d", typeTag)}
|
||
|
return
|
||
|
}
|
||
|
if err != nil {
|
||
|
err = LdapError{fmt.Sprintf("ReadPrimitiveSubBytes:\n%s", err.Error())}
|
||
|
return
|
||
|
}
|
||
|
// Move offset
|
||
|
bytes.offset = end
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (bytes *Bytes) Bytes() []byte {
|
||
|
return bytes.bytes
|
||
|
}
|