...

Source file src/github.com/go-asn1-ber/asn1-ber/identifier.go

Documentation: github.com/go-asn1-ber/asn1-ber

     1  package ber
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  )
     8  
     9  func readIdentifier(reader io.Reader) (Identifier, int, error) {
    10  	identifier := Identifier{}
    11  	read := 0
    12  
    13  	// identifier byte
    14  	b, err := readByte(reader)
    15  	if err != nil {
    16  		if Debug {
    17  			fmt.Printf("error reading identifier byte: %v\n", err)
    18  		}
    19  		return Identifier{}, read, err
    20  	}
    21  	read++
    22  
    23  	identifier.ClassType = Class(b) & ClassBitmask
    24  	identifier.TagType = Type(b) & TypeBitmask
    25  
    26  	if tag := Tag(b) & TagBitmask; tag != HighTag {
    27  		// short-form tag
    28  		identifier.Tag = tag
    29  		return identifier, read, nil
    30  	}
    31  
    32  	// high-tag-number tag
    33  	tagBytes := 0
    34  	for {
    35  		b, err := readByte(reader)
    36  		if err != nil {
    37  			if Debug {
    38  				fmt.Printf("error reading high-tag-number tag byte %d: %v\n", tagBytes, err)
    39  			}
    40  			return Identifier{}, read, unexpectedEOF(err)
    41  		}
    42  		tagBytes++
    43  		read++
    44  
    45  		// Lowest 7 bits get appended to the tag value (x.690, 8.1.2.4.2.b)
    46  		identifier.Tag <<= 7
    47  		identifier.Tag |= Tag(b) & HighTagValueBitmask
    48  
    49  		// First byte may not be all zeros (x.690, 8.1.2.4.2.c)
    50  		if tagBytes == 1 && identifier.Tag == 0 {
    51  			return Identifier{}, read, errors.New("invalid first high-tag-number tag byte")
    52  		}
    53  		// Overflow of int64
    54  		// TODO: support big int tags?
    55  		if tagBytes > 9 {
    56  			return Identifier{}, read, errors.New("high-tag-number tag overflow")
    57  		}
    58  
    59  		// Top bit of 0 means this is the last byte in the high-tag-number tag (x.690, 8.1.2.4.2.a)
    60  		if Tag(b)&HighTagContinueBitmask == 0 {
    61  			break
    62  		}
    63  	}
    64  
    65  	return identifier, read, nil
    66  }
    67  
    68  func encodeIdentifier(identifier Identifier) []byte {
    69  	b := []byte{0x0}
    70  	b[0] |= byte(identifier.ClassType)
    71  	b[0] |= byte(identifier.TagType)
    72  
    73  	if identifier.Tag < HighTag {
    74  		// Short-form
    75  		b[0] |= byte(identifier.Tag)
    76  	} else {
    77  		// high-tag-number
    78  		b[0] |= byte(HighTag)
    79  
    80  		tag := identifier.Tag
    81  
    82  		b = append(b, encodeHighTag(tag)...)
    83  	}
    84  	return b
    85  }
    86  
    87  func encodeHighTag(tag Tag) []byte {
    88  	// set cap=4 to hopefully avoid additional allocations
    89  	b := make([]byte, 0, 4)
    90  	for tag != 0 {
    91  		// t := last 7 bits of tag (HighTagValueBitmask = 0x7F)
    92  		t := tag & HighTagValueBitmask
    93  
    94  		// right shift tag 7 to remove what was just pulled off
    95  		tag >>= 7
    96  
    97  		// if b already has entries this entry needs a continuation bit (0x80)
    98  		if len(b) != 0 {
    99  			t |= HighTagContinueBitmask
   100  		}
   101  
   102  		b = append(b, byte(t))
   103  	}
   104  	// reverse
   105  	// since bits were pulled off 'tag' small to high the byte slice is in reverse order.
   106  	// example: tag = 0xFF results in {0x7F, 0x01 + 0x80 (continuation bit)}
   107  	// this needs to be reversed into 0x81 0x7F
   108  	for i, j := 0, len(b)-1; i < len(b)/2; i++ {
   109  		b[i], b[j-i] = b[j-i], b[i]
   110  	}
   111  	return b
   112  }
   113  

View as plain text