Package pyamf :: Package util
[hide private]
[frames] | no frames]

Source Code for Package pyamf.util

   1  # -*- coding: utf-8 -*- 
   2  # 
   3  # Copyright (c) 2007-2009 The PyAMF Project. 
   4  # See LICENSE for details. 
   5   
   6  """ 
   7  AMF Utilities. 
   8   
   9  @since: 0.1.0 
  10  """ 
  11   
  12  import struct, calendar, datetime, types 
  13   
  14  import pyamf 
  15   
  16  try: 
  17      from cStringIO import StringIO 
  18  except ImportError: 
  19      from StringIO import StringIO 
  20   
  21  xml_types = None 
  22  ET = None 
  23  negative_timestamp_broken = False 
  24   
25 -def find_xml_lib():
26 """ 27 Run through a predefined order looking through the various C{ElementTree} 28 implementations so that any type can be encoded but PyAMF will return 29 elements as the first implementation found. 30 31 We work through the C implementations first - then the pure Python 32 versions. The downside to this is that a possible of three libraries will 33 be loaded into memory that are not used but the libs are small 34 (relatively) and the flexibility that this gives seems to outweigh the 35 cost. Time will tell. 36 37 @since: 0.4 38 """ 39 global xml_types, ET 40 41 xml_types = [] 42 43 try: 44 import xml.etree.cElementTree as cET 45 46 ET = cET 47 xml_types.append(type(cET.Element('foo'))) 48 except ImportError: 49 pass 50 51 try: 52 import cElementTree as cET 53 54 if ET is None: 55 ET = cET 56 57 xml_types.append(type(cET.Element('foo'))) 58 except ImportError: 59 pass 60 61 try: 62 import xml.etree.ElementTree as pET 63 64 if ET is None: 65 ET = pET 66 67 xml_types.append(pET._ElementInterface) 68 except ImportError: 69 pass 70 71 try: 72 import elementtree.ElementTree as pET 73 74 if ET is None: 75 ET = pET 76 77 xml_types.append(pET._ElementInterface) 78 except ImportError: 79 pass 80 81 for x in xml_types[:]: 82 # hack for jython 83 if x.__name__ == 'instance': 84 xml_types.remove(x) 85 86 xml_types = tuple(xml_types) 87 88 return xml_types
89
90 -class StringIOProxy(object):
91 """ 92 I am a C{StringIO} type object containing byte data from the AMF stream. 93 94 @see: U{ByteArray on OSFlash (external) 95 <http://osflash.org/documentation/amf3#x0c_-_bytearray>} 96 @see: U{Parsing ByteArrays on OSFlash (external) 97 <http://osflash.org/documentation/amf3/parsing_byte_arrays>} 98 """ 99 100 _wrapped_class = StringIO 101
102 - def __init__(self, buf=None):
103 """ 104 @raise TypeError: Unable to coerce C{buf} to C{StringIO}. 105 """ 106 self._buffer = StringIOProxy._wrapped_class() 107 108 if isinstance(buf, (str, unicode)): 109 self._buffer.write(buf) 110 elif hasattr(buf, 'getvalue'): 111 self._buffer.write(buf.getvalue()) 112 elif hasattr(buf, 'read') and hasattr(buf, 'seek') and hasattr(buf, 'tell'): 113 old_pos = buf.tell() 114 buf.seek(0) 115 self._buffer.write(buf.read()) 116 buf.seek(old_pos) 117 elif buf is None: 118 pass 119 else: 120 raise TypeError("Unable to coerce buf->StringIO") 121 122 self._get_len() 123 self._len_changed = False 124 self._buffer.seek(0, 0)
125
126 - def close(self):
127 self._buffer.close() 128 self._len = 0 129 self._len_changed = False
130
131 - def flush(self):
132 self._buffer.flush()
133
134 - def getvalue(self):
135 return self._buffer.getvalue()
136
137 - def next(self):
138 return self._buffer.next()
139
140 - def read(self, n=-1):
141 bytes = self._buffer.read(n) 142 143 return bytes
144
145 - def readline(self):
146 line = self._buffer.readline() 147 148 return line
149
150 - def readlines(self, sizehint=0):
151 """ 152 @type sizehint: C{int} 153 @param sizehint: Default is 0. 154 @note: This function does not consume the buffer. 155 """ 156 lines = self._buffer.readlines(sizehint) 157 158 return lines
159
160 - def seek(self, pos, mode=0):
161 return self._buffer.seek(pos, mode)
162
163 - def tell(self):
164 return self._buffer.tell()
165
166 - def truncate(self, size=0):
167 if size == 0: 168 self._buffer = StringIOProxy._wrapped_class() 169 self._len_changed = True 170 171 return 172 173 cur_pos = self.tell() 174 self.seek(0) 175 buf = self.read(size) 176 self._buffer = StringIOProxy._wrapped_class() 177 178 self._buffer.write(buf) 179 self.seek(cur_pos) 180 self._len_changed = True
181
182 - def write(self, s):
183 self._buffer.write(s) 184 self._len_changed = True
185
186 - def writelines(self, iterable):
187 self._buffer.writelines(iterable) 188 self._len_changed = True
189
190 - def _get_len(self):
191 if hasattr(self._buffer, 'len'): 192 self._len = self._buffer.len 193 194 return 195 196 old_pos = self._buffer.tell() 197 self._buffer.seek(0, 2) 198 199 self._len = self._buffer.tell() 200 self._buffer.seek(old_pos)
201
202 - def __len__(self):
203 if not self._len_changed: 204 return self._len 205 206 self._get_len() 207 self._len_changed = False 208 209 return self._len
210
211 - def consume(self):
212 """ 213 Chops the tail off the stream starting at 0 and ending at C{tell()}. 214 The stream pointer is set to 0 at the end of this function. 215 216 @since: 0.4 217 """ 218 bytes = self.read() 219 self.truncate() 220 221 if len(bytes) > 0: 222 self.write(bytes) 223 self.seek(0)
224
225 -class DataTypeMixIn(object):
226 """ 227 Provides methods for reading and writing basic data types for file-like 228 objects. 229 """ 230 231 ENDIAN_NETWORK = "!" 232 ENDIAN_NATIVE = "@" 233 ENDIAN_LITTLE = "<" 234 ENDIAN_BIG = ">" 235 236 endian = ENDIAN_NETWORK 237
238 - def _read(self, length):
239 """ 240 Reads C{length} bytes from the stream. If an attempt to read past the 241 end of the buffer is made, L{EOFError} is raised. 242 """ 243 bytes = self.read(length) 244 245 if len(bytes) != length: 246 self.seek(0 - len(bytes), 1) 247 248 raise EOFError("Tried to read %d byte(s) from the stream" % length) 249 250 return bytes
251
252 - def _is_big_endian(self):
253 """ 254 Whether this system is big endian or not. 255 256 @rtype: C{bool} 257 """ 258 if self.endian == DataTypeMixIn.ENDIAN_NATIVE: 259 return DataTypeMixIn._system_endian == DataTypeMixIn.ENDIAN_BIG 260 261 return self.endian in (DataTypeMixIn.ENDIAN_BIG, DataTypeMixIn.ENDIAN_NETWORK)
262
263 - def read_uchar(self):
264 """ 265 Reads an C{unsigned char} from the stream. 266 """ 267 return struct.unpack("B", self._read(1))[0]
268
269 - def write_uchar(self, c):
270 """ 271 Writes an C{unsigned char} to the stream. 272 273 @raise OverflowError: Not in range. 274 """ 275 if not 0 <= c <= 255: 276 raise OverflowError("Not in range, %d" % c) 277 278 self.write(struct.pack("B", c))
279
280 - def read_char(self):
281 """ 282 Reads a C{char} from the stream. 283 """ 284 return struct.unpack("b", self._read(1))[0]
285
286 - def write_char(self, c):
287 """ 288 Write a C{char} to the stream. 289 290 @raise OverflowError: Not in range. 291 """ 292 if not -128 <= c <= 127: 293 raise OverflowError("Not in range, %d" % c) 294 295 self.write(struct.pack("b", c))
296
297 - def read_ushort(self):
298 """ 299 Reads a 2 byte unsigned integer from the stream. 300 """ 301 return struct.unpack("%sH" % self.endian, self._read(2))[0]
302
303 - def write_ushort(self, s):
304 """ 305 Writes a 2 byte unsigned integer to the stream. 306 307 @raise OverflowError: Not in range. 308 """ 309 if not 0 <= s <= 65535: 310 raise OverflowError("Not in range, %d" % s) 311 312 self.write(struct.pack("%sH" % self.endian, s))
313
314 - def read_short(self):
315 """ 316 Reads a 2 byte integer from the stream. 317 """ 318 return struct.unpack("%sh" % self.endian, self._read(2))[0]
319
320 - def write_short(self, s):
321 """ 322 Writes a 2 byte integer to the stream. 323 324 @raise OverflowError: Not in range. 325 """ 326 if not -32768 <= s <= 32767: 327 raise OverflowError("Not in range, %d" % s) 328 329 self.write(struct.pack("%sh" % self.endian, s))
330
331 - def read_ulong(self):
332 """ 333 Reads a 4 byte unsigned integer from the stream. 334 """ 335 return struct.unpack("%sL" % self.endian, self._read(4))[0]
336
337 - def write_ulong(self, l):
338 """ 339 Writes a 4 byte unsigned integer to the stream. 340 341 @raise OverflowError: Not in range. 342 """ 343 if not 0 <= l <= 4294967295: 344 raise OverflowError("Not in range, %d" % l) 345 346 self.write(struct.pack("%sL" % self.endian, l))
347
348 - def read_long(self):
349 """ 350 Reads a 4 byte integer from the stream. 351 """ 352 return struct.unpack("%sl" % self.endian, self._read(4))[0]
353
354 - def write_long(self, l):
355 """ 356 Writes a 4 byte integer to the stream. 357 358 @raise OverflowError: Not in range. 359 """ 360 if not -2147483648 <= l <= 2147483647: 361 raise OverflowError("Not in range, %d" % l) 362 363 self.write(struct.pack("%sl" % self.endian, l))
364
365 - def read_24bit_uint(self):
366 """ 367 Reads a 24 bit unsigned integer from the stream. 368 369 @since: 0.4 370 """ 371 order = None 372 373 if not self._is_big_endian(): 374 order = [0, 8, 16] 375 else: 376 order = [16, 8, 0] 377 378 n = 0 379 380 for x in order: 381 n += (self.read_uchar() << x) 382 383 return n
384
385 - def write_24bit_uint(self, n):
386 """ 387 Writes a 24 bit unsigned integer to the stream. 388 389 @since: 0.4 390 """ 391 if not 0 <= n <= 0xffffff: 392 raise OverflowError("n is out of range") 393 394 order = None 395 396 if not self._is_big_endian(): 397 order = [0, 8, 16] 398 else: 399 order = [16, 8, 0] 400 401 for x in order: 402 self.write_uchar((n >> x) & 0xff)
403
404 - def read_24bit_int(self):
405 """ 406 Reads a 24 bit integer from the stream. 407 408 @since: 0.4 409 """ 410 n = self.read_24bit_uint() 411 412 if n & 0x800000 != 0: 413 # the int is signed 414 n -= 0x1000000 415 416 return n
417
418 - def write_24bit_int(self, n):
419 """ 420 Writes a 24 bit integer to the stream. 421 422 @since: 0.4 423 """ 424 if not -8388608 <= n <= 8388607: 425 raise OverflowError("n is out of range") 426 427 order = None 428 429 if not self._is_big_endian(): 430 order = [0, 8, 16] 431 else: 432 order = [16, 8, 0] 433 434 if n < 0: 435 n += 0x1000000 436 437 for x in order: 438 self.write_uchar((n >> x) & 0xff)
439
440 - def read_double(self):
441 """ 442 Reads an 8 byte float from the stream. 443 """ 444 return struct.unpack("%sd" % self.endian, self._read(8))[0]
445
446 - def write_double(self, d):
447 """ 448 Writes an 8 byte float to the stream. 449 """ 450 self.write(struct.pack("%sd" % self.endian, d))
451
452 - def read_float(self):
453 """ 454 Reads a 4 byte float from the stream. 455 """ 456 return struct.unpack("%sf" % self.endian, self._read(4))[0]
457
458 - def write_float(self, f):
459 """ 460 Writes a 4 byte float to the stream. 461 """ 462 self.write(struct.pack("%sf" % self.endian, f))
463
464 - def read_utf8_string(self, length):
465 """ 466 Reads a UTF-8 string from the stream. 467 468 @rtype: C{unicode} 469 """ 470 str = struct.unpack("%s%ds" % (self.endian, length), self.read(length))[0] 471 472 return unicode(str, "utf8")
473
474 - def write_utf8_string(self, u):
475 """ 476 Writes a unicode object to the stream in UTF-8 477 """ 478 bytes = u.encode("utf8") 479 480 self.write(struct.pack("%s%ds" % (self.endian, len(bytes)), bytes))
481 482 if struct.pack('@H', 1)[0] == '\x01': 483 DataTypeMixIn._system_endian = DataTypeMixIn.ENDIAN_LITTLE 484 else: 485 DataTypeMixIn._system_endian = DataTypeMixIn.ENDIAN_BIG 486
487 -class BufferedByteStream(StringIOProxy, DataTypeMixIn):
488 """ 489 An extension of C{StringIO}. 490 491 Features: 492 - Raises L{EOFError} if reading past end. 493 - Allows you to C{peek()} at the next byte. 494 """ 495
496 - def __init__(self, buf=None):
497 """ 498 @param buf: Initial byte stream. 499 @type buf: C{str} or C{StringIO} instance 500 """ 501 StringIOProxy.__init__(self, buf=buf) 502 503 self.seek(0)
504
505 - def read(self, length=-1):
506 """ 507 Read bytes from stream. 508 509 If we are at the end of the buffer, a C{EOFError} is raised. 510 If there is not enough buffer to be read and length is 511 specified C{IOError} is raised. 512 513 @param length: Number of bytes to read. 514 @type length: C{int} 515 @raise EOFError: Reading past end of stream. 516 @raise IOError: Length specified but not enough buffer 517 available. 518 519 @rtype: array of C{char} 520 @return: The bytes read from the stream. 521 """ 522 if length > 0 and self.at_eof(): 523 raise EOFError 524 if length > 0 and self.tell() + length > len(self): 525 raise IOError 526 527 return StringIOProxy.read(self, length)
528
529 - def peek(self, size=1):
530 """ 531 Looks size bytes ahead in the stream, returning what it finds, 532 returning the stream pointer to its initial position. 533 534 @param size: Default is 1. 535 @type size: C{int} 536 @raise ValueError: Trying to peek backwards. 537 538 @rtype: 539 @return: Bytes. 540 """ 541 if size == -1: 542 return self.peek(len(self) - self.tell()) 543 544 if size < -1: 545 raise ValueError("Cannot peek backwards") 546 547 bytes = '' 548 pos = self.tell() 549 550 while not self.at_eof() and len(bytes) != size: 551 bytes += self.read(1) 552 553 self.seek(pos) 554 555 return bytes
556
557 - def at_eof(self):
558 """ 559 Returns true if C{next.read(1)} will trigger an C{EOFError}. 560 561 @rtype: C{bool} 562 @return: 563 """ 564 return self.tell() >= len(self)
565
566 - def remaining(self):
567 """ 568 Returns number of remaining bytes. 569 570 @rtype: C{number} 571 @return: Number of remaining bytes. 572 """ 573 return len(self) - self.tell()
574
575 - def __add__(self, other):
576 old_pos = self.tell() 577 old_other_pos = other.tell() 578 579 new = BufferedByteStream(self) 580 581 other.seek(0) 582 new.seek(0, 2) 583 new.write(other.read()) 584 585 self.seek(old_pos) 586 other.seek(old_other_pos) 587 new.seek(0) 588 589 return new
590
591 -def hexdump(data):
592 """ 593 Get hexadecimal representation of C{StringIO} data. 594 595 @type data: 596 @param data: 597 @rtype: C{str} 598 @return: Hexadecimal string. 599 """ 600 import string 601 602 hex = ascii = buf = "" 603 index = 0 604 605 for c in data: 606 hex += "%02x " % ord(c) 607 if c in string.printable and c not in string.whitespace: 608 ascii += c 609 else: 610 ascii += "." 611 612 if len(ascii) == 16: 613 buf += "%04x: %s %s %s\n" % (index, hex[:24], hex[24:], ascii) 614 hex = ascii = "" 615 index += 16 616 617 if len(ascii): 618 buf += "%04x: %-24s %-24s %s\n" % (index, hex[:24], hex[24:], ascii) 619 620 return buf
621
622 -def get_timestamp(d):
623 """ 624 Returns a UTC timestamp for a C{datetime.datetime} object. 625 626 @type d: C{datetime.datetime} 627 @param d: The date object. 628 @return: UTC timestamp. 629 @rtype: C{str} 630 631 @note: Inspiration taken from the U{Intertwingly blog 632 <http://intertwingly.net/blog/2007/09/02/Dealing-With-Dates>}. 633 """ 634 if isinstance(d, datetime.date) and not isinstance(d, datetime.datetime): 635 d = datetime.datetime.combine(d, datetime.time(0, 0, 0, 0)) 636 637 return calendar.timegm(d.utctimetuple())
638
639 -def get_datetime(secs):
640 """ 641 Return a UTC date from a timestamp. 642 643 @type secs: C{long} 644 @param secs: Seconds since 1970. 645 @return: UTC timestamp. 646 @rtype: C{datetime.datetime} 647 """ 648 if secs < 0 and negative_timestamp_broken: 649 return datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=secs) 650 651 return datetime.datetime.utcfromtimestamp(secs)
652
653 -def make_classic_instance(klass):
654 """ 655 Create an instance of a classic class (not inherited from ``object``) 656 without calling __init__(). 657 658 @type klass: C{class} 659 @param klass: The classic class to create an instance for. 660 @rtype: 661 @return: instance created 662 """ 663 assert isinstance(klass, types.ClassType), "not an old style class" 664 665 class _TemporaryClass: 666 pass
667 668 inst = _TemporaryClass() 669 inst.__class__ = klass 670 671 return inst 672
673 -def get_mro(C):
674 """ 675 Compute the class precedence list (mro). 676 677 @raise TypeError: class type expected. 678 """ 679 def merge(seqs): 680 """ 681 @raise NameError: Inconsistent hierarchy. 682 @raise TypeError: Class type expected. 683 """ 684 res = [] 685 i = 0 686 687 while 1: 688 nonemptyseqs = [seq for seq in seqs if seq] 689 if not nonemptyseqs: 690 return res 691 692 i += 1 693 for seq in nonemptyseqs: 694 cand = seq[0] 695 nothead = [s for s in nonemptyseqs if cand in s[1:]] 696 697 if nothead: 698 cand = None 699 else: 700 break 701 702 if not cand: 703 raise NameError("Inconsistent hierarchy") 704 705 res.append(cand) 706 707 for seq in nonemptyseqs: 708 if seq[0] == cand: 709 del seq[0]
710 711 if not isinstance(C, (types.ClassType, types.ObjectType)): 712 raise TypeError('class type expected') 713 714 if hasattr(C, '__mro__'): 715 return C.__mro__ 716 717 return merge([[C]] + map(get_mro, C.__bases__) + [list(C.__bases__)]) 718
719 -def get_attrs(obj):
720 """ 721 Gets a C{dict} of the attrs of an object in a predefined resolution order. 722 723 @raise AttributeError: A duplicate attribute was already found in this 724 collection, are you mixing different key types? 725 """ 726 if hasattr(obj, 'iteritems'): 727 attrs = {} 728 729 for k, v in obj.iteritems(): 730 sk = str(k) 731 732 if sk in attrs.keys(): 733 raise AttributeError('A duplicate attribute (%s) was ' 734 'already found in this collection, are you mixing ' 735 'different key types?' % (sk,)) 736 737 attrs[sk] = v 738 739 return attrs 740 elif hasattr(obj, '__dict__'): 741 return obj.__dict__.copy() 742 elif hasattr(obj, '__slots__'): 743 attrs = {} 744 745 for k in obj.__slots__: 746 attrs[k] = getattr(obj, k) 747 748 return attrs 749 750 return None
751
752 -def set_attrs(obj, attrs):
753 """ 754 A generic function which applies a collection of attributes C{attrs} to 755 object C{obj} 756 757 @param obj: An instance implementing the __setattr__ function 758 @param attrs: A collection implementing the iteritems function 759 @type attrs: Usually a dict 760 """ 761 f = lambda n, v: setattr(obj, n, v) 762 763 if isinstance(obj, (list, dict)): 764 f = obj.__setitem__ 765 766 for k, v in attrs.iteritems(): 767 f(k, v)
768
769 -def get_class_alias(klass):
770 for k, v in pyamf.ALIAS_TYPES.iteritems(): 771 for kl in v: 772 if isinstance(kl, types.FunctionType): 773 if kl(klass) is True: 774 return k 775 elif isinstance(kl, (type, (types.ClassType, types.ObjectType))): 776 if issubclass(klass, kl): 777 return k 778 779 return None
780
781 -class IndexedCollection(object):
782
783 - def __init__(self, use_hash=False):
784 if use_hash is True: 785 self.func = hash 786 else: 787 self.func = id 788 789 self.clear()
790
791 - def clear(self):
792 self.list = [] 793 self.dict = {}
794
795 - def getByReference(self, ref):
796 """ 797 @raise TypeError: Bad reference type. 798 @raise pyamf.ReferenceError: Reference not found. 799 """ 800 if not isinstance(ref, (int, long)): 801 raise TypeError("Bad reference type") 802 803 try: 804 return self.list[ref] 805 except IndexError: 806 raise pyamf.ReferenceError("Reference %r not found" % (ref,))
807
808 - def getReferenceTo(self, obj):
809 """ 810 @raise pyamf.ReferenceError: Value not found. 811 """ 812 try: 813 return self.dict[self.func(obj)] 814 except KeyError: 815 raise pyamf.ReferenceError("Value %r not found" % (obj,))
816
817 - def append(self, obj):
818 h = self.func(obj) 819 820 try: 821 return self.dict[h] 822 except KeyError: 823 self.list.append(obj) 824 idx = len(self.list) - 1 825 self.dict[h] = idx 826 827 return idx
828
829 - def remove(self, obj):
830 """ 831 @raise pyamf.ReferenceError: Trying to remove an invalid reference. 832 """ 833 h = self.func(obj) 834 835 try: 836 idx = self.dict[h] 837 except KeyError: 838 raise pyamf.ReferenceError("%r is not a valid reference" % (obj,)) 839 840 del self.list[idx] 841 del self.dict[h] 842 843 return idx
844
845 - def __eq__(self, other):
846 if isinstance(other, list): 847 return self.list == other 848 elif isinstance(other, dict): 849 return self.dict == other 850 851 return False
852
853 - def __len__(self):
854 return len(self.list)
855
856 - def __getitem__(self, idx):
857 return self.getByReference(idx)
858
859 - def __contains__(self, obj):
860 try: 861 r = self.getReferenceTo(obj) 862 except pyamf.ReferenceError: 863 r = None 864 865 return r is not None
866
867 - def __repr__(self):
868 return '<%s list=%r dict=%r>' % (self.__class__.__name__, self.list, self.dict)
869
870 - def __iter__(self):
871 return iter(self.list)
872
873 -class IndexedMap(IndexedCollection):
874 """ 875 Like L{IndexedCollection}, but also maps to another object. 876 877 @since: 0.4 878 """ 879
880 - def __init__(self, use_hash=False):
881 IndexedCollection.__init__(self, use_hash) 882 self.mapped = []
883
884 - def clear(self):
885 IndexedCollection.clear(self) 886 self.mapped = []
887
888 - def getMappedByReference(self, ref):
889 """ 890 @raise TypeError: Bad reference type. 891 @raise pyamf.ReferenceError: Reference not found. 892 """ 893 if not isinstance(ref, (int, long)): 894 raise TypeError("Bad reference type.") 895 896 try: 897 return self.mapped[ref] 898 except IndexError: 899 raise pyamf.ReferenceError("Reference %r not found" % ref)
900
901 - def append(self, obj):
902 idx = IndexedCollection.append(self, obj) 903 diff = (idx + 1) - len(self.mapped) 904 for i in range(0, diff): 905 self.mapped.append(None) 906 return idx
907
908 - def map(self, obj, mapped_obj):
909 idx = self.append(obj) 910 self.mapped[idx] = mapped_obj 911 return idx
912
913 - def remove(self, obj):
914 idx = IndexedCollection.remove(self, obj) 915 del self.mapped[idx] 916 return idx
917
918 -def is_ET_element(obj):
919 """ 920 Determines if the supplied C{obj} param is a valid ElementTree element. 921 """ 922 return isinstance(obj, xml_types)
923
924 -def is_float_broken():
925 """ 926 Older versions of Python (<=2.5) and the Windows platform are renowned for 927 mixing up 'special' floats. This function determines whether this is the 928 case. 929 930 @since: 0.4 931 @rtype: C{bool} 932 """ 933 # we do this instead of float('nan') because windows throws a wobbler. 934 nan = 1e300000/1e300000 935 936 return str(nan) != str(struct.unpack("!d", '\xff\xf8\x00\x00\x00\x00\x00\x00')[0])
937 938 # init the module from here .. 939 940 find_xml_lib() 941 942 try: 943 datetime.datetime.utcfromtimestamp(-31536000.0) 944 except ValueError: 945 negative_timestamp_broken = True 946 947 if is_float_broken(): 948 import fpconst 949
950 - def read_double_workaround(self):
951 bytes = self.read(8) 952 953 if self._is_big_endian(): 954 if bytes == '\xff\xf8\x00\x00\x00\x00\x00\x00': 955 return fpconst.NaN 956 957 if bytes == '\xff\xf0\x00\x00\x00\x00\x00\x00': 958 return fpconst.NegInf 959 960 if bytes == '\x7f\xf0\x00\x00\x00\x00\x00\x00': 961 return fpconst.PosInf 962 else: 963 if bytes == '\x00\x00\x00\x00\x00\x00\xf8\xff': 964 return fpconst.NaN 965 966 if bytes == '\x00\x00\x00\x00\x00\x00\xf0\xff': 967 return fpconst.NegInf 968 969 if bytes == '\x00\x00\x00\x00\x00\x00\xf0\x7f': 970 return fpconst.PosInf 971 972 return struct.unpack("%sd" % self.endian, bytes)[0]
973 974 DataTypeMixIn.read_double = read_double_workaround 975
976 - def write_double_workaround(self, d):
977 if fpconst.isNaN(d): 978 if self._is_big_endian(): 979 self.write('\xff\xf8\x00\x00\x00\x00\x00\x00') 980 else: 981 self.write('\x00\x00\x00\x00\x00\x00\xf8\xff') 982 elif fpconst.isNegInf(d): 983 if self._is_big_endian(): 984 self.write('\xff\xf0\x00\x00\x00\x00\x00\x00') 985 else: 986 self.write('\x00\x00\x00\x00\x00\x00\xf0\xff') 987 elif fpconst.isPosInf(d): 988 if self._is_big_endian(): 989 self.write('\x7f\xf0\x00\x00\x00\x00\x00\x00') 990 else: 991 self.write('\x00\x00\x00\x00\x00\x00\xf0\x7f') 992 else: 993 write_double_workaround.old_func(self, d)
994 995 x = DataTypeMixIn.write_double 996 DataTypeMixIn.write_double = write_double_workaround 997 write_double_workaround.old_func = x 998 999 try: 1000 from cpyamf.util import BufferedByteStream 1001
1002 - class StringIOProxy(BufferedByteStream):
1003 _wrapped_class = None 1004
1005 - def __init__(self, *args, **kwargs):
1006 BufferedByteStream.__init__(self, *args, **kwargs) 1007 self._buffer = self
1008
1009 - class DataTypeMixIn(BufferedByteStream):
1010 ENDIAN_NETWORK = "!" 1011 ENDIAN_NATIVE = "@" 1012 ENDIAN_LITTLE = "<" 1013 ENDIAN_BIG = ">"
1014 except ImportError: 1015 pass 1016