aboutsummaryrefslogtreecommitdiff
path: root/goldap/bytes.go
diff options
context:
space:
mode:
Diffstat (limited to 'goldap/bytes.go')
-rw-r--r--goldap/bytes.go199
1 files changed, 199 insertions, 0 deletions
diff --git a/goldap/bytes.go b/goldap/bytes.go
new file mode 100644
index 0000000..92c63a2
--- /dev/null
+++ b/goldap/bytes.go
@@ -0,0 +1,199 @@
+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
+}