root/umpa/branches/protocols/umit/umpa/protocols/_fields.py @ 5808

Revision 5808, 27.5 kB (checked in by kosma, 3 years ago)

_fields.py: add OptionField? that holds a single IP/TCP option

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (C) 2008-2010 Adriano Monteiro Marques.
5#
6# Author: Bartosz SKOWRON <getxsick at gmail dot com>
7#
8# This library is free software; you can redistribute it and/or modify
9# it under the terms of the GNU Lesser General Public License as published
10# by the Free Software Foundation; either version 2.1 of the License, or
11# (at your option) any later version.
12#
13# This library is distributed in the hope that it will be useful, but
14# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16# License for more details.
17#
18# You should have received a copy of the GNU Lesser General Public License
19# along with this library; if not, write to the Free Software Foundation,
20# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22"""
23Generic Field classes.
24
25Protocols' headers contain fields. Each field's objects should be an instance
26of a Field class or of a subclass thereof (especially some generic subclasses
27provided by this module).
28
29Use these fields' classes to create new implementation of any protocols.
30"""
31
32import types
33
34from umit.umpa.utils.exceptions import UMPAException, UMPAAttributeException
35from umit.umpa.utils.bits import BYTE, str_to_bits
36
37class Field(object):
38    """
39    Superclass for any fields.
40
41    Protocols' headers contain there fields.
42
43    To implement new fields, create subclass of this class or any other
44    common classes included in this module.
45
46    IMPORTANT: You should overwrite this __doc__ to get hints in some frontends
47    like the one provided by Umit Project.
48    """
49
50    bits = 0
51    auto = False
52    active = True
53    def __init__(self, name, value=None, bits=None, auto=None, active=True):
54        """
55        Create a new Field().
56
57        @type name: C{str}
58        @param name: name of the field.
59
60        @type value: Optional
61        @param value: predefined value of the field.
62
63        @type bits: Optional C{int}
64        @param bits: length of the field.
65
66        @type auto: Optional C{bool}
67        @param auto: information for users if the field can be auto-filling
68
69        @type active: Optional C{bool}
70        @param active: indicates if the field is included in the raw packet
71        """
72
73        self.name = name
74        self.active = active
75        if auto is not None:
76            self.auto = auto
77        else:
78            self.auto = self.__class__.auto
79
80        if bits is not None:
81            self.bits = bits
82        if value is None:
83            self._value = None
84        # XXX hack for unitttests, normally Field is only super-class for others
85        elif self.__class__ is Field:
86            self._value = value
87        else:
88            self.set(value)
89
90    def __str__(self):
91        """
92        Print in human-readable tree-style a content of the field.
93
94        @return: the part of the whole tree which accords to the field.
95        """
96
97        if self.auto:
98            return "| +-[ %-25s ]\t%-15s : %s (auto - %s)" % (self.name,
99                        self._shortname, str(self._value), str(self.fillout()))
100        else:
101            return "| +-[ %-25s ]\t%-15s : %s" % (self.name,
102                                            self._shortname, str(self._value))
103
104    def __repr__(self):
105        """
106        Print name of the Field
107        """
108
109        return self.name
110
111    def get(self):
112        """
113        Return the current value of the field.
114
115        Don't generate the value if the is not saved any but auto-filling
116        is possible. In this case, just return None.
117
118        @return: the current value of the field.
119        """
120
121        return self._value
122
123    def set(self, value):
124        """
125        Set a value for the field.
126
127        The new value is validing before assigment.
128        'auto' parameter is unset.
129
130        @param value: new value for the field.
131        """
132
133        if self._is_valid(value):
134            self._value = value
135        else:
136            raise UMPAAttributeException("%s: %s is not allowed" %
137                                           ( self.name, str(value) ))
138
139        if self.auto:
140            self.auto = False
141
142    def clear(self):
143        """
144        Clear the current value of the field.
145        """
146
147        self._value = None
148
149    def set_doc(self, text):
150        """
151        Set the pydocs of the field.
152
153        It's important for new subclasses of the Field.
154        Some GUIs use this information in hints etc.
155
156        @type text: C{str}
157        @param text: new pydoc for the field.
158        """
159
160        self.__doc__ = text
161
162    def _is_valid(self, value):
163        """
164        Validate the new value.
165
166        This method is an abstract. You HAVE TO override it.
167
168        @param value: the new value
169
170        @rtype: C{bool}
171        @return: result of the validation.
172        """
173
174        raise NotImplementedError("this is abstract class")
175
176    def _raw_value(self):
177        """
178        Convert the value to the raw mode.
179
180        Raw value's type is a number. It has to be in big-endian order.
181        The bits of the result of this method are inserted into the raw number
182        of the whole protocol.
183
184        This method is an abstract. You HAVE TO override it.
185        You need to implement a conversion of the value here.
186        E.g. for IntField is just return the value. But for some strings-fields
187        you need to convert characters in the specific way.
188
189        @rtype: C{number}
190        @return: raw value of the field.
191        """
192
193        raise NotImplementedError("this is abstract class")
194
195    def _generate_value(self):
196        """
197        Generate value for undefined yet field.
198
199        This is auto-filling feature. If you implement this method, propably
200        you should set the auto attribute to True for the class. It means that
201        user doesn't need to set the value of the field.
202
203        @return: auto-generated value of the field.
204        """
205
206        raise UMPAException(self.name + ": value is not defined or _generate_value() " 
207                                        "method is not implemented.")
208
209    def fillout(self):
210        """
211        Fillout the field.
212
213        Generate the value if undefined and convert the result
214        to the big-endian representation.
215
216        @return: bits of the field for the (generated) value.
217        """
218
219        # we have to clear self._value if it was not defined
220        # because of later usage
221        if self._value is None:
222            self._value = self._generate_value()
223            raw = self._raw_value()
224            self.clear()
225        else:
226            raw = self._raw_value()
227       
228        return raw
229
230class IntField(Field):
231    """
232    Superclass for number-type fields.
233
234    This class implemented _raw_value() and _is_valid() methods.
235    You need to implement _generate_value() method if needed.
236
237    IMPORTANT: You should overwrite this __doc__ to get hints in some frontends
238    like the one provided by Umit Project.
239    """
240
241    def _raw_value(self):
242        """
243        Convert the value to the raw mode.
244
245        Raw value's type is a number. It has to be in big-endian order.
246        The bits of the result of this method are inserted into the raw number
247        of the whole protocol.
248       
249        For IntField there is nothing to convert. Just simple return the value.
250
251        @rtype: C{number}
252        @return: raw value of the field.
253        """
254
255        return self._value
256
257    def _is_valid(self, value):
258        """
259        Validate if the value is not bigger than expected.
260
261        @param value: the new value.
262
263        @rtype: C{bool}
264        @return: result of the validation.
265        """
266
267        if 2**self.bits > value:
268            return True
269        else:
270            return False
271
272class SpecialIntField(IntField):
273    """
274    This class is a specific one and has special meaning.
275   
276    It's a subclass of IntField.
277    Use this class if the field handles with other fields from the protocol
278    or other layers/protocols.
279
280    E.g. Internet Header Length (IHL) field from the IP protocol needs to know
281    some informations about others fields.
282
283    Use _tmp_value attribute then in pre/post raw methods in protocol
284    classes. Just assign to the _tmp_value needed information from other fields
285    and implement _generate_value() method in the related way.
286    Check umit.umpa.protocols.IP module for examples.
287    """
288
289    def __init__(self, *args, **kwargs):
290        """
291        Create a new SpecialIntField().
292
293        Call the super constructor and initiate temporary value.
294        """
295
296        super(SpecialIntField, self).__init__(*args, **kwargs)
297        self.__temp_value = 0
298
299    def get_tmpvalue(self):
300        """
301        Return temporary value.
302
303        @rtype: C{int}
304        @return: temporary value of the field.
305        """
306
307        return self.__temp_value
308
309    def set_tmpvalue(self, value):
310        """
311        Set the temporary value.
312
313        @type value: C{int}
314        @param value: temporary value for special cases
315        """
316
317        self.__temp_value = value
318
319    def clear_tmpvalue(self):
320        """
321        Clear the temporary value.
322        """
323
324        self.__temp_value = 0
325
326    _tmp_value = property(get_tmpvalue, set_tmpvalue, clear_tmpvalue, """
327    The temporary value -- attribute for special cases in pre/post raw methods.
328
329    Use _tmp_value attribute in pre/post raw methods in protocol
330    classes if you need handle with other fields.
331    Assign to the _tmp_value needed information from other fields
332    and implement _generate_value() method in the related way.
333    Check umit.umpa.protocols.IP module for examples.
334
335    @type: C{int}
336    """)
337
338class EnumField(IntField):
339    """
340    This is a specific version of IntField and handles with enumerable fields.
341
342    E.g. SMTP port is 25. To set/get value of port from TCP protocol,
343    use "STMP" instead of "25". Read documentation for get() and set() methods
344    for additional information.
345    """
346
347    enumerable = {}
348
349    def get(self, human=False):
350        """
351        Return the current value of the field.
352
353        @type human: Optional C{bool}
354        @param human: if True, return human-readable value instead of numeric.
355        (Default: False)
356        """
357
358        value = super(EnumField, self).get()
359        if human:
360            for k, val in self.enumerable.items():
361                if val == value:
362                    return k
363        return value
364
365    def set(self, value):
366        """
367        Set the new value of the field.
368
369        Try to use value as a key for a dictionary ("SMTP" e.g.) and set
370        the value returned by the dictionary.
371
372        If value doesn't recognise as a dictionary key, try classic way.
373
374        @type value: C{int} or C{str}
375        @param value: assign new value in both ways (numeric and human).
376        """
377       
378        # we try to use value as a "human" value
379        # if doesn't work, then as a normal one
380        try:
381            super(EnumField, self).set(self.enumerable[value])
382        except KeyError:
383            super(EnumField, self).set(value)
384
385class AddrField(Field):
386    """
387    Superclass for address-type fields.
388
389    Subclasses of this class are related to the different kinds of addresses
390    as IP addresses for example.
391
392    Handle with 2 types of data:
393     1. strings as "127.0.0.1" or "0:0:0:0:0:0:0:1"
394     2. tuples as (127,0,0,1) or (0,0,0,0,0,0,0,1)
395    """
396
397    separator = ""
398    base = 0
399    piece_size = 0
400    pieces_amount = 0
401    bits = 0
402
403    def set(self, value):
404        """
405        Set the new value of the field.
406       
407        @type value: C{str} or C{list} or C{tuple}
408        @param value: new value for the field.
409        """
410
411        # convert list to tuple
412        if isinstance(value, types.ListType):
413            value = tuple(value)
414
415        super(AddrField, self).set(value)
416
417    def _raw_value(self):
418        """
419        Convert the value to the raw mode.
420
421        Raw value's type is a number. It has to be in big-endian order.
422        The bits of the result of this method are inserted into the raw number
423        of the whole protocol.
424
425        @rtype: C{number}
426        @return: raw value of the field.
427        """
428
429        # convert the value to the list if it's str
430        if isinstance(self._value, types.StringType):
431            pieces = self._value.split(self.separator)
432        else:
433            pieces = self._value
434
435        # add every piece of the address to the raw value
436        # with bits-length of them keeping
437        raw = 0
438        for bit in pieces:
439            bit = str(bit)
440            raw += int(bit, self.base)
441            raw <<= self.piece_size
442        raw >>= self.piece_size
443
444        return raw
445
446    def _is_valid(self, value):
447        """
448        Validate the new value.
449
450        Only str or tuple type of the value is allowed.
451
452        @param value: the new value.
453
454        @rtype: C{bool}
455        @return: result of the validation.
456        """
457
458        if isinstance(value, types.StringType):
459            pieces = value.split(self.separator)
460        elif isinstance(value, types.TupleType):
461            pieces = value
462        else:
463            return False
464
465        if len(pieces) != self.pieces_amount:
466            return False
467
468        for i in pieces:
469            i = str(i)
470            try:
471                i_base = int(i, self.base)
472            except ValueError:
473                return False
474            if i_base >= 2**self.piece_size or i_base < 0:
475                return False
476
477        return True
478
479class IPAddrField(AddrField):
480    """
481    Main class for IP-style adresses.
482    """
483    pass
484
485class IPv4AddrField(IPAddrField):
486    """
487    Address in IPv4 style.
488
489    Handle with 2 types of data:
490     1. strings as "127.0.0.1"
491     2. tuples as (127,0,0,1)
492    """
493
494    separator = "."
495    piece_size = 8
496    pieces_amount = 4
497    base = 10
498    bits = 32
499
500#class IPv6AddrField(IPAddrField):
501#    """
502#    Address in IPv6 style.
503#
504#    Handle with 2 types of data:
505#     1. strings as "0:0:0:0:0:0:0:1"
506#     2. tuples as (0,0,0,0,0,0,0,1)
507#
508#    @note: This field is really limited and you can't use address
509#    like 2001:db8::1428:57ab. All groups have to be pass.
510#    This issue should be fixed soon.
511#    """
512#
513#    separator = ":"
514#    piece_size = 16
515#    pieces_amount = 8
516#    base = 16
517#    bits = 128
518
519class MACAddrField(AddrField):
520    """
521    Hardware address in MAC style.
522
523    Handle with 2 types of data:
524     1. strings as "aa:bb:cc:dd:ee:ff"
525     2. tuples as ('aa','bb','cc',11,22,33)
526    """
527
528    separator = ":"
529    piece_size = 8
530    pieces_amount = 6
531    base = 16
532    bits = 48
533
534class PaddingField(SpecialIntField):
535    """
536    This class is for padding cases.
537
538    PaddingField is used to ensure that the header ends on a 32 bit boundary.
539    This is common fields for many protocols.
540    """
541
542    bits = 0
543    auto = True
544
545    def __init__(self, name, word=32, *args, **kwargs):
546        """
547        Create a new PaddingField().
548
549        @type word: C{int}
550        @param word: length of field which need padding (default: 32)
551       
552        Call the super constructor and initiate extra attributes.
553
554        Please note that padding is always done by using zeros (0).
555        """
556
557        self._word = word
558        super(PaddingField, self).__init__(name, 0, *args, **kwargs)
559        self.auto = True    # XXX: super-class overrides it
560                            # (should be fix with #314)
561
562    def fillout(self):
563        """
564        Fillout the field.
565
566        If undefined value, set the correct length of the field and generate
567        a value.
568
569        @return: call _raw_value() method for conversion.
570        """
571
572        if not self.get():
573            self.bits = self._generate_value()
574        else:
575            self.bits = self.get()
576        return self._raw_value()
577   
578    def _is_valid(self, value):
579        """
580        Validate if the value is not bigger than expected.
581
582        @param value: the new value.
583
584        @rtype: C{bool}
585        @return: result of the validation.
586        """
587
588        if isinstance(value, types.IntType) and 0 <= value <= self._word:
589            return True
590        return False
591
592    def _raw_value(self):
593        """
594        Don't convert the value. Return 0.
595
596        Padding B{always} contains bits with 0 assigned.
597
598        @rtype: C{int}
599        @return: 0
600        """
601
602        return 0
603
604    def _generate_value(self):
605        """
606        Generate value for undefined field yet.
607       
608        @return: auto-generated value of the field.
609        """
610
611        return (self._word - (self._tmp_value % self._word)) % self._word
612
613class Flags(Field):
614    """
615    This is special case of field - Flags.
616
617    Most of protocols have a special field with bit-flags.
618    E.g. TCP use them for ACK,SYN and others flags.
619    """
620
621    def __init__(self, name, names, **preset):
622        """
623        Create a new Flags()
624
625        List names need to be in correct order. List contains string names
626        of the bit-flags.
627
628        @type name: C{str}
629        @param name: name of the field.
630       
631        @type names: C{list}
632        @param names: list of bit-flags (C{str} type) B{in correct order}.
633
634        @type preset: C{bool}
635        @param preset: predefined values of bit-flags (defailt: I{0})
636        """
637        super(Flags, self).__init__(name, bits=len(names))
638
639        self._ordered_fields = names
640
641        # initialize of self._value...
642        # call clear() to not duplicate the code
643        self.clear()
644
645        # if **preset exists then we update values
646        for name in preset:
647            if preset[name] is True:
648                self.set(name)
649            else:
650                self.set(False, name)
651
652    def __str__(self):
653        """
654        Print in human-readable tree-style a content of the field.
655
656        Call print statement for bit-flags.
657
658        @return: the part of the whole tree which accords to the field.
659        """
660
661        print "| +-[ %-25s ]\t%s" % (self.name, self._shortname)
662        print "| | \\"
663        for bit in self._ordered_fields:
664            print self._value[bit]
665        print "| | /"
666        return "| \\-[ %-25s ]\tcontains %d bit flags" % (self.name,
667                                                    len(self._ordered_fields))
668
669    def get(self, *names):
670        """
671        Return a number which is n-bits value of bits
672        or a list of passed bits values.
673
674        If no names passed return a numeric value of all bits.
675        To return a list of all bits, pass [] as a first argument.
676
677        @type names: C{str}
678        @param names: names of bit-flags.
679
680        @return: a numeric-value or list of passed bits values.
681        """
682
683        try:
684            result = [ self._value[val].get() for val in names ]
685        except KeyError, msg:
686            raise UMPAAttributeException(msg)
687        except TypeError:
688            if len(names[0]) == 0:
689                result = [ self._value[bit].get() for bit in
690                                                        self._ordered_fields ]
691            else:
692                raise
693
694        if not names:
695            result = 0
696            for bit in self._ordered_fields:
697                result += self._value[bit].get()
698                result <<= 1
699            result >>= 1
700
701        return result
702
703
704    def set(self, value, *args, **kwargs):
705        """
706        Set value of bits.
707
708        This function is pretty complex and handles with many cases.
709       
710        @note: *args overrides value, and **kwargs overrids each.
711       
712        @param value: for C{int}: value of all bits,
713        for C{list}: True for bits from the list,
714        for C{dict}: bitname=value,
715        for C{str}: merging with *args
716        for C{False} or C{True}: bits from *args are set to True/False
717
718        @param args: True for bits from the list
719        @param kwargs: bitname=value
720        """
721
722        # Protocol.__setattr__ call Field.set()
723        # for Flags we have to handle different types
724        # 1) numeric-value 2) lists 3) dicts
725
726        if value in (None, False, True):
727            pass
728        elif isinstance(value, types.IntType):
729            # check if a value exceeds flags's length
730            if value > 2**self.bits - 1:
731                raise UMPAAttributeException('%d is not allowed. %d is '
732                            'a maximum value' % (value, 2**self.bits-1))
733
734            mask = 1
735            for bit in reversed(self._ordered_fields):
736                # cast to list because str is iterable (avoid iter over chars)
737                self._set_bit([bit], value & mask)
738                mask <<= 1
739        elif isinstance(value, (types.ListType, types.TupleType)):
740            value = list(value)
741            value.extend(args)  # to keep an order
742            args = value
743        elif isinstance(value, types.DictType):
744            value.update(kwargs) # to keep an order
745            kwargs = value
746        elif isinstance(value, (types.StringType, types.UnicodeType)):
747            args = list(args)
748            args.insert(0, value)
749        else:
750            raise UMPAAttributeException(value + ' is wrong type.')
751
752        # update bits for *args and **kwargs
753        if value is False:
754            self._set_bit(args, False)
755        else:
756            self._set_bit(args, True)
757        for bit in kwargs:
758            # cast to list because str is iterable (avoid iter over chars)
759            self._set_bit([bit], kwargs[bit])
760
761    def clear(self):
762        """
763        Clear the values of bit-flags.
764
765        Re-create a storing dictionary.
766        """
767
768        # we overwrite an attribute self._value
769        # because we need a list instead of simple var here
770        self._value = {}
771        for flag in self._ordered_fields:
772            self._value[flag] = BitField(flag, False)
773
774    def fillout(self):
775        """
776        Fillout the field.
777
778        Call fillout() methods for every bit-flags.
779        Return concatenated result.
780
781        @return: bits of the bit-flags.
782        """
783
784        raw = 0
785        for bitname in self._ordered_fields:
786            raw += self._value[bitname].fillout()
787            raw <<= 1
788        raw >>= 1
789        return raw
790
791    def _is_valid(self, name):
792        """
793        Validate if the value is not bigger than expected.
794
795        @param name: the name of the bit-flag.
796
797        @rtype: C{bool}
798        @return: result of the validation.
799        """
800
801        return name in self._value
802
803    def _set_bit(self, names, value):
804        """
805        Set the value for a bit.
806
807        Set True or False for the bit-flag.
808        Set the same value for every bit-flags from the list.
809
810        @type names: C{list}
811        @param names: list of names to set the value
812
813        @type value: C{bool}
814        @param value: the logical value.
815        """
816
817        for flag_name in names:
818            if self._is_valid(flag_name):
819                self._value[flag_name].set(value)
820            else:
821                raise UMPAAttributeException(flag_name + ' is not allowed')
822
823class BitField(Field):
824    """
825    This class is used for bit-flags of Flags field.
826
827    Flags is a field which contains several independent bits.
828    Each of the bits is an instance of BitField.
829    """
830
831    bits = 1
832    auto = False
833
834    def __str__(self):
835        """
836        Print in human-readable tree-style a content of the field.
837
838        @return: the part of the whole tree which accords to the field.
839        """
840
841        return "| |  -{ %-23s }\t%d" % (self.name, int(bool(self._value)))
842
843    def get(self):
844        """
845        Return the current value of the field.
846
847        @return: the current value of the field.
848        """
849
850        if self._value is None:
851            return self._value
852        return bool(self._value)
853
854    def fillout(self):
855        """
856        Fillout the field.
857
858        Generate the value if undefined and convert the result
859        to the big-endian representation.
860
861        @return: bits of the field for the (generated) value.
862        """
863
864        if self._value is None:
865            self._value = self._generate_value()
866            raw = self._raw_value()
867            self.clear()
868        else:
869            raw = self._raw_value()
870
871        return raw
872
873    def _is_valid(self, value):
874        """
875        Validate the new value.
876
877        @param value: the new value
878
879        @rtype: C{bool}
880        @return: C{True}, becuase this is a bool type so every value is correct.
881        """
882
883        # always True because it's bool type
884        return True
885
886    def _raw_value(self):
887        """
888        Convert the value to the raw mode.
889
890        In this case simple return 0 or 1.
891
892        @rtype: C{number}
893        @return: raw value of the field.
894        """
895
896        return int(bool(self.get()))
897
898class DataField(Field):
899    """
900    Raw binary data stored as a string.
901    """
902   
903    bits = 0
904    auto = False
905
906    def set(self, value):
907        """
908        Set the new value of the field.
909
910        @param value: assign new value with str() casting.
911        """
912
913        super(DataField, self).set(str(value))
914        # calculate how many bits we need
915        self.bits = len(self._value) * BYTE
916
917    def clear(self):
918        """
919        Clear the current value of the field.
920        """
921
922        super(DataField, self).clear()
923        self.bits = 0
924
925    def _is_valid(self, val):
926        """
927        Validate if the value is not bigger than expected.
928
929        @param val: the new value.
930
931        @rtype: C{bool}
932        @return: C{True}.
933        """
934        return True     # we use str() so everything is ok
935
936    def _raw_value(self):
937        """
938        Convert the value to the raw mode.
939
940        Convert every character into the integer ordinal.
941        Merge the integer values.
942        Raw value's type is a number. It has to be in big-endian order.
943        The bits of the result of this method are inserted into the raw number
944        of the whole protocol.
945
946        @rtype: C{number}
947        @return: raw value of the field.
948        """
949
950        return str_to_bits(self._value)
951
952class OptionField(Field):
953    """
954    A field holding a single IP/TCP option. This field can take two forms:
955
956    1. A (option-kind, option-value) tuple. The option-length octet will be
957       generated automatically. The option-value should be a raw string value.
958       Options 0 and 1 don't have option-value.
959    2. A string value which will be inserted as-is without any validation.
960    """
961
962    bits = 0    # dynamic, changes depending on the content
963
964    def _is_valid(self, value):
965        """
966        Ensure that the value is either a string or a valid tuple.
967        """
968
969        if value is None or isinstance(value, str):
970            return True
971        if len(value) == 0:
972            return False
973        if value[0] in (0, 1):
974            return True
975        if len(value) == 1:
976            return False
977        if not isinstance(value[1], str):
978            return False
979        return True
980
981    def set(self, value):
982        """
983        Calculate the bit length after setting the value.
984        """
985
986        super(OptionField, self).set(value)
987        if value is None:
988            self.bits = 0
989        elif isinstance(value, str):
990            # use a raw value as-is
991            self.bits = BYTE * len(value)
992        else:
993            if value[0] in (0, 1):
994                # options 0 and 1 have no option-length field
995                self.bits = BYTE
996            else:
997                self.bits = BYTE * (2 + len(value[1]))
998
999    def clear(self):
1000        """
1001        Reset the bit length after clearing the value.
1002        """
1003
1004        super(OptionField, self).clear()
1005        self.bits = 0
1006
1007    def _raw_value(self):
1008        """
1009        Convert the value to the raw mode.
1010        """
1011
1012        if isinstance(self._value, str):
1013            data = self._value
1014        else:
1015            if self._value[0] in (0,1):
1016                data = "%c" % self._value[0]
1017            else:
1018                data = "%c%c%s" % ( self._value[0], len(self._value[1]) + 2,
1019                                    self._value[1] )
1020
1021        return str_to_bits(data)
Note: See TracBrowser for help on using the browser.