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