1
2
3
4
5
6
7
8
9
10 """ WSP Data Unit structure encoding and decoding classes
11
12 Throughout the classes defined in this module, the following "primitive data
13 type" terminology applies, as specified in [5], section 8.1.1::
14
15 Data Type Definition
16 bit 1 bit of data
17 octet 8 bits of opaque data
18 uint8 8-bit unsigned integer
19 uint16 16-bit unsigned integer
20 uint32 32-bit unsigned integer
21 uintvar variable length unsigned integer
22
23 This Encoder and Decoder classes provided in this module firstly provides
24 public methods for decoding and encoding each of these data primitives (where
25 needed).
26
27 Next, they provide methods encapsulating the basic WSP Header encoding rules
28 as defined in section 8.4.2.1 of [5].
29
30 Finally, the classes defined here provide methods for decoding/parsing
31 specific WSP header fields.
32
33 @author: Francois Aucamp C{<faucamp@csir.co.za>}
34 @license: GNU Lesser General Public License, version 2
35 @note: This is part of the PyMMS library
36
37 @note: References used in the code and this document:
38 5. Wap Forum/Open Mobile Alliance, "WAP-230 Wireless Session Protocol Specification"
39 U{http://www.openmobilealliance.org/tech/affiliates/LicenseAgreement.asp?DocName=/wap/wap-230-wsp-20010705-a.pdf}
40 """
41
42 import array
43 from iterator import PreviewIterator
44
45
46
47
48
50 """ Static class containing the constant values defined in [5] for
51 well-known content types, parameter names, etc.
52
53 It also defines some function for combining assigned number-tables for
54 specific WSP encoding versions, where appropriate.
55
56 This is used by both the Encoder and Decoder classes during well-known
57 assigned number lookups (usually these functions have the string
58 C{WellKnown} in their names).
59
60 - Assigned parameters are stored in a dictionary, C{wkParameters},
61 containing all assigned values for WSP encoding versions 1.1 - 1.4,
62 in the format:
63 C{{<int>assigned number: (<str>name, <str>expected value type)}}
64 A "encoding versioned"-version of this dictionary can be retrieved
65 by calling the C{wellKnowParameters()} function with an appropriate
66 WSP encoding version as parameter.
67 - Assigned content types are stored in a list, C{wkContentTypes}, in
68 order; thus, their index in the list is equal to their assigned
69 value.
70
71 """
72 wspPDUTypes = {0x01: 'Connect',
73 0x02: 'ConnectReply',
74 0x03: 'Redirect',
75 0x04: 'Reply',
76 0x05: 'Disconnect',
77 0x06: 'Push',
78 0x07: 'ConfirmedPush',
79 0x08: 'Suspend',
80 0x09: 'Resume',
81 0x40: 'Get',
82 0x60: 'Post'}
83
84
85 wkParameters = {0x00: ('Q', 'QValue'),
86 0x01: ('Charset', 'WellKnownCharset'),
87 0x02: ('Level', 'VersionValue'),
88 0x03: ('Type', 'IntegerValue'),
89 0x05: ('Name', 'TextString'),
90 0x06: ('Filename', 'TextString'),
91 0x07: ('Differences', 'Field-name'),
92 0x08: ('Padding', 'ShortInteger'),
93 0x09: ('Type', 'ConstrainedEncoding'),
94 0x0a: ('Start', 'TextString'),
95 0x0b: ('Start-info', 'TextString'),
96 0x0c: ('Comment', 'TextString'),
97 0x0d: ('Domain', 'TextString'),
98 0x0e: ('Max-Age', 'DeltaSecondsValue'),
99 0x0f: ('Path', 'TextString'),
100 0x10: ('Secure', 'NoValue'),
101 0x11: ('SEC', 'ShortInteger'),
102 0x12: ('MAC', 'TextValue'),
103 0x13: ('Creation-date', 'DateValue'),
104 0x14: ('Modification-date', 'DateValue'),
105 0x15: ('Read-date', 'DateValue'),
106 0x16: ('Size', 'IntegerValue'),
107 0x17: ('Name', 'TextValue'),
108 0x18: ('Filename', 'TextValue'),
109 0x19: ('Start', 'TextValue'),
110 0x1a: ('Start-info', 'TextValue'),
111 0x1b: ('Comment', 'TextValue'),
112 0x1c: ('Domain', 'TextValue'),
113 0x1d: ('Path', 'TextValue')}
114
115
116 wkContentTypes = ['*/*', 'text/*', 'text/html', 'text/plain',
117 'text/x-hdml', 'text/x-ttml', 'text/x-vCalendar',
118 'text/x-vCard', 'text/vnd.wap.wml',
119 'text/vnd.wap.wmlscript', 'text/vnd.wap.wta-event',
120 'multipart/*', 'multipart/mixed', 'multipart/form-data',
121 'multipart/byterantes', 'multipart/alternative',
122 'application/*', 'application/java-vm',
123 'application/x-www-form-urlencoded',
124 'application/x-hdmlc', 'application/vnd.wap.wmlc',
125 'application/vnd.wap.wmlscriptc',
126 'application/vnd.wap.wta-eventc',
127 'application/vnd.wap.uaprof',
128 'application/vnd.wap.wtls-ca-certificate',
129 'application/vnd.wap.wtls-user-certificate',
130 'application/x-x509-ca-cert',
131 'application/x-x509-user-cert',
132 'image/*', 'image/gif', 'image/jpeg', 'image/tiff',
133 'image/png', 'image/vnd.wap.wbmp',
134 'application/vnd.wap.multipart.*',
135 'application/vnd.wap.multipart.mixed',
136 'application/vnd.wap.multipart.form-data',
137 'application/vnd.wap.multipart.byteranges',
138 'application/vnd.wap.multipart.alternative',
139 'application/xml', 'text/xml',
140 'application/vnd.wap.wbxml',
141 'application/x-x968-cross-cert',
142 'application/x-x968-ca-cert',
143 'application/x-x968-user-cert',
144 'text/vnd.wap.si',
145 'application/vnd.wap.sic',
146 'text/vnd.wap.sl',
147 'application/vnd.wap.slc',
148 'text/vnd.wap.co',
149 'application/vnd.wap.coc',
150 'application/vnd.wap.multipart.related',
151 'application/vnd.wap.sia',
152 'text/vnd.wap.connectivity-xml',
153 'application/vnd.wap.connectivity-wbxml',
154 'application/pkcs7-mime',
155 'application/vnd.wap.hashed-certificate',
156 'application/vnd.wap.signed-certificate',
157 'application/vnd.wap.cert-response',
158 'application/xhtml+xml',
159 'application/wml+xml',
160 'text/css',
161 'application/vnd.wap.mms-message',
162 'application/vnd.wap.rollover-certificate',
163 'application/vnd.wap.locc+wbxml',
164 'application/vnd.wap.loc+xml',
165 'application/vnd.syncml.dm+wbxml',
166 'application/vnd.syncml.dm+xml',
167 'application/vnd.syncml.notification',
168 'application/vnd.wap.xhtml+xml',
169 'application/vnd.wv.csp.cir',
170 'application/vnd.oma.dd+xml',
171 'application/vnd.oma.drm.message',
172 'application/vnd.oma.drm.content',
173 'application/vnd.oma.drm.rights+xml',
174 'application/vnd.oma.drm.rights+wbxml']
175
176
177
178
179
180
181
182 wkCharSets = {0x07EA: 'big5',
183 0x03E8: 'iso-10646-ucs-2',
184 0x04: 'iso-8859-1',
185 0x05: 'iso-8859-2',
186 0x06: 'iso-8859-3',
187 0x07: 'iso-8859-4',
188 0x08: 'iso-8859-5',
189 0x09: 'iso-8859-6',
190 0x0A: 'iso-8859-7',
191 0x0B: 'iso-8859-8',
192 0x0C: 'iso-8859-9',
193 0x11: 'shift_JIS',
194 0x03: 'us-ascii',
195 0x6A: 'utf-8'}
196
197
198 hdrFieldNames = ['Accept', 'Accept-Charset', 'Accept-Encoding',
199 'Accept-Language', 'Accept-Ranges', 'Age',
200 'Allow', 'Authorization', 'Cache-Control',
201 'Connection', 'Content-Base', 'Content-Encoding',
202 'Content-Language', 'Content-Length',
203 'Content-Location', 'Content-MD5', 'Content-Range',
204 'Content-Type', 'Date', 'Etag', 'Expires', 'From',
205 'Host', 'If-Modified-Since', 'If-Match',
206 'If-None-Match', 'If-Range', 'If-Unmodified-Since',
207 'Location', 'Last-Modified', 'Max-Forwards', 'Pragma',
208 'Proxy-Authenticate', 'Proxy-Authorization', 'Public',
209 'Range', 'Referer', 'Retry-After', 'Server',
210 'Transfer-Encoding', 'Upgrade', 'User-Agent',
211 'Vary', 'Via', 'Warning', 'WWW-Authenticate',
212 'Content-Disposition',
213
214 'X-Wap-Application-Id', 'X-Wap-Content-URI',
215 'X-Wap-Initiator-URI', 'Accept-Application',
216 'Bearer-Indication', 'Push-Flag', 'Profile',
217 'Profile-Diff', 'Profile-Warning',
218
219 'Expect', 'TE', 'Trailer', 'Accept-Charset',
220 'Accept-Encoding', 'Cache-Control',
221 'Content-Range', 'X-Wap-Tod', 'Content-ID',
222 'Set-Cookie', 'Cookie', 'Encoding-Version',
223
224 'Profile-Warning', 'Content-Disposition',
225 'X-WAP-Security', 'Cache-Control']
226
227
228
229 hdrFieldEncodings = {'Accept': 'AcceptValue',
230 'Pragma': 'PragmaValue'}
231
232 @staticmethod
234 """ Formats list of assigned values for well-known parameter names,
235 for the specified WSP encoding version.
236
237 @param encodingVersion: The WSP encoding version to use. This defaults
238 to "1.2", but may be "1.1", "1.2", "1.3" or
239 "1.4" (see table 38 in [5] for details).
240 @type encodingVersion: str
241
242 @raise ValueError: The specified encoding version is invalid.
243
244 @return: A dictionary containing the well-known parameters with
245 assigned numbers for the specified encoding version (and
246 lower). Entries in this dict follow the format:
247 C{{<int:assigned_number> : (<str:param_name>, <str:expected_type>)}}
248 @rtype: dict
249 """
250 if encodingVersion not in ('1.1', '1.2', '1.3', '1.4'):
251 raise ValueError, 'encodingVersion must be "1.1", "1.2", "1.3" or "1.4"'
252 else:
253 version = int(encodingVersion.split('.')[1])
254 wkVersionedParameters = dict(WSPEncodingAssignments.wkParameters)
255 if version <= 3:
256 for assignedNumber in range(0x11, 0x1e):
257 del wkVersionedParameters[assignedNumber]
258 if version <= 2:
259 for assignedNumber in range(0x0c, 0x11):
260 del wkVersionedParameters[assignedNumber]
261 if version == 1:
262 for assignedNumber in range(0x09, 0x0c):
263 del wkVersionedParameters[assignedNumber]
264 return wkVersionedParameters
265
266 @staticmethod
268 """ Formats list of assigned values for header field names, for the
269 specified WSP encoding version.
270
271 @param encodingVersion: The WSP encoding version to use. This defaults
272 to "1.2", but may be "1.1", "1.2", "1.3" or
273 "1.4" (see table 39 in [5] for details).
274 @type encodingVersion: str
275
276 @raise ValueError: The specified encoding version is invalid.
277
278 @return: A list containing the WSP header field names with assigned
279 numbers for the specified encoding version (and lower).
280 @rtype: list
281 """
282 if encodingVersion not in ('1.1', '1.2', '1.3', '1.4'):
283 raise ValueError, 'encodingVersion must be "1.1", "1.2", "1.3" or "1.4"'
284 else:
285 version = int(encodingVersion.split('.')[1])
286 versionedHdrFieldNames = list(WSPEncodingAssignments.hdrFieldNames)
287 if version == 3:
288 versionedHdrFieldNames = versionedHdrFieldNames[:0x44]
289 elif version == 2:
290 versionedHdrFieldNames = versionedHdrFieldNames[:0x38]
291 elif version == 1:
292 versionedHdrFieldNames = versionedHdrFieldNames[:0x2f]
293 return versionedHdrFieldNames
294
295
297 """ The decoding operation failed; most probably due to an invalid byte in
298 the sequence provided for decoding """
299
301 """ The encoding operation failed; most probably due to an invalid value
302 provided for encoding """
303
305 """ A WSP Data unit decoder """
306 @staticmethod
308 """ Decodes an 8-bit unsigned integer from the byte pointed to by
309 C{byteIter.next()}
310
311 @note: this function will move the iterator passed as C{byteIter} one
312 byte forward.
313
314 @param byteIter: an iterator over a sequence of bytes
315 @type byteIter: iter
316
317 @return: the decoded 8-bit unsigned integer
318 @rtype: int
319 """
320
321 return byteIter.next() & 0xff
322
323 @staticmethod
325 """ Decodes the variable-length unsigned integer starting at the
326 byte pointed to by C{byteIter.next()}
327
328 See C{wsp.Encoder.encodeUintvar()} for a detailed description of the
329 encoding scheme used for C{Uintvar} sequences.
330
331 @note: this function will move the iterator passed as C{byteIter} to
332 the last octet in the uintvar sequence; thus, after calling
333 this, that iterator's C{next()} function will return the first
334 byte B{after}the uintvar sequence.
335
336 @param byteIter: an iterator over a sequence of bytes
337 @type byteIter: iter
338
339 @return: the decoded unsigned integer
340 @rtype: int
341 """
342 uint = 0
343 byte = byteIter.next()
344 while (byte >> 7) == 0x01:
345 uint = uint << 7
346 uint |= byte & 0x7f
347 byte = byteIter.next()
348 uint = uint << 7
349 uint |= byte & 0x7f
350 return uint
351
352
353 @staticmethod
355 """ Decodes the short-integer value starting at the byte pointed to
356 by C{byteIter.next()}.
357
358 The encoding for a long integer is specified in [5], section 8.4.2.1:
359 C{Short-integer = OCTET
360 Integers in range 0-127 shall be encoded as a one octet value with
361 the most significant bit set to one (1xxx xxxx) and with the value
362 in the remaining least significant bits.}
363
364 @raise DecodeError: Not a valid short-integer; the most significant
365 isn't set to 1.
366 C{byteIter} will not be modified if this is raised
367
368 @return: The decoded short integer
369 @rtype: int
370 """
371 byte = byteIter.preview()
372 if not byte & 0x80:
373 byteIter.resetPreview()
374 raise DecodeError, 'Not a valid short-integer: most significant bit not set'
375 byte = byteIter.next()
376 return byte & 0x7f
377
378 @staticmethod
380 """ Decodes the short-integer value contained in the specified byte
381 value
382
383 @param byte: the byte value to decode
384 @type byte: int
385
386 @raise DecodeError: Not a valid short-integer; the most significant
387 isn't set to 1.
388 @return: The decoded short integer
389 @rtype: int
390 """
391 if not byte & 0x80:
392 raise DecodeError, 'Not a valid short-integer: most significant bit not set'
393 return byte & 0x7f
394
395 @staticmethod
397 """ Decodes the long integer value starting at the byte pointed to
398 by C{byteIter.next()}.
399
400 The encoding for a long integer is specified in [5], section 8.4.2.1,
401 and follows the form::
402
403 Long-integer = [Short-length] [Multi-octet-integer]
404 ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
405 1 byte <Short-length> bytes
406
407 The Short-length indicates the length of the Multi-octet-integer.
408
409 @raise DecodeError: The byte pointed to by C{byteIter.next()} does
410 not indicate the start of a valid long-integer
411 sequence (short-length is invalid). If this is
412 raised, the iterator passed as C{byteIter} will
413 not be modified.
414
415 @note: If this function returns successfully, it will move the
416 iterator passed as C{byteIter} to the last octet in the encoded
417 long integer sequence; thus, after calling this, that
418 iterator's C{next()} function will return the first byte
419 B{after}the encoded long integer sequence.
420
421 @param byteIter: an iterator over a sequence of bytes
422 @type byteIter: iter
423
424 @return: The decoded long integer
425 @rtype: int
426 """
427 try:
428 shortLength = Decoder.decodeShortLength(byteIter)
429 except DecodeError:
430 raise DecodeError, 'Not a valid long-integer: short-length byte is invalid'
431 longInt = 0
432
433 for i in range(shortLength):
434 longInt = longInt << 8
435 longInt |= byteIter.next()
436 return longInt
437
438 @staticmethod
439 - def decodeTextString(byteIter):
440 """ Decodes the null-terminated, binary-encoded string value starting
441 at the byte pointed to by C{dataIter.next()}.
442
443 This follows the basic encoding rules specified in [5], section
444 8.4.2.1
445
446 @note: this function will move the iterator passed as C{byteIter} to
447 the last octet in the encoded string sequence; thus, after
448 calling this, that iterator's C{next()} function will return
449 the first byte B{after}the encoded string sequence.
450
451 @param byteIter: an iterator over a sequence of bytes
452 @type byteIter: iter
453
454 @return: The decoded text string
455 @rtype: str
456 """
457 decodedString = ''
458 byte = byteIter.next()
459
460 if byte == 127:
461 byte = byteIter.next()
462 while byte != 0x00:
463 decodedString += chr(byte)
464 byte = byteIter.next()
465 return decodedString
466
467 @staticmethod
469 """ From [5], section 8.4.2.1:
470 Quoted-string = <Octet 34> *TEXT End-of-string
471 The TEXT encodes an RFC2616 Quoted-string with the enclosing
472 quotation-marks <"> removed
473
474 @return: The decoded text string
475 @rtype: str
476 """
477
478
479 byte = byteIter.preview()
480 if byte != 34:
481 byteIter.resetPreview()
482 raise DecodeError, 'Invalid quoted string; must start with <octect 34>'
483 else:
484 byteIter.next()
485
486
487 return Decoder.decodeTextString(byteIter)
488
489
490 @staticmethod
491 - def decodeTokenText(byteIter):
492 """ From [5], section 8.4.2.1:
493 Token-text = Token End-of-string
494
495 @raise DecodeError: invalid token; in this case, byteIter is not modified
496
497 @return: The token string if successful, or the byte that was read if not
498 @rtype: str or int
499 """
500 separators = (11, 32, 40, 41, 44, 47, 58, 59, 60, 61, 62, 63, 64, 91,
501 92, 93, 123, 125)
502 token = ''
503
504
505 byte = byteIter.preview()
506 if byte <= 31 or byte in separators:
507 byteIter.resetPreview()
508 raise DecodeError, 'Invalid token'
509 byte = byteIter.next()
510 while byte > 31 and byte not in separators:
511 token += chr(byte)
512 byte = byteIter.next()
513 return token
514
515 @staticmethod
540
541
542 @staticmethod
544 """ Constrained-encoding = Extension-Media --or-- Short-integer
545 This encoding is used for token values, which have no well-known
546 binary encoding, or when the assigned number of the well-known
547 encoding is small enough to fit into Short-integer.
548
549 @return: The decoding constrained-encoding token value
550 @rtype: str or int
551 """
552 result = None
553
554 try:
555
556
557 result = Decoder.decodeShortInteger(byteIter)
558
559 except DecodeError, msg:
560
561 try:
562
563 result = Decoder.decodeExtensionMedia(byteIter)
564 except DecodeError, msg:
565
566
567
568
569
570
571 raise DecodeError, 'Not a valid Constrained-encoding sequence'
572
573 return result
574
575 @staticmethod
577 """ From [5], section 8.4.2.2:
578 Short-length = <Any octet 0-30>
579
580 @raise DecodeError: The byte is not a valid short-length value;
581 it is not in octet range 0-30. In this case, the
582 iterator passed as C{byteIter} is not modified.
583
584 @note: If this function returns successfully, the iterator passed as
585 C{byteIter} is moved one byte forward.
586
587 @return: The decoded short-length
588 @rtype: int
589 """
590
591
592
593 byte = byteIter.preview()
594 if byte > 30:
595 byteIter.resetPreview()
596 raise DecodeError, 'Not a valid short-length; should be in octet range 0-30'
597 else:
598 return byteIter.next()
599
600 @staticmethod
602 """ Decodes the value length indicator starting at the byte pointed to
603 by C{byteIter.next()}.
604
605 "Value length" is used to indicate the length of a value to follow, as
606 used in the C{Content-Type} header in the MMS body, for example.
607
608 The encoding for a value length indicator is specified in [5],
609 section 8.4.2.2, and follows the form::
610
611 Value-length = [Short-length] --or-- [Length-quote] [Length]
612 ^^^^^^ ^^^^^^ ^^^^^^
613 1 byte 1 byte x bytes
614 <Any octet 0-30> <Octet 31> Uintvar-integer
615
616 @raise DecodeError: The ValueLength could not be decoded. If this
617 happens, C{byteIter} is not modified.
618
619 @return: The decoded value length indicator
620 @rtype: int
621 """
622 lengthValue = 0
623
624 try:
625 lengthValue = Decoder.decodeShortLength(byteIter)
626 except DecodeError:
627 byte = byteIter.preview()
628
629 if byte == 31:
630 byteIter.next()
631 lengthValue = Decoder.decodeUintvar(byteIter)
632 else:
633 byteIter.resetPreview()
634 raise DecodeError, 'Invalid Value-length: not short-length, and no length-quote present'
635 return lengthValue
636
637 @staticmethod
639 """ From [5], section 8.4.2.3:
640 Integer-Value = Short-integer | Long-integer
641
642 @raise DecodeError: The sequence of bytes starting at
643 C{byteIter.next()} does not contain a valid
644 integervalue. If this is raised, the iterator
645 passed as C{byteIter} is not modified.
646
647 @note: If successful, this function will move the iterator passed as
648 C{byteIter} to the last octet in the integer value sequence;
649 thus, after calling this, that iterator's C{next()} function
650 will return the first byte B{after}the integer value sequence.
651
652 @return: The decoded integer value
653 @rtype: int
654 """
655 integer = 0
656
657 try:
658 integer = Decoder.decodeShortInteger(byteIter)
659 except DecodeError:
660 try:
661 integer = Decoder.decodeLongInteger(byteIter)
662 except DecodeError:
663 raise DecodeError, 'Not a valid integer value'
664 return integer
665
666 @staticmethod
668 """ Decodes an encoded content type value.
669
670 From [5], section 8.4.2.24:
671 C{Content-type-value = Constrained-media | Content-general-form}
672
673 The short form of the Content-type-value MUST only be used when the
674 well-known media is in the range of 0-127 or a text string. In all
675 other cases the general form MUST be used.
676
677 @return: The media type (content type), and a dictionary of
678 parameters to this content type (which is empty if there
679 are no parameters). This parameter dictionary is in the
680 format:
681 C{{<str:parameter_name>: <str/int/float:parameter_value>}}.
682 The final returned tuple is in the format:
683 (<str:media_type>, <dict:parameter_dict>)
684 @rtype: tuple
685 """
686
687 contentType = ''
688 parameters = {}
689 try:
690 contentType = Decoder.decodeConstrainedMedia(byteIter)
691 except DecodeError:
692
693 contentType, parameters = Decoder.decodeContentGeneralForm(byteIter)
694 return (contentType, parameters)
695
696
697 @staticmethod
738
739
740 @staticmethod
758
759 @staticmethod
784
785 @staticmethod
787 """ From [5], section 8.4.2.24:
788 Content-general-form = Value-length Media-type
789
790 @note: Used in decoding Content-type fields and their parameters;
791 see C{decodeContentTypeValue}
792
793 @note: Used by C{decodeContentTypeValue()}
794
795 @return: The media type (content type), and a dictionary of
796 parameters to this content type (which is empty if there
797 are no parameters). This parameter dictionary is in the
798 format:
799 C{{<str:parameter_name>: <str/int/float:parameter_value>}}.
800 The final returned tuple is in the format:
801 (<str:media_type>, <dict:parameter_dict>)
802 @rtype: tuple
803 """
804
805
806 valueLength = Decoder.decodeValueLength(byteIter)
807
808
809
810
811
812 ctFieldBytes = array.array('B')
813 for i in range(valueLength):
814 ctFieldBytes.append(byteIter.next())
815
816 ctIter = PreviewIterator(ctFieldBytes)
817
818 mediaType = Decoder.decodeMediaType(ctIter)
819
820 parameters = {}
821 while True:
822 try:
823 parameter, value = Decoder.decodeParameter(ctIter)
824 parameters[parameter] = value
825 except StopIteration:
826 break
827 return (mediaType, parameters)
828
829 @staticmethod
831 """ From [5], section 8.4.2.4:
832 Parameter = Typed-parameter | Untyped-parameter
833
834 @return: The name of the parameter, and its value, in the format:
835 (<parameter name>, <parameter value>)
836 @rtype: tuple
837 """
838 try:
839 parameter, value = Decoder.decodeTypedParameter(byteIter)
840 except DecodeError:
841 parameter, value = Decoder.decodeUntypedParameter(byteIter)
842 return (parameter, value)
843
844 @staticmethod
846 """ From [5], section 8.4.2.4:
847 C{Typed-parameter = Well-known-parameter-token Typed-value}
848 The actual expected type of the value is implied by the well-known
849 parameter.
850
851 @note: This is used in decoding parameters; see C{decodeParameter}
852
853 @return: The name of the parameter, and its value, in the format:
854 (<parameter name>, <parameter value>)
855 @rtype: tuple
856 """
857 parameterToken, expectedValueType = Decoder.decodeWellKnownParameter(byteIter)
858 typedValue = ''
859 try:
860
861
862
863
864 exec 'typedValue = Decoder.decode%s(byteIter)' % expectedValueType
865 except DecodeError, msg:
866 raise DecodeError, 'Could not decode Typed-parameter: %s' % msg
867 except:
868 print 'A fatal error occurred, probably due to an unimplemented decoding operation'
869 raise
870 return (parameterToken, typedValue)
871
872 @staticmethod
874 """ From [5], section 8.4.2.4:
875 C{Untyped-parameter = Token-text Untyped-value}
876 The type of the value is unknown, but it shall be encoded as an
877 integer, if that is possible.
878
879 @note: This is used in decoding parameters; see C{decodeParameter}
880
881 @return: The name of the parameter, and its value, in the format:
882 (<parameter name>, <parameter value>)
883 @rtype: tuple
884 """
885 parameterToken = Decoder.decodeTokenText(byteIter)
886 parameterValue = Decoder.decodeUntypedValue(byteIter)
887 return (parameterToken, parameterValue)
888
889 @staticmethod
891 """ From [5], section 8.4.2.4:
892 Untyped-value = Integer-value | Text-value
893
894 @note: This is used in decoding parameter values; see
895 C{decodeUntypedParameter}
896 @return: The decoded untyped-value
897 @rtype: int or str
898 """
899 try:
900 value = Decoder.decodeIntegerValue(byteIter)
901 except DecodeError:
902 value = Decoder.decodeTextValue(byteIter)
903 return value
904
905 @staticmethod
907 """ Decodes the name and expected value type of a parameter of (for
908 example) a "Content-Type" header entry, taking into account the WSP
909 short form (assigned numbers) of well-known parameter names, as
910 specified in section 8.4.2.4 and table 38 of [5].
911
912 From [5], section 8.4.2.4:
913 Well-known-parameter-token = Integer-value
914 The code values used for parameters are specified in [5], table 38
915
916 @raise ValueError: The specified encoding version is invalid.
917
918 @raise DecodeError: This is raised if the integer value representing
919 the well-known parameter name cannot be decoded
920 correctly, or the well-known paramter token value
921 could not be found in the table of assigned
922 content types.
923 If this exception is raised, the iterator passed
924 as C{byteIter} is not modified.
925
926 @param encodingVersion: The WSP encoding version to use. This defaults
927 to "1.2", but may be "1.1", "1.2", "1.3" or
928 "1.4" (see table 39 in [5] for details).
929 @type encodingVersion: str
930
931 @return: the decoded parameter name, and its expected value type, in
932 the format (<parameter name>, <expected type>)
933 @rtype: tuple
934 """
935 decodedParameterName = ''
936 expectedValue = ''
937
938 try:
939
940 wkParameterValue = Decoder.decodeIntegerValue(byteIter)
941 except DecodeError:
942 raise DecodeError, 'Invalid well-known parameter token: could not read integer value representing it'
943
944 wkParameters = WSPEncodingAssignments.wellKnownParameters(encodingVersion)
945 if wkParameterValue in wkParameters:
946 decodedParameterName, expectedValue = wkParameters[wkParameterValue]
947
948
949 else:
950
951 raise DecodeError, 'Invalid well-known parameter token: could not find in table of assigned numbers (encoding version %s)' % encodingVersion
952 return (decodedParameterName, expectedValue)
953
954
955 @staticmethod
957 """ From [5], section 8.4.2.4:
958 Typed-value = Compact-value | Text-value
959 In addition to the expected type, there may be no value.
960 If the value cannot be encoded using the expected type, it shall be
961 encoded as text.
962
963 @note: This is used in decoding parameters, see C{decodeParameter()}
964
965 @return: The decoded Parameter Typed-value
966 @rtype: str
967 """
968 typedValue = ''
969 try:
970 typedValue = Decoder.decodeCompactValue(byteIter)
971 except DecodeError:
972 try:
973 typedValue = Decoder.decodeTextValue(byteIter)
974 except DecodeError:
975 raise DecodeError, 'Could not decode the Parameter Typed-value'
976 return typedValue
977
978
979 @staticmethod
981 """ From [5], section 8.4.2.4:
982 Compact-value = Integer-value | Date-value | Delta-seconds-value
983 | Q-value | Version-value | Uri-value
984
985 @raise DecodeError: Failed to decode the Parameter Compact-value;
986 if this happens, C{byteIter} is unmodified
987
988 @note: This is used in decoding parameters, see C{decodeTypeValue()}
989
990 @return: The decoded Compact-value (this is specific to the
991 parameter type
992 @rtype: str or int
993 """
994 compactValue = None
995 try:
996
997
998 compactValue = Decoder.decodeIntegerValue(byteIter)
999 except DecodeError:
1000 try:
1001
1002 compactValue = Decoder.decodeUriValue(byteIter)
1003 except DecodeError:
1004 raise DecodeError, 'Could not decode Parameter Compact-value'
1005 return compactValue
1006
1007
1008 @staticmethod
1010 """ From [5], section 8.4.2.3:
1011 Date-value = Long-integer
1012 The encoding of dates shall be done in number of seconds from
1013 1970-01-01, 00:00:00 GMT.
1014
1015 @raise DecodeError: This method uses C{decodeLongInteger}, and thus
1016 raises this under the same conditions.
1017
1018 @return: The date, in a format such as: C{Tue Nov 27 16:12:21 2007}
1019 @rtype: str
1020 """
1021 import time
1022 return time.ctime(Decoder.decodeLongInteger(byteIter))
1023
1024 @staticmethod
1026 """ From [5], section 8.4.2.3:
1027 Delta-seconds-value = Integer-value
1028 @raise DecodeError: This method uses C{decodeIntegerValue}, and thus
1029 raises this under the same conditions.
1030 @return: the decoded delta-seconds-value
1031 @rtype: int
1032 """
1033 return Decoder.decodeIntegerValue(byteIter)
1034
1035 @staticmethod
1037 """ From [5], section 8.4.2.1:
1038 The encoding is the same as in Uintvar-integer, but with restricted
1039 size. When quality factor 0 and quality factors with one or two
1040 decimal digits are encoded, they shall be multiplied by 100 and
1041 incremented by one, so that they encode as a one-octet value in
1042 range 1-100, ie, 0.1 is encoded as 11 (0x0B) and 0.99 encoded as
1043 100 (0x64). Three decimal quality factors shall be multiplied with
1044 1000 and incremented by 100, and the result shall be encoded as a
1045 one-octet or two-octet uintvar, eg, 0.333 shall be encoded as 0x83 0x31.
1046 Quality factor 1 is the default value and shall never be sent.
1047
1048 @return: The decode quality factor (Q-value)
1049 @rtype: float
1050 """
1051 qValue = 0.0
1052 qValueInt = Decoder.decodeUintvar(byteIter)
1053
1054 if qValueInt > 100:
1055 qValue = float(qValueInt - 100) / 1000.0
1056 else:
1057 qValue = float(qValueInt - 1) / 100.0
1058 return qValue
1059
1060
1061 @staticmethod
1063 """ Decodes the version-value. From [5], section 8.4.2.3:
1064 Version-value = Short-integer | Text-string
1065
1066 @return: the decoded version value in the format, usually in the
1067 format: "<major_version>.<minor_version>"
1068 @rtype: str
1069 """
1070 version = ''
1071 try:
1072 byteValue = Decoder.decodeShortInteger(byteIter)
1073 major = (byteValue & 0x70) >> 4
1074 minor = byteValue & 0x0f
1075 version = '%d.%d' % (major, minor)
1076 except DecodeError:
1077 version = Decoder.decodeTextString(byteIter)
1078 return version
1079
1080 @staticmethod
1082 """ Stub for Uri-value decoding; this is a wrapper to C{decodeTextString} """
1083 return Decoder.decodeTextString(byteIter)
1084
1085 @staticmethod
1086 - def decodeTextValue(byteIter):
1087 """ Stub for Parameter Text-value decoding.
1088 From [5], section 8.4.2.3:
1089 Text-value = No-value | Token-text | Quoted-string
1090
1091 This is used when decoding parameter values; see C{decodeTypedValue()}
1092
1093 @return: The decoded Parameter Text-value
1094 @rtype: str
1095 """
1096 textValue = ''
1097 try:
1098 textValue = Decoder.decodeTokenText(byteIter)
1099 except DecodeError:
1100 try:
1101 textValue = Decoder.decodeQuotedString(byteIter)
1102 except DecodeError:
1103
1104 pass
1105 return textValue
1106
1107 @staticmethod
1109 """ Basically verifies that the byte pointed to by C{byteIter.next()}
1110 is 0x00.
1111
1112 @note: If successful, this function will move C{byteIter} one byte
1113 forward.
1114
1115 @raise DecodeError: If 0x00 is not found; C{byteIter} is not modified
1116 if this is raised.
1117
1118 @return: No-value, which is 0x00
1119 @rtype: int
1120 """
1121 byteIter, localIter = byteIter.next()
1122 if localIter.next() != 0x00:
1123 raise DecodeError, 'Expected No-value'
1124 else:
1125 byteIter.next()
1126 return 0x00
1127
1128 @staticmethod
1130 """ From [5], section 8.4.2.7:
1131 Accept-value = Constrained-media | Accept-general-form
1132 Accept-general-form = Value-length Media-range [Accept-parameters]
1133 Media-range = (Well-known-media | Extension-Media) *(Parameter)
1134 Accept-parameters = Q-token Q-value *(Accept-extension)
1135 Accept-extension = Parameter
1136 Q-token = <Octet 128>
1137
1138 @note: most of these things are currently decoded, but discarded (e.g
1139 accept-parameters); we only return the media type
1140
1141 @raise DecodeError: The decoding failed. C{byteIter} will not be
1142 modified in this case.
1143 @return: the decoded Accept-value (media/content type)
1144 @rtype: str
1145 """
1146 acceptValue = ''
1147
1148 try:
1149 acceptValue = Decoder.decodeConstrainedMedia(byteIter)
1150 except DecodeError:
1151
1152 valueLength = Decoder.decodeValueLength(byteIter)
1153 try:
1154 media = Decoder.decodeWellKnownMedia(byteIter)
1155 except DecodeError:
1156 media = Decoder.decodeExtensionMedia(byteIter)
1157
1158 if byteIter.preview() == 128:
1159 byteIter.next()
1160 qValue = Decoder.decodeQValue(byteIter)
1161 try:
1162 acceptExtension = Decoder.decodeParameter(byteIter)
1163 except DecodeError:
1164
1165 acceptExtension = []
1166 byteIter.resetPreview()
1167 acceptValue = media
1168 return acceptValue
1169
1170 @staticmethod
1172 """ Defined in [5], section 8.4.2.38:
1173 Pragma-value = No-cache | (Value-length Parameter)
1174
1175 From [5], section 8.4.2.15:
1176 No-cache = <Octet 128>
1177
1178 @raise DecodeError: The decoding failed. C{byteIter} will not be
1179 modified in this case.
1180 @return: the decoded Pragma-value, in the format:
1181 (<parameter name>, <parameter value>)
1182 @rtype: tuple
1183 """
1184 byte = byteIter.preview()
1185 if byte == 0x80:
1186 byteIter.next()
1187
1188 parameterName = 'Cache-control'
1189 parameterValue = 'No-cache'
1190 else:
1191 byteIter.resetPreview()
1192 valueLength = Decoder.decodeValueLength(byteIter)
1193 parameterName, parameterValue = Decoder.decodeParameter(byteIter)
1194 return parameterName, parameterValue
1195
1196 @staticmethod
1198 """ From [5], section 8.4.2.8:
1199 C{Well-known-charset = Any-charset | Integer-value}
1200 It is encoded using values from "Character Set Assignments" table.
1201 C{Any-charset = <Octet 128>}
1202 Equivalent to the special RFC2616 charset value "*"
1203 """
1204 decodedCharSet = ''
1205
1206 byte = byteIter.preview()
1207 byteIter.resetPreview()
1208 if byte == 127:
1209 byteIter.next()
1210 decodcedCharSet = '*'
1211 else:
1212 charSetValue = Decoder.decodeIntegerValue(byteIter)
1213 if charSetValue in WSPEncodingAssignments.wkCharSets:
1214 decodedCharSet = WSPEncodingAssignments.wkCharSets[charSetValue]
1215 else:
1216
1217 decodedCharSet = str(charSetValue)
1218 return decodedCharSet
1219
1220 @staticmethod
1222 """ From [5], section 8.4.2.6:
1223 C{Well-known-header = Well-known-field-name Wap-value}
1224 C{Well-known-field-name = Short-integer}
1225 C{Wap-value = <many different headers value, most not implemented>}
1226
1227 @todo: Currently, "Wap-value" is decoded as a Text-string in most cases
1228
1229 @return: The header name, and its value, in the format:
1230 (<str:header_name>, <str:header_value>)
1231 @rtype: tuple
1232 """
1233 decodedHeaderFieldName = ''
1234 hdrFieldValue = Decoder.decodeShortInteger(byteIter)
1235 hdrFields = WSPEncodingAssignments.headerFieldNames()
1236
1237 if hdrFieldValue in range(len(hdrFields)):
1238 decodedHeaderFieldName = hdrFields[hdrFieldValue]
1239 else:
1240 raise DecodeError, 'Invalid Header Field value: %d' % hdrFieldValue
1241
1242
1243 if decodedHeaderFieldName in WSPEncodingAssignments.hdrFieldEncodings:
1244 wapValueType = WSPEncodingAssignments.hdrFieldEncodings[decodedHeaderFieldName]
1245 try:
1246 exec 'decodedValue = Decoder.decode%s(byteIter)' % wapValueType
1247 except DecodeError, msg:
1248 raise DecodeError, 'Could not decode Wap-value: %s' % msg
1249 except:
1250 print 'An error occurred, probably due to an unimplemented decoding operation. Tried to decode header: %s' % decodedHeaderFieldName
1251 raise
1252 else:
1253 decodedValue = Decoder.decodeTextString(byteIter)
1254 return (decodedHeaderFieldName, decodedValue)
1255
1256 @staticmethod
1258 """ From [5], section 8.4.2.6:
1259 C{Application-header = Token-text Application-specific-value}
1260
1261 From [4], section 7.1:
1262 C{Application-header = Token-text Application-specific-value}
1263 C{Application-specific-value = Text-string}
1264
1265 @note: This is used when decoding generic WSP headers;
1266 see C{decodeHeader()}.
1267 @note: We follow [4], and decode the "Application-specific-value"
1268 as a Text-string
1269
1270 @return: The application-header, and its value, in the format:
1271 (<str:application_header>, <str:application_specific_value>)
1272 @rtype: tuple
1273 """
1274 try:
1275 appHeader = Decoder.decodeTokenText(byteIter)
1276
1277 except DecodeError:
1278 appHeader = Decoder.decodeTextString(byteIter)
1279 appSpecificValue = Decoder.decodeTextString(byteIter)
1280 return (appHeader, appSpecificValue)
1281
1282 @staticmethod
1284 """ Decodes a WSP header entry
1285
1286 From [5], section 8.4.2.6:
1287 C{Header = Message-header | Shift-sequence}
1288 C{Message-header = Well-known-header | Application-header}
1289 C{Well-known-header = Well-known-field-name Wap-value}
1290 C{Application-header = Token-text Application-specific-value}
1291
1292 @note: "Shift-sequence" encoding has not been implemented
1293 @note: Currently, almost all header values are treated as text-strings
1294
1295 @return: The decoded headername, and its value, in the format:
1296 (<str:header_name>, <str:header_value>)
1297 @rtype: tuple
1298 """
1299 header = ''
1300 value = ''
1301
1302 try:
1303 header, value = Decoder.decodeWellKnownHeader(byteIter)
1304 except DecodeError:
1305
1306 header, value = Decoder.decodeApplicationHeader(byteIter)
1307 return (header, value)
1308
1309
1311 """ A WSP Data unit decoder """
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327 @staticmethod
1329 """ Variable Length Unsigned Integer encoding algorithm
1330
1331 This binary-encodes the given unsigned integer number as specified
1332 in section 8.1.2 of [5]. Basically, each encoded byte has the
1333 following structure::
1334
1335 [0][ Payload ]
1336 | ^^^^^^^
1337 | 7 bits (actual data)
1338 |
1339 Continue bit
1340
1341 The uint is split into 7-bit segments, and the "continue bit" of each
1342 used octet is set to '1' to indicate more is to follow; the last used
1343 octet's "continue bit" is set to 0.
1344
1345 @return: the binary-encoded Uintvar, as a list of byte values
1346 @rtype: list
1347 """
1348 uintVar = []
1349
1350 uintVar.append(uint & 0x7f)
1351 uint = uint >> 7
1352
1353 while uint > 0:
1354 uintVar.insert(0, 0x80 | (uint & 0x7f))
1355 uint = uint >> 7
1356 return uintVar
1357
1358 @staticmethod
1359 - def encodeTextString(string):
1360 """ Encodes a "Text-string" value.
1361
1362 This follows the basic encoding rules specified in [5], section
1363 8.4.2.1
1364
1365 @param string: The text string to encode
1366 @type string: str
1367
1368 @return: the null-terminated, binary-encoded version of the
1369 specified Text-string, as a list of byte values
1370 @rtype: list
1371 """
1372 encodedString = []
1373 for char in string:
1374 encodedString.append(ord(char))
1375 encodedString.append(0x00)
1376 return encodedString
1377
1378 @staticmethod
1380 """ Encodes the specified short-integer value
1381
1382 The encoding for a long integer is specified in [5], section 8.4.2.1:
1383 C{Short-integer = OCTET}
1384 Integers in range 0-127 shall be encoded as a one octet value with
1385 the most significant bit set to one (1xxx xxxx) and with the value
1386 in the remaining least significant bits.
1387
1388 @param integer: The short-integer value to encode
1389 @type integer: int
1390
1391 @raise EncodeError: Not a valid short-integer; the integer must be in
1392 the range of 0-127
1393
1394 @return: The encoded short integer, as a list of byte values
1395 @rtype: list
1396 """
1397 if integer < 0 or integer > 127:
1398 raise EncodeError, 'Short-integer value must be in range 0-127: %d' % integer
1399 encodedInteger = []
1400
1401 byte = 0x80 | integer
1402 encodedInteger.append(byte)
1403 return encodedInteger
1404
1405 @staticmethod
1407 """ Encodes a Long-integer value
1408
1409 The encoding for a long integer is specified in [5], section 8.4.2.1;
1410 for a description of this encoding scheme, see
1411 C{wsp.Decoder.decodeLongIntger()}.
1412
1413 Basically:
1414 From [5], section 8.4.2.2:
1415 Long-integer = Short-length Multi-octet-integer
1416 Short-length = <Any octet 0-30>
1417
1418 @raise EncodeError: <integer> is not of type "int"
1419
1420 @param integer: The integer value to encode
1421 @type integer: int
1422
1423 @return: The encoded Long-integer, as a sequence of byte values
1424 @rtype: list
1425 """
1426 if type(integer) != int:
1427 raise EncodeError, '<integer> must be of type "int"'
1428 encodedLongInt = []
1429 longInt = integer
1430
1431 while longInt > 0:
1432 byte = 0xff & longInt
1433 encodedLongInt.append(byte)
1434 longInt = longInt >> 8
1435
1436 shortLength = len(encodedLongInt)
1437 if shortLength > 30:
1438 raise EncodeError, 'Cannot encode Long-integer value: Short-length is too long; should be in octet range 0-30'
1439 encodedLongInt.insert(0, shortLength)
1440 return encodedLongInt
1441
1442 @staticmethod
1444 """ Encodes the version-value. From [5], section 8.4.2.3:
1445 Version-value = Short-integer | Text-string
1446
1447 Example: An MMS version of "1.0" consists of a major version of 1 and a
1448 minor version of 0, and would be encoded as 0x90. However, a version
1449 of "1.2.4" would be encoded as the Text-string "1.2.4".
1450
1451 @param version: The version number to encode, e.g. "1.0"
1452 @type version: str
1453
1454 @raise TypeError: The specified version value was not of type C{str}
1455
1456 @return: the encoded version value, as a list of byte values
1457 @rtype: list
1458 """
1459 if type(version) != str:
1460 raise TypeError, 'Parameter must be of type "str"'
1461 encodedVersionValue = []
1462
1463 try:
1464 if len(version.split('.')) <= 2:
1465 majorVersion = int(version.split('.')[0])
1466 if majorVersion < 1 or majorVersion > 7:
1467 raise ValueError, 'Major version must be in range 1-7'
1468 major = majorVersion << 4
1469 if len(version.split('.')) == 2:
1470 minorVersion = int(version.split('.')[1])
1471 if minorVersion < 0 or minorVersion > 14:
1472 raise ValueError, 'Minor version must be in range 0-14'
1473 else:
1474 minorVersion = 15
1475 minor = minorVersion
1476 encodedVersionValue = Encoder.encodeShortInteger(major|minor)
1477 except:
1478
1479 encodedVersionValue = Encoder.encodeTextString(version)
1480 return encodedVersionValue
1481
1482 @staticmethod
1506
1507 @staticmethod
1508 - def encodeParameter(parameterName, parameterValue, encodingVersion='1.2'):
1509 """ Binary-encodes the name of a parameter of (for example) a
1510 "Content-Type" header entry, taking into account the WSP short form of
1511 well-known parameter names, as specified in section 8.4.2.4 and table
1512 38 of [5].
1513
1514 From [5], section 8.4.2.4:
1515 C{Parameter = Typed-parameter | Untyped-parameter}
1516 C{Typed-parameter = Well-known-parameter-token Typed-value}
1517 C{Untyped-parameter = Token-text Untyped-value}
1518 C{Untyped-value = Integer-value | Text-value}
1519
1520 @param parameterName: The name of the parameter to encode
1521 @type parameterName: str
1522 @param parameterValue: The value of the parameter
1523 @type parameterValue: str or int
1524
1525 @param encodingVersion: The WSP encoding version to use. This defaults
1526 to "1.2", but may be "1.1", "1.2", "1.3" or
1527 "1.4" (see table 38 in [5] for details).
1528 @type encodingVersion: str
1529
1530 @raise ValueError: The specified encoding version is invalid.
1531
1532 @return: The binary-encoded parameter name, as a list of (integer)
1533 byte values
1534 @rtype: list
1535 """
1536 wkParameters = WSPEncodingAssignments.wellKnownParameters(encodingVersion)
1537 encodedParameter = []
1538
1539 wkParamNumbers = wkParameters.keys().sort(reverse=True)
1540 for assignedNumber in wkParamNumbers:
1541 if wkParameters[assignedNumber][0] == parameterName:
1542
1543 encodedParameter.extend(Encoder.encodeShortInteger(assignedNumber))
1544
1545 expectedType = wkParameters[assignedNumber][1]
1546 try:
1547 exec 'encodedParameter.extend(Encoder.encode%s(parameterValue))' % expectedType
1548 except EncodeError, msg:
1549 raise EncodeError, 'Error encoding parameter value: %s' % msg
1550 except:
1551 print 'A fatal error occurred, probably due to an unimplemented encoding operation'
1552 raise
1553 break
1554
1555 if len(encodedParameter) == 0:
1556
1557 encodedParameter.extend(Encoder.encodeTokenText(parameterName))
1558 value = []
1559
1560 try:
1561 value = Encoder.encodeIntegerValue(parameterValue)
1562 except EncodeError:
1563 value = Encoder.encodeTextString(parameterValue)
1564 encodedParameter.extend(value)
1565 return encodedParameter
1566
1567
1568 @staticmethod
1569 - def encodeTokenText(text):
1570 """ From [5], section 8.4.2.1:
1571 Token-text = Token End-of-string
1572
1573 @raise EncodeError: Specified text cannot be encoding as a token
1574
1575 @return: The encoded token string, as a list of byte values
1576 @rtype: list
1577 """
1578 separators = (11, 32, 40, 41, 44, 47, 58, 59, 60, 61, 62, 63, 64, 91,
1579 92, 93, 123, 125)
1580
1581 for char in separators:
1582 if chr(char) in text:
1583 raise EncodeError, 'Char "%s" in text string; cannot encode as Token-text' % chr(char)
1584 encodedToken = Encoder.encodeTextString(text)
1585 return encodedToken
1586
1587 @staticmethod
1589 """ Encodes an integer value
1590
1591 From [5], section 8.4.2.3:
1592 Integer-Value = Short-integer | Long-integer
1593
1594 This function will first try to encode the specified integer value
1595 into a short-integer, and failing that, will encode into a
1596 long-integer value.
1597
1598 @param integer: The integer to encode
1599 @type integer: int
1600
1601 @raise EncodeError: The <integer> parameter is not of type C{int}
1602
1603 @return: The encoded integer value, as a list of byte values
1604 @rtype: list
1605 """
1606 if type(integer) != int:
1607 raise EncodeError, '<integer> must be of type "int"'
1608 encodedInteger = []
1609
1610 try:
1611 encodedInteger = Encoder.encodeShortInteger(integer)
1612 except EncodeError:
1613 encodedInteger = Encoder.encodeLongInteger(integer)
1614 return encodedInteger
1615
1616 @staticmethod
1617 - def encodeTextValue(text):
1618 """ Stub for encoding Text-values; this is equivalent to
1619 C{encodeTextString} """
1620 return Encoder.encodeTextString(text)
1621
1622 @staticmethod
1624 """ Encodes a No-value, which is 0x00
1625
1626 @note: This function mainly exists for use by automatically-selected
1627 encoding routines (see C{encodeParameter()} for an example.
1628
1629 @param value: This value is ignored; it is present so that this
1630 method complies with the format of the other C{encode}
1631 methods.
1632
1633 @return: A list containing a single "No-value", which is 0x00
1634 @rtype: list
1635 """
1636 return [0x00]
1637
1638 @staticmethod
1640 """ Encodes a WSP header entry, and its value
1641
1642 From [5], section 8.4.2.6:
1643 C{Header = Message-header | Shift-sequence}
1644 C{Message-header = Well-known-header | Application-header}
1645 C{Well-known-header = Well-known-field-name Wap-value}
1646 C{Application-header = Token-text Application-specific-value}
1647
1648 @note: "Shift-sequence" encoding has not been implemented
1649 @note: Currently, almost all header values are encoded as text-strings
1650
1651 @return: The encoded header, and its value, as a sequence of byte
1652 values
1653 @rtype: list
1654 """
1655 encodedHeader = []
1656
1657 wkHdrFields = WSPEncodingAssignments.headerFieldNames()
1658 if headerFieldName in wkHdrFields:
1659 headerFieldValue = Encoder.encodeShortInteger(wkHdrFields.index(headerFieldName))
1660 encodedHeader.extend(headerFieldValue)
1661 else:
1662
1663 encodedHeaderName = Encoder.encodeTokenText(headerFieldName)
1664 encodedHeader.extend(encodedHeaderName)
1665
1666
1667
1668 if headerFieldName in WSPEncodingAssignments.hdrFieldEncodings:
1669 wapValueType = WSPEncodingAssignments.hdrFieldEncodings[headerFieldName]
1670 try:
1671 exec 'encodedHeader.extend(Encoder.encode%s(headerValue))' % wapValueType
1672 except EncodeError, msg:
1673 raise EncodeError, 'Error encoding Wap-value: %s' % msg
1674 except:
1675 print 'A fatal error occurred, probably due to an unimplemented encoding operation'
1676 raise
1677 else:
1678 encodedHeader.extend(Encoder.encodeTextString(headerValue))
1679 return encodedHeader
1680
1681 @staticmethod
1682 - def encodeContentTypeValue(mediaType, parameters):
1683 """ Encodes a content type, and its parameters
1684
1685 From [5], section 8.4.2.24:
1686 C{Content-type-value = Constrained-media | Content-general-form}
1687
1688 The short form of the Content-type-value MUST only be used when the
1689 well-known media is in the range of 0-127 or a text string. In all
1690 other cases the general form MUST be used.
1691
1692 @return: The encoded Content-type-value (including parameters, if
1693 any), as a sequence of bytes
1694 @rtype: list
1695 """
1696 encodedContentTypeValue = []
1697
1698 try:
1699 if len(parameters) > 0:
1700 raise EncodeError, 'Need to use Content-general-form for parameters'
1701 else:
1702 encodedContentTypeValue = Encoder.encodeConstrainedMedia(mediaType)
1703 except EncodeError:
1704
1705 encodedContentTypeValue = Encoder.encodeContentGeneralForm(mediaType, parameters)
1706 return encodedContentTypeValue
1707
1708 @staticmethod
1731
1732 @staticmethod
1734 """ Constrained-encoding = Extension-Media --or-- Short-integer
1735 This encoding is used for token values, which have no well-known
1736 binary encoding, or when the assigned number of the well-known
1737 encoding is small enough to fit into Short-integer.
1738
1739 @param value: The value to encode
1740 @type value: int or str
1741
1742 @raise EncodeError: <value> cannot be encoded as a
1743 Constrained-encoding sequence
1744
1745 @return: The encoded constrained-encoding token value, as a sequence
1746 of bytes
1747 @rtype: list
1748 """
1749 encodedValue = None
1750 if type(value) == int:
1751
1752 encodedValue = Encoder.encodeShortInteger(value)
1753 else:
1754
1755 try:
1756 encodedValue = Encoder.encodeExtensionMedia(value)
1757 except EncodeError:
1758
1759 raise EncodeError, 'Cannot encode %s as a Constrained-encoding sequence' % str(value)
1760 return encodedValue
1761
1762 @staticmethod
1789
1790 @staticmethod
1792 """ From [5], section 8.4.2.24:
1793 Content-general-form = Value-length Media-type
1794
1795 @note: Used in decoding Content-type fields and their parameters;
1796 see C{decodeContentTypeValue}
1797
1798 @note: Used by C{decodeContentTypeValue()}
1799
1800 @return: The encoded Content-general-form, as a sequence of bytes
1801 @rtype: list
1802 """
1803 encodedContentGeneralForm = []
1804 encodedMediaType = []
1805 encodedParameters = []
1806
1807 encodedMediaType = Encoder.encodeMediaType(mediaType)
1808
1809 for paramName in parameters:
1810 encodedParameters.extend(Encoder.encodeParameter(paramName, parameters[paramName]))
1811 valueLength = len(encodedMediaType) + len(encodedParameters)
1812 encodedValueLength = Encoder.encodeValueLength(valueLength)
1813 encodedContentGeneralForm.extend(encodedValueLength)
1814 encodedContentGeneralForm.extend(encodedMediaType)
1815 encodedContentGeneralForm.extend(encodedParameters)
1816 return encodedContentGeneralForm
1817
1818 @staticmethod
1820 """ Encodes the specified length value as a value length indicator
1821
1822 "Value length" is used to indicate the length of a value to follow, as
1823 used in the C{Content-Type} header in the MMS body, for example.
1824
1825 The encoding for a value length indicator is specified in [5],
1826 section 8.4.2.2, and follows the form::
1827
1828 Value-length = [Short-length] --or-- [Length-quote] [Length]
1829 ^^^^^^ ^^^^^^ ^^^^^^
1830 1 byte 1 byte x bytes
1831 <Any octet 0-30> <Octet 31> Uintvar-integer
1832
1833 @raise EncodeError: The ValueLength could not be encoded.
1834
1835 @return: The encoded value length indicator, as a sequence of bytes
1836 @rtype: list
1837 """
1838 encodedValueLength = []
1839
1840 try:
1841 encodedValueLength = Encoder.encodeShortLength(length)
1842 except EncodeError:
1843
1844 encodedValueLength.append(31)
1845 encodedValueLength.extend(Encoder.encodeUintvar(length))
1846 return encodedValueLength
1847
1848 @staticmethod
1850 """ From [5], section 8.4.2.2:
1851 Short-length = <Any octet 0-30>
1852
1853 @raise EmcodeError: The specified <length> cannot be encoded as a
1854 short-length value; it is not in octet range 0-30.
1855
1856 @return: The encoded short-length, as a sequence of bytes
1857 @rtype: list
1858 """
1859 if length < 0 or length > 30:
1860 raise EncodeError, 'Cannot encode short-length; length should be in range 0-30'
1861 else:
1862 return [length]
1863
1864 @staticmethod
1866 """ From [5], section 8.4.2.7:
1867 Accept-value = Constrained-media | Accept-general-form
1868 Accept-general-form = Value-length Media-range [Accept-parameters]
1869 Media-range = (Well-known-media | Extension-Media) *(Parameter)
1870 Accept-parameters = Q-token Q-value *(Accept-extension)
1871 Accept-extension = Parameter
1872 Q-token = <Octet 128>
1873
1874 @note: This implementation does not currently support encoding of
1875 "Accept-parameters".
1876
1877 @param acceptValue: The Accept-value to encode (media/content type)
1878 @type acceptValue: str
1879
1880 @raise EncodeError: The encoding failed.
1881
1882 @return: The encoded Accept-value, as a sequence of bytes
1883 @rtype: list
1884 """
1885 encodedAcceptValue = []
1886
1887 try:
1888 encodedAcceptValue = Encoder.encodeConstrainedMedia(acceptValue)
1889 except EncodeError:
1890
1891 try:
1892 encodedMediaRange = Encoder.encodeMediaType(acceptValue)
1893 except EncodeError, msg:
1894 raise EncodeError, 'Cannot encode Accept-value: %s' % msg
1895 valueLength = Encoder.encodeValueLength(len(encodedMediaRange))
1896 encodedAcceptValue = valueLength
1897 encodedAcceptValue.extend(encodedMediaRange)
1898 return encodedAcceptValue
1899