summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-asn1-ber/asn1-ber/identifier.go')
-rw-r--r--vendor/github.com/go-asn1-ber/asn1-ber/identifier.go112
1 files changed, 112 insertions, 0 deletions
diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go b/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go
new file mode 100644
index 00000000..e8c43574
--- /dev/null
+++ b/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go
@@ -0,0 +1,112 @@
+package ber
+
+import (
+ "errors"
+ "fmt"
+ "io"
+)
+
+func readIdentifier(reader io.Reader) (Identifier, int, error) {
+ identifier := Identifier{}
+ read := 0
+
+ // identifier byte
+ b, err := readByte(reader)
+ if err != nil {
+ if Debug {
+ fmt.Printf("error reading identifier byte: %v\n", err)
+ }
+ return Identifier{}, read, err
+ }
+ read++
+
+ identifier.ClassType = Class(b) & ClassBitmask
+ identifier.TagType = Type(b) & TypeBitmask
+
+ if tag := Tag(b) & TagBitmask; tag != HighTag {
+ // short-form tag
+ identifier.Tag = tag
+ return identifier, read, nil
+ }
+
+ // high-tag-number tag
+ tagBytes := 0
+ for {
+ b, err := readByte(reader)
+ if err != nil {
+ if Debug {
+ fmt.Printf("error reading high-tag-number tag byte %d: %v\n", tagBytes, err)
+ }
+ return Identifier{}, read, err
+ }
+ tagBytes++
+ read++
+
+ // Lowest 7 bits get appended to the tag value (x.690, 8.1.2.4.2.b)
+ identifier.Tag <<= 7
+ identifier.Tag |= Tag(b) & HighTagValueBitmask
+
+ // First byte may not be all zeros (x.690, 8.1.2.4.2.c)
+ if tagBytes == 1 && identifier.Tag == 0 {
+ return Identifier{}, read, errors.New("invalid first high-tag-number tag byte")
+ }
+ // Overflow of int64
+ // TODO: support big int tags?
+ if tagBytes > 9 {
+ return Identifier{}, read, errors.New("high-tag-number tag overflow")
+ }
+
+ // Top bit of 0 means this is the last byte in the high-tag-number tag (x.690, 8.1.2.4.2.a)
+ if Tag(b)&HighTagContinueBitmask == 0 {
+ break
+ }
+ }
+
+ return identifier, read, nil
+}
+
+func encodeIdentifier(identifier Identifier) []byte {
+ b := []byte{0x0}
+ b[0] |= byte(identifier.ClassType)
+ b[0] |= byte(identifier.TagType)
+
+ if identifier.Tag < HighTag {
+ // Short-form
+ b[0] |= byte(identifier.Tag)
+ } else {
+ // high-tag-number
+ b[0] |= byte(HighTag)
+
+ tag := identifier.Tag
+
+ b = append(b, encodeHighTag(tag)...)
+ }
+ return b
+}
+
+func encodeHighTag(tag Tag) []byte {
+ // set cap=4 to hopefully avoid additional allocations
+ b := make([]byte, 0, 4)
+ for tag != 0 {
+ // t := last 7 bits of tag (HighTagValueBitmask = 0x7F)
+ t := tag & HighTagValueBitmask
+
+ // right shift tag 7 to remove what was just pulled off
+ tag >>= 7
+
+ // if b already has entries this entry needs a continuation bit (0x80)
+ if len(b) != 0 {
+ t |= HighTagContinueBitmask
+ }
+
+ b = append(b, byte(t))
+ }
+ // reverse
+ // since bits were pulled off 'tag' small to high the byte slice is in reverse order.
+ // example: tag = 0xFF results in {0x7F, 0x01 + 0x80 (continuation bit)}
+ // this needs to be reversed into 0x81 0x7F
+ for i, j := 0, len(b)-1; i < len(b)/2; i++ {
+ b[i], b[j-i] = b[j-i], b[i]
+ }
+ return b
+}