source: server/lib/gutenbach/ipp/core/attribute.py @ 441604f

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

Clean up core ipp code a bit

  • Property mode set to 100644
File size: 5.0 KB
Line 
1from .value import Value
2import sys
3import struct
4import logging
5
6# initialize logger
7logger = logging.getLogger(__name__)
8
9class Attribute(object):
10    """In addition to what the RFC reports, an attribute has an
11    'attribute tag', which specifies what type of attribute it is.  It
12    is 1 bytes long, and comes before the list of values.
13
14    From RFC 2565:
15
16    Each attribute consists of:
17    -----------------------------------------------
18    |                   value-tag                 |   1 byte
19    -----------------------------------------------
20    |               name-length  (value is u)     |   2 bytes
21    -----------------------------------------------
22    |                     name                    |   u bytes
23    -----------------------------------------------
24    |              value-length  (value is v)     |   2 bytes
25    -----------------------------------------------
26    |                     value                   |   v bytes
27    -----------------------------------------------
28
29    An additional value consists of:
30    -----------------------------------------------------------
31    |                   value-tag                 |   1 byte  |
32    -----------------------------------------------           |
33    |            name-length  (value is 0x0000)   |   2 bytes |
34    -----------------------------------------------           |-0 or more
35    |              value-length (value is w)      |   2 bytes |
36    -----------------------------------------------           |
37    |                     value                   |   w bytes |
38    -----------------------------------------------------------
39
40    """
41
42    def __init__(self, name=None, values=None):
43        """Initialize an Attribute.  This function can be called in
44        three different ways:
45
46            Attribute() -- creates an empty Attribute
47
48            Attribute(name) -- creates an empty Attribute with a name
49
50            Attribute(name, values) -- creates an Attribute
51            initialized with a name and list of values
52       
53        Arguments:
54
55            name -- the name of the attribute
56
57            values -- a list of Values.  May not be empty.
58
59        """
60
61        if name is not None and not isinstance(name, str):
62            raise ValueError("attribute name must be a string")
63        if values is None:
64            values = []
65        for value in values:
66            if not isinstance(value, Value):
67                raise ValueError("value %s must be of type Value" % (value,))
68
69        self.name = name
70        self.values = values
71
72    def __cmp__(self, other):
73        eq = self.name == other.name
74        for v1, v2 in zip(self.values, other.values):
75            eq = eq and (v1 == v2)
76        return 0 if eq else 1
77
78    @property
79    def packed_value(self):
80        """Packs the attribute data into binary data.
81       
82        """
83
84        if self.name is None:
85            raise ValueError, "cannot pack unnamed attribute"
86        if len(self.values) == 0:
87            raise ValueError, "cannot pack empty attribute"
88
89        # get the binary data for all the values
90        values = []
91        for v, i in zip(self.values, xrange(len(self.values))):
92
93            # get the name length (0 for everything but the first
94            # value)
95            name_length = len(self.name) if i == 0 else 0
96
97            logger.debug("dumping name : %s" % self.name)
98            logger.debug("dumping name_length : %i" % name_length)
99            logger.debug("value tag : 0x%x" % v.tag)
100
101            # get the binary value
102            value_bin = v.packed_value
103            # get the value length
104            value_length = len(value_bin)
105
106            logger.debug("dumping value : %s" % v.value)
107            logger.debug("dumping value_length : %i" % value_length)
108
109            # the value tag in binary
110            tag_bin = struct.pack('>b', v.tag)
111            # the name length in binary
112            name_length_bin = struct.pack('>h', name_length)
113            # the name in binary
114            name_bin = self.name
115            # the value length in binary
116            value_length_bin = struct.pack('>h', value_length)
117
118            # add the binary value to the list of values
119            vlist = [tag_bin, name_length_bin, value_length_bin, value_bin]
120            if i == 0:
121                vlist.insert(2, name_bin)
122            values.append(''.join(vlist))
123
124        # concatenate everything together and return it along with the
125        # total length of the attribute
126        return ''.join(values)
127
128    @property
129    def packed_value_size(self):
130        """Gets the total size of the attribute.
131       
132        """
133
134        return len(self.packed_value)
135
136    total_size = packed_value_size
137
138    def __str__(self):
139        if len(self.values) > 0:
140            values = [str(v) for v in self.values]
141        else:
142            values = "None"
143
144        if self.name is None:
145            name = "None"
146        else:
147            name = self.name
148       
149        return "%s: %s" % (name, str(values))
150
151    def __repr__(self):
152        return '<IPPAttribute (%r, %r)>' % (self.name, self.values)
Note: See TracBrowser for help on using the repository browser.