source: server/lib/gutenbach/ipp/value.py @ 0c4f3bf

no-cups
Last change on this file since 0c4f3bf was 0c4f3bf, checked in by Jessica B. Hamrick <jhamrick@…>, 12 years ago

Rename value_tag to tag in ipp.value

  • Property mode set to 100644
File size: 10.8 KB
RevLine 
[7a1c039]1from .constants import OutOfBandTags, IntegerTags, OctetStringTags, CharacterStringTags
[d04a689]2import sys
3import struct
4import logging
[8979f90]5
6# initialize logger
[7a1c039]7logger = logging.getLogger(__name__)
[8979f90]8
[fa0d0ef]9class Value(object):
[5c5fe6d]10    """An IPP value consists of a tag and a value.
[8979f90]11
12    From RFC 2565:
13     -----------------------------------------------
14     |                   value-tag                 |   1 byte
15     -----------------------------------------------
[5cfb358]16     |            name-length  (value is 0x0000)   |   2 bytes
[8979f90]17     -----------------------------------------------
18     |              value-length  (value is v)     |   2 bytes
19     -----------------------------------------------
20     |                     value                   |   v bytes
21     -----------------------------------------------   
[5c5fe6d]22
[8979f90]23    """
24
[0c4f3bf]25    def __init__(self, tag=None, value=None):
[5c5fe6d]26        """Initialize a Value.  There are three different ways you can
[5cfb358]27        call this method:
28
29            Value() -- creates an empty Value instance
30
[0c4f3bf]31            Value(tag, value) -- creates a Value instance from
[fa0d0ef]32            a non-binary value
[5cfb358]33
34        If you create an empty Value instance, once you have set
[0c4f3bf]35        tag and value, you can retrieve the packed value from
[fa0d0ef]36        the packed_value property.
[8979f90]37
38        Arguments:
39
[0c4f3bf]40            tag -- one byte, identifying the type of value
[8979f90]41
[fa0d0ef]42            value -- variable size, containing the actual value.
43            It should be a string or number.
[5c5fe6d]44
[8979f90]45        """
46
[5cfb358]47        # make sure the arguments are valid
[fa0d0ef]48        if value is not None:
[0c4f3bf]49            assert tag is not None, \
50                   "tag must not be null because " + \
[fa0d0ef]51                   "value is not null!"
[8979f90]52
[5cfb358]53        # initialize member variables
[0c4f3bf]54        self.tag = tag # one byte, the type of value
[fa0d0ef]55        self.value     = value     # non-binary value of self.value
56
57    @classmethod
[0c4f3bf]58    def unpack(cls, tag, packed_value):
[5c5fe6d]59        """Unpack a binary IPP value into a Value object.
[fa0d0ef]60
[5cfb358]61        """
[0c4f3bf]62        return cls(tag, cls._unpack(tag, packed_value))
[fa0d0ef]63
64    @staticmethod
[0c4f3bf]65    def _unpack(tag, packed_value):
66        """Given self.tag and self.packed_value, unpack the
[5c5fe6d]67        binary value into either a string or number.  These values
68        MUST NOT be null.
[fa0d0ef]69
70        Returns: unpacked value
[5cfb358]71
72        """
[8979f90]73
[0c4f3bf]74        assert tag is not None, \
[5cfb358]75               "Cannot unpack values with unspecified value tag!"
[fa0d0ef]76        assert packed_value is not None, \
[5cfb358]77               "Cannot unpack null values!"
78
79        value = None
[8979f90]80
81        # out-of-band value tags
[0c4f3bf]82        if tag == OutOfBandTags.UNSUPPORTED or \
83               tag == OutOfBandTags.DEFAULT or \
84               tag == OutOfBandTags.UNKNOWN or \
85               tag == OutOfBandTags.NO_VALUE:
[5cfb358]86            value_size = 0
87            value = ''
[8979f90]88
89        # integer value tags
[0c4f3bf]90        elif tag == IntegerTags.INTEGER:
[fa0d0ef]91            value = struct.unpack('>i', packed_value)[0]
[0c4f3bf]92        elif tag == IntegerTags.BOOLEAN:
[569c377]93            value = struct.unpack('>b', packed_value)[0]
[0c4f3bf]94        elif tag == IntegerTags.ENUM:
[fa0d0ef]95            value = struct.unpack('>i', packed_value)[0]
[8979f90]96
97       
[0c4f3bf]98        elif tag == OctetStringTags.DATETIME:
[8979f90]99            # field  octets  contents                  range
100            # -----  ------  --------                  -----
101            #   1      1-2   year                      0..65536
102            #   2       3    month                     1..12
103            #   3       4    day                       1..31
104            #   4       5    hour                      0..23
105            #   5       6    minutes                   0..59
106            #   6       7    seconds                   0..60
107            #                (use 60 for leap-second)
108            #   7       8    deci-seconds              0..9
109            #   8       9    direction from UTC        '+' / '-'
110            #   9      10    hours from UTC            0..11
111            #  10      11    minutes from UTC          0..59
112
[fa0d0ef]113            value = struct.unpack('>hbbbbbbcbb', packed_value)
[8979f90]114           
[0c4f3bf]115        elif tag == OctetStringTags.RESOLUTION:
[8979f90]116            # OCTET-STRING consisting of nine octets of 2
117            # SIGNED-INTEGERs followed by a SIGNED-BYTE. The first
118            # SIGNED-INTEGER contains the value of cross feed
119            # direction resolution. The second SIGNED-INTEGER contains
120            # the value of feed direction resolution. The SIGNED-BYTE
121            # contains the units
122
[fa0d0ef]123            value = struct.unpack('>iib', packed_value)
[8979f90]124           
[0c4f3bf]125        elif tag == OctetStringTags.RANGE_OF_INTEGER:
[8979f90]126            # Eight octets consisting of 2 SIGNED-INTEGERs.  The first
127            # SIGNED-INTEGER contains the lower bound and the second
128            # SIGNED-INTEGER contains the upper bound.
129
[fa0d0ef]130            value = struct.unpack('>ii', packed_value)
[8979f90]131
[0c4f3bf]132        elif tag == OctetStringTags.TEXT_WITH_LANGUAGE or \
133                 tag == OctetStringTags.NAME_WITH_LANGUAGE:
[fa0d0ef]134            a = struct.unpack('>h', packed_value[:2])[0]
135            b = struct.unpack('>%ss' % a, packed_value[2:a+2])[0]
136            c = struct.unpack('>h', packed_value[a+2:a+4])[0]
137            d = struct.unpack('>%ss' % c, packed_value[a+4:][0])
[5cfb358]138            value = (a, b, c, d)
[8979f90]139
140        # character string value tags
[0c4f3bf]141        elif tag == \
[5cfb358]142                 CharacterStringTags.TEXT_WITHOUT_LANGUAGE or \
[0c4f3bf]143                 tag == \
[5cfb358]144                 CharacterStringTags.NAME_WITHOUT_LANGUAGE:
[fa0d0ef]145            value = str(packed_value)
[0c4f3bf]146        elif tag == CharacterStringTags.GENERIC or \
147                 tag == CharacterStringTags.KEYWORD or \
148                 tag == CharacterStringTags.URI or \
149                 tag == CharacterStringTags.URI_SCHEME or \
150                 tag == CharacterStringTags.CHARSET or \
151                 tag == CharacterStringTags.NATURAL_LANGUAGE or \
152                 tag == CharacterStringTags.MIME_MEDIA_TYPE:
[fa0d0ef]153            value = str(packed_value)
[8979f90]154
[5cfb358]155        # anything else that we didn't handle
156        else:
[fa0d0ef]157            if value is None:
158                value = packed_value
[5cfb358]159
[fa0d0ef]160        return value
[5cfb358]161
[fa0d0ef]162    @property
163    def packed_value(self):
[0c4f3bf]164        """Given self.tag and self.value, pack the value into
[fa0d0ef]165        binary form.  These values MUST NOT be null.
166
167        Returns: packed_value
[5cfb358]168
169        """
170       
[0c4f3bf]171        assert self.tag is not None, \
[5cfb358]172               "cannot pack value with null value tag!"
173        assert self.value is not None, \
174               "cannot pack null value!"
175
[fa0d0ef]176        packed_value = None
[8979f90]177
178        # out-of-band value tags
[0c4f3bf]179        if self.tag == OutOfBandTags.UNSUPPORTED or \
180               self.tag == OutOfBandTags.DEFAULT or \
181               self.tag == OutOfBandTags.UNKNOWN or \
182               self.tag == OutOfBandTags.NO_VALUE:
[fa0d0ef]183            packed_value = ''
[8979f90]184
185        # integer value tags
[0c4f3bf]186        elif self.tag == IntegerTags.INTEGER:
[fa0d0ef]187            packed_value = struct.pack('>i', self.value)
[0c4f3bf]188        elif self.tag == IntegerTags.BOOLEAN:
[569c377]189            packed_value = struct.pack('>b', self.value)
[0c4f3bf]190        elif self.tag == IntegerTags.ENUM:
[fa0d0ef]191            packed_value = struct.pack('>i', self.value)
[8979f90]192
193        # octet string value tags
[0c4f3bf]194        elif self.tag == OctetStringTags.DATETIME:
[8979f90]195            # field  octets  contents                  range
196            # -----  ------  --------                  -----
197            #   1      1-2   year                      0..65536
198            #   2       3    month                     1..12
199            #   3       4    day                       1..31
200            #   4       5    hour                      0..23
201            #   5       6    minutes                   0..59
202            #   6       7    seconds                   0..60
203            #                (use 60 for leap-second)
204            #   7       8    deci-seconds              0..9
205            #   8       9    direction from UTC        '+' / '-'
206            #   9      10    hours from UTC            0..11
207            #  10      11    minutes from UTC          0..59
[5cfb358]208
[fa0d0ef]209            packed_value = struct.pack('>hbbbbbbcbb', *self.value)
[8979f90]210           
[0c4f3bf]211        elif self.tag == OctetStringTags.RESOLUTION:
[8979f90]212            # OCTET-STRING consisting of nine octets of 2
213            # SIGNED-INTEGERs followed by a SIGNED-BYTE. The first
214            # SIGNED-INTEGER contains the value of cross feed
215            # direction resolution. The second SIGNED-INTEGER contains
216            # the value of feed direction resolution. The SIGNED-BYTE
217            # contains the units
[5cfb358]218
[556a285]219            packed_value = truct.pack('>iib', *self.value)
[8979f90]220           
[0c4f3bf]221        elif self.tag == OctetStringTags.RANGE_OF_INTEGER:
[8979f90]222            # Eight octets consisting of 2 SIGNED-INTEGERs.  The first
223            # SIGNED-INTEGER contains the lower bound and the second
224            # SIGNED-INTEGER contains the upper bound.
[5cfb358]225
[556a285]226            packed_value = struct.pack('>ii', *self.value)
[8979f90]227
[0c4f3bf]228        elif self.tag == OctetStringTags.TEXT_WITH_LANGUAGE or \
229                 self.tag == OctetStringTags.NAME_WITH_LANGUAGE:
[5cfb358]230           
[8979f90]231            a_bin = struct.pack('>h', self.value[0])
232            b_bin = struct.pack('>%ss' % self.value[0], self.value[1])
233            c_bin = struct.pack('>h', self.value[2])
234            d_bin = struct.pack('>%ss' % self.value[2], self.value[3])
[5cfb358]235
[fa0d0ef]236            packed_value = a_bin + b_bin + c_bin + d_bin
[8979f90]237
238        # character string value tags
[0c4f3bf]239        elif self.tag == \
[5cfb358]240                 CharacterStringTags.TEXT_WITHOUT_LANGUAGE or \
[0c4f3bf]241                 self.tag == \
[5cfb358]242                 CharacterStringTags.NAME_WITHOUT_LANGUAGE:
243
[fa0d0ef]244            packed_value = struct.pack('>%ss' % len(self.value),
[5cfb358]245                                       self.value)
246                   
[0c4f3bf]247        elif self.tag == CharacterStringTags.GENERIC or \
248                 self.tag == CharacterStringTags.KEYWORD or \
249                 self.tag == CharacterStringTags.URI or \
250                 self.tag == CharacterStringTags.URI_SCHEME or \
251                 self.tag == CharacterStringTags.CHARSET or \
252                 self.tag == CharacterStringTags.NATURAL_LANGUAGE or \
253                 self.tag == CharacterStringTags.MIME_MEDIA_TYPE:
[5cfb358]254           
[fa0d0ef]255            packed_value = struct.pack('>%ss' % len(self.value),
[5cfb358]256                                       self.value)
257
258        else:
[fa0d0ef]259            packed_value = self.value
[5cfb358]260
[fa0d0ef]261        return packed_value
[5cfb358]262
[5c5fe6d]263    @packed_value.setter
[a6a1f43]264    def packed_value(self, packed_value):
[fa0d0ef]265        """Replace a value using a new packed value
[5cfb358]266
[0c4f3bf]267        Unpacks a new packed_value (of the same tag).
[5cfb358]268
269        """
[0c4f3bf]270        self.value = self._unpack(self.tag, packed_value)
[5cfb358]271
[fa0d0ef]272    @property
273    def packed_value_size(self):
[5c5fe6d]274        """Get the size of the value in bytes.
275       
[5cfb358]276        """
277       
[fa0d0ef]278        return len(self.packed_value)
[8979f90]279
[fa0d0ef]280    @property
281    def total_size(self):
[5c5fe6d]282        """Get the total size of the IPP value.
283       
[c269bc7]284        """
285
[fa0d0ef]286        # 1 byte for the tag
287        return self.packed_value_size + 1
[c269bc7]288
[0c4f3bf]289    @property
290    def pyobj(self):
291        return (self.tag, self.value)
292
[5cfb358]293    def __str__(self):
[fa0d0ef]294        return str(self.value)
295
296    def __repr__(self):
[0c4f3bf]297        return '<IPPValue (%x, %r)>' % (self.tag, self.value)
Note: See TracBrowser for help on using the repository browser.