1
2
3
4
5
6
7
8
9
10 """The various types used in protocol descriptions
11
12 To implement a type used for protocol descriptions,
13 examine the code for UINTlsb in this file. Of note:
14
15 - Inherit from BaseProtogenClass
16 - Call superclass constructors using super()
17 - Do not process any of the args or kwargs in the constructor unless
18 you need them to alter how you are constructed
19 - At the end of the constructor, call _update if you are the most
20 derived class
21 - In _update, call super()._update, and then delete keyword arguments
22 as you process them (consider using L{BaseProtogenClass._consumekw} function)
23 - If you are the most derived class, complain about
24 unused keyword arguments (consider using
25 L{BaseProtogenClass._complainaboutunusedargs} function)
26 - set _bufferstartoffset and _bufferendoffset whenever
27 you are read or written from a buffer
28 - (optionally) define a getvalue() method that returns
29 a better type. For example if your class is integer
30 like then this would return a real int. If string like,
31 then this will return a real string.
32 - If you are a container, override iscontainer. You will
33 also need to provide a containerelements() method which
34 lets you iterate over the entries.
35
36 containerelements method:
37
38 - You should return tuples of (fieldname, fieldvalue, descriptionstring or None)
39 - fieldvalue should be the actual object, not a pretty version (eg a USTRING not str)
40
41
42 """
43 import sys
44 import calendar
45 import cStringIO
46 import re
47 import time
48
49 import common
50
52 """Base class for exceptions encountered with data marshalling"""
55
57 "Unable to marshal since size isn't known"
60
65
67 "Some sort of problem with the value"
70
72 "The value should have been terminated and wasn't"
75
77 "The value is the wrong size (too big or too small)"
80
82 "The value does not have quotes around it"
85
86
88 """All types are derived from this"""
91
100
102 "Scribble ourselves to the buf"
103 raise NotImplementedError("writetobuffer()")
105 "Get our value from the buffer"
106 raise NotImplementedError("readfrombuffer()")
108 "Returns our underlying value if sensible (eg an integer, string or list) else returns self"
109 return self
111 """Returns tuple of begining,end offsets from last packet we were read or written from.
112
113 Note that in normal Python style, end is one beyond the last byte we
114 actually own"""
115 return self._bufferstartoffset, self._bufferendoffset
117 """A helper function for easily setting internal values from the dict
118
119 For each name in consumelist, we look for it in the dict and
120 set self._name to the value from dict. The key is then deleted
121 from the dict."""
122 for name in consumelist:
123 if dict.has_key(name):
124 setattr(self, "_"+name, dict[name])
125 del dict[name]
127 """A helper function that will raise an exception if there are unused keyword arguments.
128
129 @Note: that we only complain if in the most derived class, so it is safe
130 to always call this helper as the last line of your constructor.
131
132 @param klass: This should be the class you are calling this function from
133 @param dict: The keyword arguments still in play
134 """
135 if len(dict) and self.__class__.__mro__[0]==klass:
136 raise TypeError('Unexpected keyword args supplied: '+`dict`)
137
139
140 return self.__class__.__mro__[0]==klass
141
144
146 """Do we contain fields?"""
147 return False
148
149 - def update(self, *args, **kwargs):
151
152
154 f=sys._getframe()
155 f=f.f_back
156 if f:
157 f=f.f_back
158 if f:
159 caller=f.f_locals.get("self", None)
160 if caller:
161 try:
162 caller.logdata(logtitle, buf.getvalue(), self)
163 except:
164 pass
165
167 f=sys._getframe()
168 f=f.f_back
169 if f:
170 f=f.f_back
171 if f:
172 caller=f.f_locals.get("self", None)
173 if caller:
174 try:
175 caller.logdata(logtitle, buf.getdata(), self)
176 except:
177 pass
178
180 "An integer in Least Significant Byte first order"
182 """
183 An integer value can be specified in the constructor, or as the value keyword arg.
184
185 @keyword constant: (Optional) A constant value. All reads must have this value
186 @keyword constantexception: (Optional) Type of exception raised when data doesn't match constant.
187 @keyword sizeinbytes: (Mandatory for writing, else Optional) How big we are in bytes
188 @keyword default: (Optional) Our default value
189 @keyword value: (Optional) The value
190 """
191 super(UINTlsb, self).__init__(*args, **kwargs)
192 self._constant=None
193 self._constantexception=ValueError
194 self._sizeinbytes=None
195 self._value=None
196 self._default=None
197
198 if self._ismostderived(UINTlsb):
199 self._update(args,kwargs)
200
201
203 super(UINTlsb,self)._update(args, kwargs)
204
205 self._consumekw(kwargs, ("constant", "constantexception", "sizeinbytes", "default", "value"))
206 self._complainaboutunusedargs(UINTlsb,kwargs)
207
208
209 if len(args)==0:
210 pass
211 elif len(args)==1:
212 self._value=int(args[0])
213 else:
214 raise TypeError("Unexpected arguments "+`args`)
215
216 if self._value is None and self._default is not None:
217 self._value=self._default
218
219 if self._value is None and self._constant is not None:
220 self._value=self._constant
221
222 if self._constant is not None and self._constant!=self._value:
223 raise self._constantexception("This field is a constant of %d. You tried setting it to %d" % (self._constant, self._value))
224
225
227 if self._sizeinbytes is None:
228 raise SizeNotKnownException()
229 self._bufferstartoffset=buf.getcurrentoffset()
230
231 res=0
232 shift=0
233 for dummy in range(self._sizeinbytes):
234 res|=buf.getnextbyte()<<shift
235 shift+=8
236 self._value=res
237 self._bufferendoffset=buf.getcurrentoffset()
238 if self._constant is not None and self._value!=self._constant:
239 raise self._constantexception("The value read should be a constant of %d, but was %d instead" % (self._constant, self._value))
240
254
259
261 """Returns the integer we are"""
262 if self._value is None:
263 raise ValueNotSetException()
264 return self._value
265
267 "An Boolean in Least Significant Byte first order"
269 """
270 A boolean value can be specified in the constructor.
271
272 Keyword arguments are the same a UINTlsb
273 """
274 super(BOOLlsb, self).__init__(*args, **kwargs)
275
276 if self._ismostderived(BOOLlsb):
277 self._update(args,kwargs)
278
283
285 if self._value is not None:
286 self._value=bool(self._value)
287
291
292 -class STRING(BaseProtogenClass):
293 "A text string DEPRECATED USE USTRING "
295 """
296 A string value can be specified to this constructor, or in the value keyword arg.
297
298 @keyword constant: (Optional) A constant value. All reads must have this value
299 @keyword terminator: (Default=0) The string terminator (or None). If set there will
300 always be a terminator when writing. The terminator is not returned when getting
301 the value.
302 @keyword pad: (Default=0) The padding byte if fixed length when writing, or stripped off
303 when reading
304 @keyword sizeinbytes: (Optional) Set if fixed length.
305 If not set, then the terminator will be used to find the end of strings on reading.
306 If not set and the terminator is None, then reads will be entire rest of buffer.
307 @keyword maxsizeinbytes: (Optional) Max string length. Used together
308 with terminator to limit the max length of the value.
309 TODO: Need to add this to USTRING also.
310 @keyword default: (Optional) Our default value
311 @keyword raiseonunterminatedread: (Default True) raise L{NotTerminatedException} if there is
312 no terminator on the value being read in. terminator must also be set.
313 @keyword raiseontruncate: (Default True) raise L{ValueLengthException} if the supplied
314 value is too large to fit within sizeinbytes.
315 @keyword value: (Optional) Value
316 @keyword pascal: (Default False) The string is preceded with one byte giving the length
317 of the string (including terminator if there is one)
318 """
319 super(STRING, self).__init__(*args, **kwargs)
320
321 self._constant=None
322 self._terminator=0
323 self._pad=0
324 self._sizeinbytes=None
325 self._default=None
326 self._raiseonunterminatedread=True
327 self._raiseontruncate=True
328 self._value=None
329 self._pascal=False
330 self._maxsizeinbytes=None
331
332 if self._ismostderived(STRING):
333 self._update(args,kwargs)
334
336 super(STRING,self)._update(args, kwargs)
337
338 self._consumekw(kwargs, ("constant", "terminator", "pad", "pascal",
339 "sizeinbytes", "default", "raiseonunterminatedread", "value",
340 "raiseontruncate", "maxsizeinbytes"))
341 self._complainaboutunusedargs(STRING,kwargs)
342
343
344 if len(args)==0:
345 pass
346 elif len(args)==1:
347 self._value=common.forceascii(args[0])
348 if self._constant is not None and self._constant!=self._value:
349 raise ValueException("This field is a constant of '%s'. You tried setting it to '%s'" % (self._constant, self._value))
350 else:
351 raise TypeError("Unexpected arguments "+`args`)
352 if self._value is None and self._default is not None:
353 self._value=self._default
354
355 if self._value is not None:
356 self._value=str(self._value)
357 l=len(self._value)
358 if self._sizeinbytes is not None:
359 if self._terminator is not None:
360 l+=1
361 if l>self._sizeinbytes:
362 if self._raiseontruncate:
363 raise ValueLengthException(l, self._sizeinbytes)
364
365 self._value=self._value[:self._sizeinbytes]
366 if len(self._value) and self._terminator is not None:
367 self._value=self._value[:-1]
368 elif self._maxsizeinbytes is not None:
369 if l>self._maxsizeinbytes:
370 if self._raiseontruncate:
371 raise ValueLengthException(l, self._maxsizeinbytes)
372 self._value=self._value[:self._maxsizeinbytes]
373
375 self._bufferstartoffset=buf.getcurrentoffset()
376
377 flush=0
378 if self._pascal:
379 if self._sizeinbytes is None:
380 self._sizeinbytes=buf.getnextbyte()
381
382 else:
383 temp=self._sizeinbytes-1
384 self._sizeinbytes=buf.getnextbyte()
385 flush=temp-self._sizeinbytes
386 if(temp < 0):
387 raise ValueLengthException()
388
389 if self._sizeinbytes is not None:
390
391 self._value=buf.getnextbytes(self._sizeinbytes)
392 if self._terminator is not None:
393
394 pos=self._value.find(chr(self._terminator))
395 if pos>=0:
396 self._value=self._value[:pos]
397 elif self._raiseonunterminatedread:
398 raise NotTerminatedException()
399 elif self._pad is not None:
400
401 while len(self._value) and self._value[-1]==chr(self._pad):
402 self._value=self._value[:-1]
403 else:
404 if self._terminator is None:
405
406 self._value=buf.getremainingbytes()
407 else:
408
409 self._value=""
410 while buf.hasmore():
411 self._value+=chr(buf.getnextbyte())
412 if self._value[-1]==chr(self._terminator):
413 break
414 if self._value[-1]!=chr(self._terminator):
415 if self._raiseonunterminatedread:
416 raise NotTerminatedException()
417 else:
418 self._value=self._value[:-1]
419
420 if self._maxsizeinbytes is not None:
421 self._value=self._value[:self._maxsizeinbytes]
422
423 if self._constant is not None and self._value!=self._constant:
424 raise ValueException("The value read was not the constant")
425
426
427 if(flush):
428 buf.getnextbytes(flush)
429
430 self._bufferendoffset=buf.getcurrentoffset()
431
433 if self._value is None:
434 raise ValueNotSetException()
435
436 self._bufferstartoffset=buf.getcurrentoffset()
437
438 l=len(self._value)
439 if self._terminator is not None:
440 l+=1
441 if self._pascal:
442 buf.appendbyte(l)
443 l+=1
444 buf.appendbytes(self._value)
445 if self._terminator is not None:
446 buf.appendbyte(self._terminator)
447 if self._sizeinbytes is not None:
448 if l<self._sizeinbytes:
449 buf.appendbytes(chr(self._pad)*(self._sizeinbytes-l))
450
451 self._bufferendoffset=buf.getcurrentoffset()
452
454 if self._sizeinbytes is not None:
455 return self._sizeinbytes
456
457 if self._value is None:
458 raise ValueNotSetException()
459
460 l=len(self._value)
461 if self._terminator is not None:
462 l+=1
463 if self._pascal:
464 l+=1
465 return l
466
468 """Returns the string we are"""
469 if self._value is None:
470 raise ValueNotSetException()
471 return self._value
472
473
475 "A text string that supports configurable encodings"
477 """
478 A string value can be specified to this constructor, or in the value keyword arg.
479
480 @keyword constant: (Optional) A constant value. All reads must have this value
481 @keyword terminator: (Default=0) The string terminator (or None). If set there will
482 always be a terminator when writing. The terminator is not returned when getting
483 the value.
484 @keyword terminator_length: (Default=1) (min:1, max:4)The length of the string terminator.
485 This keyword is not used if the terminator is None. Multi-byte terminators are treated
486 as LSB when read from the phone.
487 @keyword pad: (Default=0) The padding byte if fixed length when writing, or stripped off
488 when reading
489 @keyword sizeinbytes: (Optional) Set if fixed length.
490 If not set, then the terminator will be used to find the end of strings on reading.
491 If not set and the terminator is None, then reads will be entire rest of buffer.
492 @keyword maxsizeinbytes: (Optional) Max string length. Used together
493 with terminator to limit the max length of the value.
494 @keyword default: (Optional) Our default value
495 @keyword raiseonunterminatedread: (Default True) raise L{NotTerminatedException} if there is
496 no terminator on the value being read in. Terminator must also be set.
497 @keyword raiseontruncate: (Default True) raise L{ValueLengthException} if the supplied
498 value is too large to fit within sizeinbytes.
499 @keyword value: (Optional) Value
500 @keyword pascal: (Default False) The string is preceded with one byte giving the length
501 of the string (including terminator if there is one)
502 @keyword encoding: (Default 'ascii') The charset to use when reading/writing to a buffer
503 @keyword read_encoding: (Default keyword:encoding) The charset to use when reading from a buffer
504 @keyword write_encoding: (Default keyword:encoding) The charset to use when writing to a buffer
505 """
506 super(USTRING, self).__init__(*args, **kwargs)
507
508 self._constant=None
509 self._terminator=0
510 self._pad=0
511 self._sizeinbytes=None
512 self._default=None
513 self._raiseonunterminatedread=True
514 self._raiseontruncate=True
515 self._value=None
516 self._pascal=False
517 self._maxsizeinbytes=None
518 self._encoding='ascii'
519 self._read_encoding=None
520 self._write_encoding=None
521 self._terminator_length=1
522
523 if self._ismostderived(USTRING):
524 self._update(args,kwargs)
525
527 super(USTRING,self)._update(args, kwargs)
528
529 self._consumekw(kwargs, ("constant", "terminator", "pad", "pascal",
530 "sizeinbytes", "default", "raiseonunterminatedread", "value", "raiseontruncate",
531 "encoding", "read_encoding", "write_encoding", "maxsizeinbytes"))
532 self._complainaboutunusedargs(USTRING,kwargs)
533 if self._read_encoding==None:
534 self._read_encoding=self._encoding
535 if self._write_encoding==None:
536 self._write_encoding=self._encoding
537 if self._terminator_length < 1 or self._terminator_length > 4:
538 raise ValueException("Terminator length outside allowed range of 1-4. You tried setting it to %d" % self._terminator_length)
539
540
541 if self._terminator == 0:
542 if self._encoding.startswith("utf_16"):
543 self._terminator_length = 2
544 elif self._encoding.startswith("utf_32"):
545 self._terminator_length = 4
546
547
548 if len(args)==0:
549 pass
550 elif len(args)==1:
551 self._value=args[0]
552 else:
553 raise TypeError("Unexpected arguments "+`args`)
554 if self._value is None and self._default is not None:
555 self._value=self._default
556
557 if self._value is not None:
558
559
560 if not isinstance(self._value, (str, unicode)):
561
562 temp=str(self._value)
563 self._value=unicode(temp, 'ascii', 'replace')
564
565 elif not isinstance(self._value, unicode):
566
567 self._value=unicode(self._value, 'ascii', 'replace')
568
569 if self._constant is not None and self._constant!=self._value:
570 raise ValueException("This field is a constant of '%s'. You tried setting it to '%s'" % (self._constant, self._value))
571
572 try:
573 test=self.convert_for_write()
574 except UnicodeEncodeError:
575 raise common.PhoneStringEncodeException(self._value, uni_string_codec)
576
577 if self._value is not None:
578 max_size=None
579 if self._sizeinbytes is not None:
580 max_size=self._sizeinbytes
581 elif self._maxsizeinbytes is not None:
582 max_size=self._maxsizeinbytes
583 if max_size is not None:
584 l=len(test)
585 if self._terminator is not None:
586 l+=self._terminator_length
587 if l>max_size:
588 if self._raiseontruncate:
589 raise ValueLengthException(l, self._sizeinbytes)
590
591
592 self._value=self._value[:max_size]
593 term_len=0
594 if self._terminator!=None:
595 term_len=self._terminator_length
596
597 while (len(self.convert_for_write())+term_len)>max_size:
598 self._value=self._value[:-1]
599
601 self._bufferstartoffset=buf.getcurrentoffset()
602
603 flush=0
604 _value=''
605 if self._pascal:
606 if self._sizeinbytes is None:
607 self._sizeinbytes=buf.getnextbyte()
608
609 else:
610 temp=self._sizeinbytes-1
611 self._sizeinbytes=buf.getnextbyte()
612 flush=temp-self._sizeinbytes
613 if(temp < 0):
614 raise ValueLengthException()
615
616 if self._sizeinbytes is not None:
617
618 _value=buf.getnextbytes(self._sizeinbytes)
619 if self._terminator is not None:
620
621 pos=-1
622 for i in range(0, self._sizeinbytes, self._terminator_length):
623 term=0
624 for j in range(self._terminator_length):
625 term+=ord(_value[i+j])<<(j*8)
626 if term==self._terminator:
627 pos=i
628 break
629 if pos>=0:
630 _value=_value[:pos]
631 elif self._raiseonunterminatedread:
632 raise NotTerminatedException()
633 elif self._pad is not None:
634
635 while len(_value) and _value[-1]==chr(self._pad):
636 _value=_value[:-1]
637 else:
638 if self._terminator is None:
639
640 _value=buf.getremainingbytes()
641 else:
642
643 _value=""
644 count=0
645 term=0
646 while buf.hasmore():
647 _value+=chr(buf.getnextbyte())
648 count+=1
649 if (count % self._terminator_length)==0:
650 term=0
651
652 for j in range(self._terminator_length):
653 term=(term<<8)+ord(_value[count-1-j])
654 if term==self._terminator:
655 break
656 if term!=self._terminator and self._raiseonunterminatedread:
657 raise NotTerminatedException()
658 else:
659 _value=_value[:-1]
660
661 if self._maxsizeinbytes is not None:
662 _value=_value[:self._maxsizeinbytes]
663
664 if self._constant is not None and _value!=self._constant:
665 raise ValueException("The value read was not the constant")
666
667
668 if(flush):
669 buf.getnextbytes(flush)
670
671 self._bufferendoffset=buf.getcurrentoffset()
672
673
674
675
676
677 self._value=_value
678
680 if self._value is None:
681 raise ValueNotSetException()
682 self._bufferstartoffset=buf.getcurrentoffset()
683
684 temp_str=self.convert_for_write()
685
686
687 l=len(temp_str)
688 if self._terminator is not None:
689 l+=1
690 if self._pascal:
691 buf.appendbyte(l)
692 l+=1
693 buf.appendbytes(temp_str)
694 term=self._terminator
695 if self._terminator is not None:
696 for j in range(self._terminator_length):
697 buf.appendbyte((term & 0xFF))
698 term=term>>8
699
700 self._bufferendoffset=buf.getcurrentoffset()
701 l = self._bufferendoffset - self._bufferstartoffset
702
703 if self._sizeinbytes is not None:
704 if l<self._sizeinbytes:
705 buf.appendbytes(chr(self._pad)*(self._sizeinbytes-l))
706 self._bufferendoffset=buf.getcurrentoffset()
707
718
720 if self._sizeinbytes is not None:
721 return self._sizeinbytes
722
723 if self._value is None:
724 raise ValueNotSetException()
725
726 l=len(self.convert_for_write())
727 if self._terminator is not None:
728 l+=1
729
730 return l
731
733 """Returns the string we are"""
734 if self._value is None:
735 raise ValueNotSetException()
736
737
738 if not isinstance(self._value, unicode):
739 try:
740 self._value=self._value.decode(self._read_encoding)
741 except UnicodeDecodeError:
742
743 raise common.PhoneStringDecodeException(self._value, self._read_encoding)
744 return self._value
745
747 """A text string where ASCII characters are stored as packed 7 bit characters. This is
748 typically used in SMS messages."""
750 """
751 @keyword terminator: (Default=\x00) The termination character
752 @keyword sizeinbytes: Amount of space the string sits in
753 """
754 super(SEVENBITSTRING, self).__init__(*args, **kwargs)
755 self._value=None
756 self._terminator='\x00'
757 self._sizeinbytes=None
758 if self._ismostderived(SEVENBITSTRING):
759 self._update(args,kwargs)
760
770
776
778 """Returns the string we are"""
779 if self._value is None:
780 raise ValueNotSetException()
781 return self._value
782
784 """A date as used in SMS messages. It is six bytes long with the
785 bytes being year month day hour minute second. From stuff on the
786 web, it appears GSM phones swap each nybble."""
788 """@keyword sizeinbytes: (optional) Must be six"""
789 super(SMSDATE, self).__init__(*args, **kwargs)
790 self._values=None
791 self._sizeinbytes=6
792 if self._ismostderived(SMSDATE):
793 self._update(args, kwargs)
794
803
818
820 """Returns the ISO date time string we are"""
821 if self._value is None:
822 raise ValueNotSetException()
823 return "%d%02d%02dT%02d%02d%02d" % self._value
824
825
827 """A text string enclosed in quotes, with a way to escape quotes that a supposed
828 to be part of the string. Typical of Samsung phones."""
830 """
831 A string value can be specified to this constructor, or in the value keyword arg.
832
833 @keyword constant: (Optional) A constant value. All reads must have this value
834 @keyword terminator: (Default=,) The string terminator (or None). If set there will
835 always be a terminator when writing. The terminator is not returned when getting
836 the value.
837 @keyword quotechar: (Default=Double Quote) Quote character that surrounds string
838 @keyword readescape: (Default=True) Interpret PPP escape char (0x7d)
839 @keywors writeescape: (Default=False) Escape quotechar. If false, drop quotechar in string.
840 @keyword maxsizeinbytes: (Optional) On writing, truncate strings longer than this (length is before
841 any escaping and quoting
842 @keyword default: (Optional) Our default value
843 @keyword raiseonunterminatedread: (Default True) raise L{NotTerminatedException} if there is
844 no terminator on the value being read in. terminator must also be set.
845 @keyword raiseontruncate: (Default True) raise L{ValueLengthException} if the supplied
846 value is too large to fit within sizeinbytes.
847 @keyword raiseonmissingquotes: (Default True) raise L{MissingQuotesException} if the string does
848 not have quote characters around it
849 @keyword value: (Optional) Value
850 @keyword invalidchars: (Default=quotechar) A string containing invalid
851 characters which would be removed before writing to buffer.
852 @keyword encoding: (Default=None) If specified Unicode charset.
853 @keyword raiseonunicodeerror: (Default=True) raise exception if fail
854 to encode/decode Unicode.
855 """
856 super(CSVSTRING, self).__init__(*args, **kwargs)
857
858 self._constant=None
859 self._terminator=ord(',')
860 self._quotechar=ord('"')
861 self._readescape=True
862 self._writeescape=False
863 self._maxsizeinbytes=None
864 self._default=None
865 self._raiseonunterminatedread=True
866 self._raiseontruncate=True
867 self._raiseonmissingquotes=True
868 self._invalidchars=chr(self._quotechar)
869 self._value=None
870 self._encoding=None
871 self._raiseonunicodeerror=True
872
873 if self._ismostderived(CSVSTRING):
874 self._update(args,kwargs)
875
877 super(CSVSTRING,self)._update(args, kwargs)
878
879 self._consumekw(kwargs, ("constant", "terminator", "quotechar", "readescape",
880 "writeescape", "maxsizeinbytes", "default",
881 "raiseonunterminatedread", "value",
882 "raiseontruncate", "raiseonmissingquotes",
883 "invalidchars"))
884 self._complainaboutunusedargs(CSVSTRING,kwargs)
885
886
887 if len(args)==0:
888 pass
889 elif len(args)==1:
890 self._value=common.forceascii(args[0])
891 if self._constant is not None and self._constant!=self._value:
892 raise ValueException("This field is a constant of '%s'. You tried setting it to '%s'" % (self._constant, self._value))
893 else:
894 raise TypeError("Unexpected arguments "+`args`)
895 if self._value is None and self._default is not None:
896 self._value=self._default
897
898 if self._value is not None:
899 self._value=str(self._value)
900 if self._invalidchars:
901 self._value=re.sub(r'[%s]'%self._invalidchars, r'', self._value)
902 if self._maxsizeinbytes is not None:
903 l=len(self._value)
904 if l>self._maxsizeinbytes:
905 if self._raiseontruncate:
906 raise ValueLengthException(l, self._maxsizeinbytes)
907
908 self._value=self._value[:self._maxsizeinbytes]
909
911 self._bufferstartoffset=buf.getcurrentoffset()
912
913
914
915
916
917 if self._terminator is None:
918
919
920
921 self._value=buf.getremainingbytes()
922 else:
923
924
925
926 self._value=chr(buf.getnextbyte())
927 if self._value == ',':
928 self._value = ''
929 else:
930 inquotes=False
931 if self._quotechar is not None:
932 if self._value[0]==chr(self._quotechar):
933 inquotes=True
934 while buf.hasmore():
935 self._value+=chr(buf.getnextbyte())
936 if inquotes:
937 if self._value[-1]==chr(self._quotechar):
938 inquotes=False
939 else:
940 if self._value[-1]==chr(self._terminator):
941 break
942 if self._value[-1]==self._terminator:
943 if self._raiseonunterminatedread:
944 raise NotTerminatedException()
945 else:
946 self._value=self._value[:-1]
947
948 if self._quotechar is not None and self._value:
949 if self._value[0]==chr(self._quotechar) and self._value[-1]==chr(self._quotechar):
950 self._value=self._value[1:-1]
951 else:
952 raise MissingQuotesException()
953
954 if self._readescape:
955 self._value=common.pppunescape(self._value)
956
957 if self._constant is not None and self._value!=self._constant:
958 raise ValueException("The value read was not the constant")
959
960 self._bufferendoffset=buf.getcurrentoffset()
961
963
964 if self._value is None:
965 raise ValueNotSetException()
966
967 if self._encoding and isinstance(self._value, unicode):
968 try:
969 _value=common.encode_with_degrade(self._value,
970 self._encoding)
971 except UnicodeError:
972 if self._raiseonunicodeerror:
973 raise common.PhoneStringEncodeException(self._value,
974 self._encoding)
975 else:
976
977 _value=''
978 else:
979 _value=self._value
980
981 self._bufferstartoffset=buf.getcurrentoffset()
982
983 if self._quotechar is not None:
984 buf.appendbyte(self._quotechar)
985 buf.appendbytes(_value)
986 if self._quotechar is not None:
987 buf.appendbyte(self._quotechar)
988 if self._terminator is not None:
989 buf.appendbyte(self._terminator)
990
991 self._bufferendoffset=buf.getcurrentoffset()
992
994 if self._sizeinbytes is not None:
995 return self._sizeinbytes
996
997 if self._value is None:
998 raise ValueNotSetException()
999
1000 l=len(self._value)
1001 if self._terminator is not None:
1002 l+=1
1003
1004 return l
1005
1007 """Returns the string we are"""
1008 if self._value is None:
1009 raise ValueNotSetException()
1010
1011 if self._encoding and not isinstance(self._value, unicode):
1012 try:
1013 if self._raiseonunicodeerror:
1014 self._value=self._value.decode(self._encoding)
1015 else:
1016 self._value=self._value.decode(self._encoding, 'ignore')
1017 except UnicodeDecodeError:
1018
1019 raise common.PhoneStringDecodeException(self._value, self._encoding)
1020 return self._value
1021
1023 """Integers in CSV lines"""
1031
1033 for k in 'constant', 'default', 'value':
1034 if kwargs.has_key(k):
1035 kwargs[k]=str(kwargs[k])
1036 if len(args)==0:
1037 pass
1038 elif len(args)==1:
1039 args=(str(args[0]),)
1040 else:
1041 raise TypeError("expected integer as arg")
1042
1043 super(CSVINT,self)._update(args,kwargs)
1044 self._complainaboutunusedargs(CSVINT,kwargs)
1045
1047 """Convert the string into an integer
1048
1049 @rtype: integer
1050 """
1051
1052
1053
1054
1055 val=super(CSVINT,self).getvalue()
1056 try:
1057 ival=int(val)
1058 except:
1059 try:
1060 ival=int(self._default)
1061 except:
1062 raise ValueException("The field '%s' is not an integer" % (val))
1063 return ival
1064
1066 """Dates in CSV lines"""
1076
1090
1092 """Unpack the string into the date
1093
1094 @rtype: tuple
1095 @return: (year, month, day)
1096 """
1097
1098 s=super(CSVDATE,self).getvalue()
1099 val=s.split("/")
1100 if len(val)<2:
1101 year = 0
1102 month = 0
1103 day = 0
1104 else:
1105 year=int(val[2])
1106 month=int(val[0])
1107 day=int(val[1])
1108 return (year, month, day)
1109
1111 if len(date)>=3:
1112 year,month,day=date[:3]
1113 if month>0 or day>0 or year>0:
1114 s='%2.2d/%2.2d/%4.4d'%(month, day, year)
1115 else:
1116 s=""
1117 else:
1118 s=""
1119 return s
1120
1121
1123 """Timestamp in CSV lines"""
1133
1147
1149 """Unpack the string into the date
1150
1151 @rtype: tuple
1152 @return: (year, month, day)
1153 """
1154
1155 s=super(CSVTIME,self).getvalue()
1156 year=int(s[0:4])
1157 month=int(s[4:6])
1158 day=int(s[6:8])
1159 hour=int(s[9:11])
1160 minute=int(s[11:13])
1161 second=int(s[13:15])
1162 return (year, month, day, hour, minute, second)
1163
1165 if len(time)>=6:
1166 year,month,day,hour,minute,second=time[:6]
1167 s='%4.4d%2.2d%2.2dT%2.2d%2.2d%2.2d'%(year, month, day, hour, minute, second)
1168 else:
1169 s=""
1170 return s
1171
1172
1174 """A string as used on Audiovox. There is a one byte header saying how long the string
1175 is, followed by the string in a fixed sized buffer"""
1177 """
1178 A string value can be specified to this constructor, or in the value keyword arg.
1179
1180 @keyword constant: (Optional) A constant value. All reads must have this value
1181 @keyword pad: (Default=32 - space) When writing, what to pad the rest of the buffer with
1182 @keyword default: (Optional) Our default value
1183 @keyword raiseontruncate: (Default True) raise L{ValueLengthException} if the supplied
1184 value is too large to fit within the buffer.
1185 @keyword value: (Optional) Value
1186 @keyword sizeinbytes: (Mandatory) Size of the buffer, including the count byte
1187 """
1188 super(COUNTEDBUFFEREDSTRING,self).__init__(*args, **kwargs)
1189
1190 self._constant=None
1191 self._pad=32
1192 self._sizeinbytes=None
1193 self._default=None
1194 self._raiseontruncate=True
1195 self._value=None
1196
1197 if self._ismostderived(COUNTEDBUFFEREDSTRING):
1198 self._update(args, kwargs)
1199
1201 super(COUNTEDBUFFEREDSTRING,self)._update(args, kwargs)
1202
1203 self._consumekw(kwargs, ("constant", "pad", "sizeinbytes", "default", "raiseontruncate", "value"))
1204 self._complainaboutunusedargs(COUNTEDBUFFEREDSTRING,kwargs)
1205
1206 if len(args)==0:
1207 pass
1208 elif len(args)==1:
1209 self._value=str(args[0])
1210 if self._constant is not None and self._constant!=self._value:
1211 raise ValueException("This field is a constant of '%s'. You tried setting it to '%s'" % (self._constant, self._value))
1212 else:
1213 raise TypeError("Unexpected arguments "+`args`)
1214 if self._value is None and self._default is not None:
1215 self._value=self._default
1216
1217 if self._sizeinbytes is None:
1218 raise ValueException("sizeinbytes must be specified for COUNTEDBUFFEREDSTRING")
1219
1220 if self._value is not None:
1221 l=len(self._value)
1222 if l>self._sizeinbytes-1:
1223 if self._raiseontruncate:
1224 raise ValueLengthException(l, self._sizeinbytes-1)
1225
1226 self._value=self._value[:self._sizeinbytes-1]
1227
1229 assert self._sizeinbytes is not None
1230 self._bufferstartoffset=buf.getcurrentoffset()
1231
1232 strlen=buf.getnextbyte()
1233 if strlen>self._sizeinbytes-1:
1234 raise ValueException("counter specifies size of %d which is greater than remaining stringbuffer size of %d!" % (strlen, self._sizeinbytes-1))
1235 self._value=buf.getnextbytes(self._sizeinbytes-1)
1236 self._value=self._value[:strlen]
1237 if self._constant is not None and self._value!=self._constant:
1238 raise ValueException("The value read was not the constant")
1239
1240 self._bufferendoffset=buf.getcurrentoffset()
1241
1254
1256 assert self._sizeinbytes is not None
1257 return self._sizeinbytes
1258
1260 """Returns the string we are"""
1261 if self._value is None:
1262 raise ValueNotSetException()
1263 return self._value
1264
1265 -class DATA(BaseProtogenClass):
1266 "A block of bytes"
1268 """
1269 A data value can be specified to this constructor or in the value keyword arg
1270
1271 @keyword constant: (Optional) A constant value. All reads must have this value
1272 @keyword pad: (Default=0) The padding byte if fixed length when writing and the
1273 value isn't long enough
1274 @keyword sizeinbytes: (Optional) Set if fixed length.
1275 If not set, then the rest of the packet will be consumed on reads.
1276 @keyword default: (Optional) Our default value
1277 @keyword raiseonwrongsize: (Default True) raise L{ValueLengthException} if the supplied
1278 value is too large to fit within sizeinbytes.
1279 """
1280 super(DATA, self).__init__(*args, **kwargs)
1281
1282 self._constant=None
1283 self._pad=0
1284 self._sizeinbytes=None
1285 self._default=None
1286 self._raiseonwrongsize=True
1287 self._value=None
1288
1289 if self._ismostderived(DATA):
1290 self._update(args,kwargs)
1291
1293 super(DATA,self)._update(args, kwargs)
1294
1295 self._consumekw(kwargs, ("constant", "pad", "sizeinbytes", "default", "raiseonwrongsize", "value"))
1296 self._complainaboutunusedargs(DATA,kwargs)
1297
1298
1299 if len(args)==0:
1300 pass
1301 elif len(args)==1:
1302 self._value=args[0]
1303 if self._constant is not None and self._constant!=self._value:
1304 raise ValueException("This field is a constant and you set it to a different value")
1305 else:
1306 raise TypeError("Unexpected arguments "+`args`)
1307 if self._value is None and self._default is not None:
1308 self._value=self._default
1309
1310 if self._value is not None:
1311 if self._sizeinbytes is not None:
1312 l=len(self._value)
1313 if l<self._sizeinbytes:
1314 if self._pad is not None:
1315 self._value+=chr(self._pad)*(self._sizeinbytes-l)
1316
1317 l=len(self._value)
1318
1319 if l!=self._sizeinbytes:
1320 if self._raiseonwrongsize:
1321 raise ValueLengthException(l, self._sizeinbytes)
1322 else:
1323 self._value=self._value[:self._sizeinbytes]
1324
1325
1327 self._bufferstartoffset=buf.getcurrentoffset()
1328
1329 if self._sizeinbytes is not None:
1330
1331 self._value=buf.getnextbytes(self._sizeinbytes)
1332 else:
1333
1334 self._value=buf.getremainingbytes()
1335
1336 if self._constant is not None and self._value!=self._constant:
1337 raise ValueException("The value read was not the constant")
1338 self._bufferendoffset=buf.getcurrentoffset()
1339
1347
1349 if self._sizeinbytes is not None:
1350 return self._sizeinbytes
1351
1352 if self._value is None:
1353 raise ValueNotSetException()
1354
1355 l=len(self._value)
1356
1357 return l
1358
1360 """Returns the bytes we are"""
1361 if self._value is None:
1362 raise ValueNotSetException()
1363 return self._value
1364
1366 "Block of bytes that we don't know and don't care for"
1368 """
1369 A data value can be specified to this constructor or in the value keyword arg
1370
1371 @keyword sizeinbytes: Length of block
1372 If not set, then the rest of the packet will be consumed on reads.
1373 @keyword default: (Optional) Our default value, could be either a char or string.
1374 @keyword storage: (Optional) True or False: whether to store the data or ignore.
1375 """
1376 super(DONTCARE, self).__init__(*args, **kwargs)
1377
1378 self._sizeinbytes=None
1379 self._default='\x00'
1380 self._storage=False
1381 self._value=None
1382
1383 if self._ismostderived(DONTCARE):
1384 self._update(args,kwargs)
1385
1387 super(DONTCARE, self)._update(args, kwargs)
1388
1389 self._consumekw(kwargs, ("sizeinbytes", "default", "storage", "value"))
1390 self._complainaboutunusedargs(DONTCARE, kwargs)
1391
1392
1393 if len(args)==0:
1394 pass
1395 elif len(args)==1:
1396 if self._storage:
1397 self._value=args[0]
1398 else:
1399 raise TypeError("Unexpected arguments "+`args`)
1400
1401 if self._sizeinbytes is None:
1402 raise ValueException("sizeinbytes must be specified for DONTCARE")
1403
1404 if self._storage and self._value is not None and \
1405 len(self._value)!=self._sizeinbytes:
1406 raise ValueLengthException(len(self._value), self._sizeinbytes)
1407 if len(self._default)>1 and len(self._default)!=self._sizeinbytes:
1408 raise ValueLengthException(len(self._default), self._sizeinbytes)
1409
1419
1424
1426 return self._sizeinbytes
1427
1429 """Returns the bytes we are"""
1430 if self._value is not None:
1431 return self._value
1432 elif len(self._default)>1:
1433 return self._default
1434 else:
1435 return self._default*self._sizeinbytes
1436
1438 "A block of bytes whose purpose we don't know"
1439
1441 """
1442 Same arguments as L{DATA.__init__}. We default to a block
1443 of pad chars (usually \x00)
1444 """
1445 dict={'pad':0 , 'default': ""}
1446 dict.update(kwargs)
1447 super(UNKNOWN,self).__init__(*args, **dict)
1448
1449 if self._ismostderived(UNKNOWN):
1450 self._update(args,dict)
1451
1461
1462 -class LIST(BaseProtogenClass):
1463 """A list of items
1464
1465 You can generally treat this class as though it is a list. Note that some
1466 list like methods haven't been implemented (there are so darn many!) If you
1467 are missing one you want to use, please add it to this class.
1468 """
1469
1471 """
1472 You can pass objects to start the list with, or to the value keyword arg
1473
1474 @keyword createdefault: (Default False) Creates default members of the list if enough
1475 were not supplied before writing.
1476 @keyword length: (Optional) How many items there are in the list
1477 @keyword raiseonbadlength: (Default True) raises L{ValueLengthException} if there are
1478 the wrong number of items in the list. Note that this checking is only done
1479 when writing or reading from a buffer. length must be set for this to have any
1480 effect. If you have createdefault set then having less than length elements will
1481 not cause the exception.
1482 @keyword elementclass: (Mandatory) The class of each element
1483 @keyword elementinitkwargs: (Optional) KWargs for the constructor of each element
1484 @keyword value: (Optional) Value
1485 """
1486 self._thelist=[]
1487 super(LIST, self).__init__(*args, **kwargs)
1488 self._createdefault=False
1489 self._length=None
1490 self._raiseonbadlength=True
1491 self._raiseonincompleteread=True
1492 self._elementclass=None
1493 self._elementinitkwargs={}
1494
1495 if self._ismostderived(LIST):
1496 self._update(args,kwargs)
1497
1499 super(LIST,self)._update(args, kwargs)
1500 self._consumekw(kwargs, ("createdefault","length","raiseonbadlength","elementclass","elementinitkwargs","raiseonincompleteread"))
1501 if kwargs.has_key("value"):
1502 self._thelist=list(kwargs['value'])
1503 del kwargs['value']
1504
1505 self._complainaboutunusedargs(LIST,kwargs)
1506
1507 if self._elementclass is None:
1508 raise TypeError("elementclass argument was not supplied")
1509
1510 if len(args):
1511 self.extend(args)
1512
1514 self._bufferstartoffset=buf.getcurrentoffset()
1515
1516 self._thelist=[]
1517
1518 if self._length is None:
1519
1520 while buf.hasmore():
1521 x=self._makeitem()
1522 x.readfrombuffer(buf)
1523 self._thelist.append(x)
1524 else:
1525 for dummy in range(self._length):
1526
1527 x=self._makeitem()
1528 try:
1529 x.readfrombuffer(buf)
1530 except IndexError:
1531 if self._raiseonincompleteread:
1532 raise IndexError("tried to read too many list items")
1533 self._thelist.append(x)
1534
1535 self._bufferendoffset=buf.getcurrentoffset()
1536
1545
1552
1555
1557 self._ensurelength()
1558 for i,v in enumerate(self._thelist):
1559 yield "["+`i`+"]",v,None
1560
1561
1562
1563
1564
1565
1566
1567
1568
1571
1574
1575 - def insert(self, index, item):
1577
1579 return self._thelist[index]
1580
1586
1588
1589 for item in self._thelist:
1590 yield item
1591
1593 return self._thelist.__len__()
1594
1597
1600
1601
1603 "Creates a child element"
1604
1605 if len(args)==1 and isinstance(args[0], self._elementclass):
1606 return args[0]
1607 d={}
1608 d.update(self._elementinitkwargs)
1609 d.update(kwargs)
1610 return self._elementclass(*args, **d)
1611
1613 "Ensures we are the correct length"
1614 if self._createdefault and self._length is not None and len(self._thelist)<self._length:
1615 while len(self._thelist)<self._length:
1616 x=self._makeitem()
1617 self._thelist.append(x)
1618 return
1619 if self._length is not None and self._raiseonbadlength and len(self._thelist)!=self._length:
1620 raise ValueLengthException(len(self), self._length)
1621
1623 "This is used for reading and writing byte data"
1625 "Call with data to read from it, or with None to write to it"
1626 self.reset(data)
1627
1628 - def reset(self, data=None):
1629 "Call with data to read from it, or with None to write to it"
1630 if data is None:
1631 self._buffer=cStringIO.StringIO()
1632 else:
1633 self._data=data
1634
1635 self._offset=0
1636
1638 "Returns distance into data we are"
1639 return self._offset
1641 "Set the current offset"
1642 if ofs>len(self._data):
1643 raise IndexError('Trying to set offset beyond end of %d byte buffer'%len(self._data))
1644 self._offset=ofs
1645 offset=property(fget=getcurrentoffset, fset=setcurrentoffset)
1646
1648 "Returns value of next byte, but doesn't advance position"
1649 if self._offset+howmuch>=len(self._data):
1650 return None
1651 return ord(self._data[self._offset+howmuch])
1652
1654 "Returns next byte"
1655 if self._offset>=len(self._data):
1656 raise IndexError("trying to read one byte beyond end of "+`len(self._data)`+" byte buffer")
1657 res=ord(self._data[self._offset])
1658 self._offset+=1
1659 return res
1660
1662 "Returns howmany bytes"
1663 assert howmany>=0
1664 if self._offset+howmany>len(self._data):
1665 raise IndexError("Trying to read "+`howmany`+" bytes starting at "+`self._offset`+" which will go beyond end of "+`len(self._data)`+" byte buffer")
1666 res=self._data[self._offset:self._offset+howmany]
1667 self._offset+=howmany
1668 return res
1669
1671 if self._offset+howmany>len(self._data):
1672 return None
1673 return self._data[self._offset:self._offset+howmany]
1674
1676 "Returns rest of buffer"
1677 sz=len(self._data)-self._offset
1678 return self.getnextbytes(sz)
1679
1681 "Discards howmany bytes"
1682 if self._offset+howmany>len(self._data):
1683 raise IndexError("Trying to discard "+`howmany`+" bytes starting at "+`self._offset`+" which will go beyond end of "+`len(self._data)`+" byte buffer")
1684 self._offset+=howmany
1685
1687 "Discards the rest of the buffer"
1688 self._offset=len(self._data)
1689
1691 "Is there any data left?"
1692 return self._offset<len(self._data)
1693
1695 "Returns how many bytes left"
1696 return len(self._data)-self._offset
1697
1699 """Appends byte to data.
1700 @param val: a number 0 <= val <=255
1701 """
1702 assert val>=0 and val<=255
1703 self._buffer.write(chr(val))
1704 self._offset+=1
1705 assert self._offset==len(self._buffer.getvalue())
1706
1708 "Adds bytes to end"
1709 self._buffer.write(bytes)
1710 self._offset+=len(bytes)
1711 assert self._offset==len(self._buffer.getvalue())
1712
1714 "Returns the buffer being built"
1715 return self._buffer.getvalue()
1716
1718 "Returns the data passed in"
1719 return self._data
1720