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 msec = str(d.microsecond).rjust(6).replace(' ', '0') 638 639 return float('%s.%s' % (calendar.timegm(d.utctimetuple()), msec))
640
641 -def get_datetime(secs):
642 """ 643 Return a UTC date from a timestamp. 644 645 @type secs: C{long} 646 @param secs: Seconds since 1970. 647 @return: UTC timestamp. 648 @rtype: C{datetime.datetime} 649 """ 650 if secs < 0 and negative_timestamp_broken: 651 return datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=secs) 652 653 return datetime.datetime.utcfromtimestamp(secs)
654
655 -def make_classic_instance(klass):
656 """ 657 Create an instance of a classic class (not inherited from ``object``) 658 without calling __init__(). 659 660 @type klass: C{class} 661 @param klass: The classic class to create an instance for. 662 @rtype: 663 @return: instance created 664 """ 665 assert isinstance(klass, types.ClassType), "not an old style class" 666 667 class _TemporaryClass: 668 pass
669 670 inst = _TemporaryClass() 671 inst.__class__ = klass 672 673 return inst 674
675 -def get_mro(C):
676 """ 677 Compute the class precedence list (mro). 678 679 @raise TypeError: class type expected. 680 """ 681 def merge(seqs): 682 """ 683 @raise NameError: Inconsistent hierarchy. 684 @raise TypeError: Class type expected. 685 """ 686 res = [] 687 i = 0 688 689 while 1: 690 nonemptyseqs = [seq for seq in seqs if seq] 691 if not nonemptyseqs: 692 return res 693 694 i += 1 695 for seq in nonemptyseqs: 696 cand = seq[0] 697 nothead = [s for s in nonemptyseqs if cand in s[1:]] 698 699 if nothead: 700 cand = None 701 else: 702 break 703 704 if not cand: 705 raise NameError("Inconsistent hierarchy") 706 707 res.append(cand) 708 709 for seq in nonemptyseqs: 710 if seq[0] == cand: 711 del seq[0]
712 713 if not isinstance(C, (types.ClassType, types.ObjectType)): 714 raise TypeError('class type expected') 715 716 if hasattr(C, '__mro__'): 717 return C.__mro__ 718 719 return merge([[C]] + map(get_mro, C.__bases__) + [list(C.__bases__)]) 720
721 -def get_attrs(obj):
722 """ 723 Gets a C{dict} of the attrs of an object in a predefined resolution order. 724 725 @raise AttributeError: A duplicate attribute was already found in this 726 collection, are you mixing different key types? 727 """ 728 if hasattr(obj, 'iteritems'): 729 attrs = {} 730 731 for k, v in obj.iteritems(): 732 sk = str(k) 733 734 if sk in attrs.keys(): 735 raise AttributeError('A duplicate attribute (%s) was ' 736 'already found in this collection, are you mixing ' 737 'different key types?' % (sk,)) 738 739 attrs[sk] = v 740 741 return attrs 742 elif hasattr(obj, '__dict__'): 743 return obj.__dict__.copy() 744 elif hasattr(obj, '__slots__'): 745 attrs = {} 746 747 for k in obj.__slots__: 748 attrs[k] = getattr(obj, k) 749 750 return attrs 751 752 return None
753
754 -def set_attrs(obj, attrs):
755 """ 756 A generic function which applies a collection of attributes C{attrs} to 757 object C{obj} 758 759 @param obj: An instance implementing the __setattr__ function 760 @param attrs: A collection implementing the iteritems function 761 @type attrs: Usually a dict 762 """ 763 f = lambda n, v: setattr(obj, n, v) 764 765 if isinstance(obj, (list, dict)): 766 f = obj.__setitem__ 767 768 for k, v in attrs.iteritems(): 769 f(k, v)
770
771 -def get_class_alias(klass):
772 for k, v in pyamf.ALIAS_TYPES.iteritems(): 773 for kl in v: 774 if isinstance(kl, types.FunctionType): 775 if kl(klass) is True: 776 return k 777 elif isinstance(kl, (type, (types.ClassType, types.ObjectType))): 778 if issubclass(klass, kl): 779 return k 780 781 return None
782
783 -class IndexedCollection(object):
784
785 - def __init__(self, use_hash=False):
786 if use_hash is True: 787 self.func = hash 788 else: 789 self.func = id 790 791 self.clear()
792
793 - def clear(self):
794 self.list = [] 795 self.dict = {}
796
797 - def getByReference(self, ref):
798 """ 799 @raise TypeError: Bad reference type. 800 @raise pyamf.ReferenceError: Reference not found. 801 """ 802 if not isinstance(ref, (int, long)): 803 raise TypeError("Bad reference type") 804 805 try: 806 return self.list[ref] 807 except IndexError: 808 raise pyamf.ReferenceError("Reference %r not found" % (ref,))
809
810 - def getReferenceTo(self, obj):
811 """ 812 @raise pyamf.ReferenceError: Value not found. 813 """ 814 try: 815 return self.dict[self.func(obj)] 816 except KeyError: 817 raise pyamf.ReferenceError("Value %r not found" % (obj,))
818
819 - def append(self, obj):
820 h = self.func(obj) 821 822 try: 823 return self.dict[h] 824 except KeyError: 825 self.list.append(obj) 826 idx = len(self.list) - 1 827 self.dict[h] = idx 828 829 return idx
830
831 - def remove(self, obj):
832 """ 833 @raise pyamf.ReferenceError: Trying to remove an invalid reference. 834 """ 835 h = self.func(obj) 836 837 try: 838 idx = self.dict[h] 839 except KeyError: 840 raise pyamf.ReferenceError("%r is not a valid reference" % (obj,)) 841 842 del self.list[idx] 843 del self.dict[h] 844 845 return idx
846
847 - def __eq__(self, other):
848 if isinstance(other, list): 849 return self.list == other 850 elif isinstance(other, dict): 851 return self.dict == other 852 853 return False
854
855 - def __len__(self):
856 return len(self.list)
857
858 - def __getitem__(self, idx):
859 return self.getByReference(idx)
860
861 - def __contains__(self, obj):
862 try: 863 r = self.getReferenceTo(obj) 864 except pyamf.ReferenceError: 865 r = None 866 867 return r is not None
868
869 - def __repr__(self):
870 return '<%s list=%r dict=%r>' % (self.__class__.__name__, self.list, self.dict)
871
872 - def __iter__(self):
873 return iter(self.list)
874
875 -class IndexedMap(IndexedCollection):
876 """ 877 Like L{IndexedCollection}, but also maps to another object. 878 879 @since: 0.4 880 """ 881
882 - def __init__(self, use_hash=False):
883 IndexedCollection.__init__(self, use_hash) 884 self.mapped = []
885
886 - def clear(self):
887 IndexedCollection.clear(self) 888 self.mapped = []
889
890 - def getMappedByReference(self, ref):
891 """ 892 @raise TypeError: Bad reference type. 893 @raise pyamf.ReferenceError: Reference not found. 894 """ 895 if not isinstance(ref, (int, long)): 896 raise TypeError("Bad reference type.") 897 898 try: 899 return self.mapped[ref] 900 except IndexError: 901 raise pyamf.ReferenceError("Reference %r not found" % ref)
902
903 - def append(self, obj):
904 idx = IndexedCollection.append(self, obj) 905 diff = (idx + 1) - len(self.mapped) 906 for i in range(0, diff): 907 self.mapped.append(None) 908 return idx
909
910 - def map(self, obj, mapped_obj):
911 idx = self.append(obj) 912 self.mapped[idx] = mapped_obj 913 return idx
914
915 - def remove(self, obj):
916 idx = IndexedCollection.remove(self, obj) 917 del self.mapped[idx] 918 return idx
919
920 -def is_ET_element(obj):
921 """ 922 Determines if the supplied C{obj} param is a valid ElementTree element. 923 """ 924 return isinstance(obj, xml_types)
925
926 -def is_float_broken():
927 """ 928 Older versions of Python (<=2.5) and the Windows platform are renowned for 929 mixing up 'special' floats. This function determines whether this is the 930 case. 931 932 @since: 0.4 933 @rtype: C{bool} 934 """ 935 # we do this instead of float('nan') because windows throws a wobbler. 936 nan = 1e300000/1e300000 937 938 return str(nan) != str(struct.unpack("!d", '\xff\xf8\x00\x00\x00\x00\x00\x00')[0])
939 940 # init the module from here .. 941 942 find_xml_lib() 943 944 try: 945 datetime.datetime.utcfromtimestamp(-31536000.0) 946 except ValueError: 947 negative_timestamp_broken = True 948 949 if is_float_broken(): 950 import fpconst 951
952 - def read_double_workaround(self):
953 bytes = self.read(8) 954 955 if self._is_big_endian(): 956 if bytes == '\xff\xf8\x00\x00\x00\x00\x00\x00': 957 return fpconst.NaN 958 959 if bytes == '\xff\xf0\x00\x00\x00\x00\x00\x00': 960 return fpconst.NegInf 961 962 if bytes == '\x7f\xf0\x00\x00\x00\x00\x00\x00': 963 return fpconst.PosInf 964 else: 965 if bytes == '\x00\x00\x00\x00\x00\x00\xf8\xff': 966 return fpconst.NaN 967 968 if bytes == '\x00\x00\x00\x00\x00\x00\xf0\xff': 969 return fpconst.NegInf 970 971 if bytes == '\x00\x00\x00\x00\x00\x00\xf0\x7f': 972 return fpconst.PosInf 973 974 return struct.unpack("%sd" % self.endian, bytes)[0]
975 976 DataTypeMixIn.read_double = read_double_workaround 977
978 - def write_double_workaround(self, d):
979 if fpconst.isNaN(d): 980 if self._is_big_endian(): 981 self.write('\xff\xf8\x00\x00\x00\x00\x00\x00') 982 else: 983 self.write('\x00\x00\x00\x00\x00\x00\xf8\xff') 984 elif fpconst.isNegInf(d): 985 if self._is_big_endian(): 986 self.write('\xff\xf0\x00\x00\x00\x00\x00\x00') 987 else: 988 self.write('\x00\x00\x00\x00\x00\x00\xf0\xff') 989 elif fpconst.isPosInf(d): 990 if self._is_big_endian(): 991 self.write('\x7f\xf0\x00\x00\x00\x00\x00\x00') 992 else: 993 self.write('\x00\x00\x00\x00\x00\x00\xf0\x7f') 994 else: 995 write_double_workaround.old_func(self, d)
996 997 x = DataTypeMixIn.write_double 998 DataTypeMixIn.write_double = write_double_workaround 999 write_double_workaround.old_func = x 1000 1001 try: 1002 from cpyamf.util import BufferedByteStream 1003
1004 - class StringIOProxy(BufferedByteStream):
1005 _wrapped_class = None 1006
1007 - def __init__(self, *args, **kwargs):
1008 BufferedByteStream.__init__(self, *args, **kwargs) 1009 self._buffer = self
1010
1011 - class DataTypeMixIn(BufferedByteStream):
1012 ENDIAN_NETWORK = "!" 1013 ENDIAN_NATIVE = "@" 1014 ENDIAN_LITTLE = "<" 1015 ENDIAN_BIG = ">"
1016 except ImportError: 1017 pass 1018