Package spoon :: Package ber :: Module tag
[hide private]
[frames] | no frames]

Source Code for Module spoon.ber.tag

  1  # 
  2  # Copyright (C) 2003-2006, Robey Pointer <robey@lag.net> 
  3  # 
  4  # Permission is hereby granted, free of charge, to any person obtaining 
  5  # a copy of this software and associated documentation files (the 
  6  # "Software"), to deal in the Software without restriction, including 
  7  # without limitation the rights to use, copy, modify, merge, publish, 
  8  # distribute, sublicense, and/or sell copies of the Software, and to 
  9  # permit persons to whom the Software is furnished to do so, subject to 
 10  # the following conditions: 
 11  #  
 12  # The above copyright notice and this permission notice shall be included 
 13  # in all copies or substantial portions of the Software. 
 14  #  
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 16  # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
 17  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 18  # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 
 19  # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
 20  # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 21  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 22  # 
 23     
 24   
 25  from common import BERException, inflate_long, deflate_long 
 26  from common import UNIVERSAL, APPLICATION, CONTEXT, PRIVATE 
 27   
 28   
 29  _class_name = { UNIVERSAL: 'UNIVERSAL', APPLICATION: 'APPLICATION', 
 30                  CONTEXT: 'CONTEXT', PRIVATE: 'PRIVATE' } 
 31   
 32   
33 -class Tag (object):
34 """ 35 Representation of the header of an ASN.1 object. This includes the 36 class (universal, application, context, or private), the type tag (any 37 integer), and size. 38 """ 39
40 - def __init__(self, tag_class=0, tag=UNIVERSAL, size=None, container=False, _bytes_read=0):
41 self._tag_class = tag_class 42 self._tag = tag 43 self._size = size 44 self._container = container 45 self._bytes_read = _bytes_read
46
47 - def __repr__(self):
48 return '<ASN.1 Tag(%s, %d, size=%r, container=%r)>' % (_class_name[self._tag_class], self._tag, 49 self._size, self._container)
50
51 - def __cmp__(self, other):
52 if not isinstance(other, Tag): 53 raise ValueError('not comparable with %r', other) 54 x = cmp(self._tag_class, other._tag_class) 55 if x != 0: 56 return x 57 x = cmp(self._container, other._container) 58 if x != 0: 59 return x 60 return cmp(self._tag, other._tag)
61
62 - def __hash__(self):
63 n = self._tag_class 64 n *= 37 65 if self._container: 66 n += 1 67 n *= 37 68 n += self._tag 69 return n
70 71 tag_class = property(lambda self: self._tag_class, None, None) 72 tag = property(lambda self: self._tag, None, None) 73 size = property(lambda self: self._size, None, None) 74 container = property(lambda self: self._container, None, None) 75
76 - def is_terminator(self):
77 """ 78 Return C{True} if this tag is the special type used to terminate 79 indefinite-length sequences (type 0, length 0). 80 """ 81 return (self._tag_class == UNIVERSAL) and not self._container and (self._tag == 0) and \ 82 self._size == 0
83 84 @staticmethod
85 - def make_terminator():
86 """ 87 Return a tag that can be used to terminate indefinite-length sequences. 88 """ 89 return Tag(Tag.UNIVERSAL, False, 0, 0)
90 91 @staticmethod
92 - def from_tag(t, size=None):
93 return Tag(t._tag_class, t._tag, size, t._container)
94 95 @staticmethod
96 - def from_stream(fd):
97 tag = fd.read(1) 98 if len(tag) == 0: 99 # end of stream 100 return None 101 bytes_read = 1 102 tag = ord(tag) 103 tag_class = (tag >> 6) 104 if tag & 0x20: 105 tag_container = True 106 else: 107 tag_container = False 108 tag &= 0x1f 109 if tag == 0x1f: 110 # extended form of tag 111 tag = 0L 112 while True: 113 t = fd.read(1) 114 if len(t) == 0: 115 raise BERException('abrupt end of tag field') 116 bytes_read += 1 117 t = ord(t) 118 tag = (tag << 7) | (t & 0x7f) 119 if not (t & 0x80): 120 break 121 size = fd.read(1) 122 if len(size) == 0: 123 raise BERException('expected size field') 124 bytes_read += 1 125 size = ord(size) 126 if size == 0x80: 127 size = None 128 if not tag_container: 129 raise BERException('indefinite-length tags must refer to sequences') 130 elif size & 0x80: 131 # extended size field 132 size &= 0x7f 133 x = fd.read(size) 134 if len(x) != size: 135 raise BERException('truncated size field') 136 bytes_read += size 137 size = inflate_long(x, True) 138 return Tag(tag_class, tag, size, container=tag_container, _bytes_read=bytes_read)
139
140 - def __len__(self):
141 if self._bytes_read > 0: 142 return self._bytes_read 143 n = 2 144 if self.tag > 30: 145 t = self.tag 146 while t > 0: 147 n += 1 148 t >>= 7 149 if self.size > 0x7f: 150 n += len(deflate_long(self.size)) 151 return n
152
153 - def write(self, fd):
154 high_bits = (self._tag_class << 6) 155 if self._container: 156 high_bits |= 0x20 157 if self._tag <= 30: 158 fd.write(chr(self._tag | high_bits)) 159 elif self._tag <= 127: 160 fd.write(chr(high_bits | 0x1f)) 161 fd.write(chr(self._tag)) 162 else: 163 fd.write(chr(high_bits | 0x1f)) 164 tag = self._tag 165 tagstr = chr(tag & 0x7f) 166 tag >>= 7 167 while tag > 0: 168 tagstr = chr(0x80 | (tag & 0x7f)) + tagstr 169 tag >>= 7 170 fd.write(tagstr) 171 # whew. okay, now length. 172 if self._size is None: 173 fd.write(chr(0x80)) 174 elif self._size > 0x7f: 175 lenstr = deflate_long(self._size) 176 fd.write(chr(0x80 | len(lenstr))) 177 fd.write(lenstr) 178 else: 179 fd.write(chr(self._size))
180