123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- package ber
- import (
- "errors"
- "fmt"
- "io"
- "math"
- )
- 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
- highBit := uint(63)
- for {
- if tag&(1<<highBit) != 0 {
- break
- }
- highBit--
- }
- tagBytes := int(math.Ceil(float64(highBit) / 7.0))
- for i := tagBytes - 1; i >= 0; i-- {
- offset := uint(i) * 7
- mask := Tag(0x7f) << offset
- tagByte := (tag & mask) >> offset
- if i != 0 {
- tagByte |= 0x80
- }
- b = append(b, byte(tagByte))
- }
- }
- return b
- }
|