Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
2.5 KiB
112 lines
2.5 KiB
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 |
|
}
|
|
|