New version by Digital Creations, supports binary format compatible
with cPickle.
diff --git a/Lib/pickle.py b/Lib/pickle.py
index bfe49f9..2a4357d 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -1,3 +1,56 @@
+#     $Id$
+#
+#     Copyright 
+#
+#       Copyright 1996 Digital Creations, L.C., 910 Princess Anne
+#       Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All
+#       rights reserved.  Copyright in this software is owned by DCLC,
+#       unless otherwise indicated. Permission to use, copy and
+#       distribute this software is hereby granted, provided that the
+#       above copyright notice appear in all copies and that both that
+#       copyright notice and this permission notice appear. Note that
+#       any product, process or technology described in this software
+#       may be the subject of other Intellectual Property rights
+#       reserved by Digital Creations, L.C. and are not licensed
+#       hereunder.
+#
+#     Trademarks 
+#
+#       Digital Creations & DCLC, are trademarks of Digital Creations, L.C..
+#       All other trademarks are owned by their respective companies. 
+#
+#     No Warranty 
+#
+#       The software is provided "as is" without warranty of any kind,
+#       either express or implied, including, but not limited to, the
+#       implied warranties of merchantability, fitness for a particular
+#       purpose, or non-infringement. This software could include
+#       technical inaccuracies or typographical errors. Changes are
+#       periodically made to the software; these changes will be
+#       incorporated in new editions of the software. DCLC may make
+#       improvements and/or changes in this software at any time
+#       without notice.
+#
+#     Limitation Of Liability 
+#
+#       In no event will DCLC be liable for direct, indirect, special,
+#       incidental, economic, cover, or consequential damages arising
+#       out of the use of or inability to use this software even if
+#       advised of the possibility of such damages. Some states do not
+#       allow the exclusion or limitation of implied warranties or
+#       limitation of liability for incidental or consequential
+#       damages, so the above limitation or exclusion may not apply to
+#       you.
+#  
+#
+# If you have questions regarding this software,
+# contact:
+#
+#   Jim Fulton, jim@digicool.com
+#
+#   (540) 371-6909
+#
+
 """\
 Pickling Algorithm
 ------------------
@@ -88,13 +141,13 @@
 
 To pickle an object x onto a file f, open for writing:
 
-	p = pickle.Pickler(f)
-	p.dump(x)
+    p = pickle.Pickler(f)
+    p.dump(x)
 
 To unpickle an object x from a file f, open for reading:
 
-	u = pickle.Unpickler(f)
-	x = u.load()
+    u = pickle.Unpickler(f)
+    x = u.load()
 
 The Pickler class only calls the method f.write with a string argument
 (XXX possibly the interface should pass f.write instead of f).
@@ -128,463 +181,768 @@
 I have no answers.  Garbage Collection may also become a problem here.)
 """
 
-__version__ = "1.6"			# Code version
+__version__ = "1.7"                     # Code version
 
 from types import *
-import string
+from copy_reg import *
+import string, marshal
 
-format_version = "1.1"			# File format version we write
-compatible_formats = ["1.0"]		# Old format versions we can read
+format_version = "1.2"                  # File format version we write
+compatible_formats = ["1.0", "1.1"]     # Old format versions we can read
+
+mdumps = marshal.dumps
+mloads = marshal.loads
 
 PicklingError = "pickle.PicklingError"
+UnpicklingError = "pickle.UnpicklingError"
 
-AtomicTypes = [NoneType, IntType, FloatType, StringType]
-
-def safe(object):
-	t = type(object)
-	if t in AtomicTypes:
-		return 1
-	if t is TupleType:
-		for item in object:
-			if not safe(item): return 0
-		return 1
-	return 0
-
-MARK = '('
-POP = '0'
-DUP = '2'
-STOP = '.'
-TUPLE = 't'
-LIST = 'l'
-DICT = 'd'
-INST = 'i'
-CLASS = 'c'
-GET = 'g'
-PUT = 'p'
-APPEND = 'a'
-SETITEM = 's'
-BUILD = 'b'
-NONE = 'N'
-INT = 'I'
-LONG = 'L'
-FLOAT = 'F'
-STRING = 'S'
-PERSID = 'P'
-AtomicKeys = [NONE, INT, LONG, FLOAT, STRING]
-AtomicMap = {
-	NoneType: NONE,
-	IntType: INT,
-	LongType: LONG,
-	FloatType: FLOAT,
-	StringType: STRING,
-}
+MARK            = '('
+STOP            = '.'
+POP             = '0'
+POP_MARK        = '1'
+DUP             = '2'
+FLOAT           = 'F'
+INT             = 'I'
+BININT          = 'J'
+BININT1         = 'K'
+LONG            = 'L'
+BININT2         = 'M'
+NONE            = 'N'
+PERSID          = 'P'
+BINPERSID       = 'Q'
+REDUCE          = 'R'
+STRING          = 'S'
+BINSTRING       = 'T'
+SHORT_BINSTRING = 'U'
+APPEND          = 'a'
+BUILD           = 'b'
+GLOBAL          = 'c'
+DICT            = 'd'
+EMPTY_DICT      = '}'
+APPENDS         = 'e'
+GET             = 'g'
+BINGET          = 'h'
+INST            = 'i'
+LONG_BINGET     = 'j'
+LIST            = 'l'
+EMPTY_LIST      = ']'
+OBJ             = 'o'
+PUT             = 'p'
+BINPUT          = 'q'
+LONG_BINPUT     = 'r'
+SETITEM         = 's'
+TUPLE           = 't'
+EMPTY_TUPLE     = ')'
+SETITEMS        = 'u'
 
 class Pickler:
 
-	def __init__(self, file):
-		self.write = file.write
-		self.memo = {}
+    def __init__(self, file, bin = 0):
+        self.write = file.write
+        self.memo = {}
+        self.bin = bin
 
-	def dump(self, object):
-		self.save(object)
-		self.write(STOP)
+    def dump(self, object):
+        self.save(object)
+        self.write(STOP)
 
-	def save(self, object):
-		pid = self.persistent_id(object)
-		if pid:
-			self.write(PERSID + str(pid) + '\n')
-			return
-		d = id(object)
-		if self.memo.has_key(d):
-			self.write(GET + `d` + '\n')
-			return
-		t = type(object)
-		try:
-			f = self.dispatch[t]
-		except KeyError:
-		        if hasattr(object, '__class__'):
-			        f = self.dispatch[InstanceType]
-			else:
-			        raise PicklingError, \
-				"can't pickle %s objects" % `t.__name__`
-		f(self, object)
+    def dump_special(self, callable, args, state = None):
+	if (type(args) is not TupleType):
+            raise PicklingError, "Second argument to dump_special " \
+                                 "must be a tuple"
 
-	def persistent_id(self, object):
-		return None
+        self.save_reduce(callable, args, state)
+        self.write(STOP)
 
-	dispatch = {}
+    def put(self, i):
+        if (self.bin):
+            s = mdumps(i)[1:]
+            if (i < 256):
+                return BINPUT + s[0]
 
-	def save_none(self, object):
-		self.write(NONE)
-	dispatch[NoneType] = save_none
+            return LONG_BINPUT + s
 
-	def save_int(self, object):
-		self.write(INT + `object` + '\n')
-	dispatch[IntType] = save_int
+        return PUT + `i` + '\n'
 
-	def save_long(self, object):
-		self.write(LONG + `object` + '\n')
-	dispatch[LongType] = save_long
+    def get(self, i):
+        if (self.bin):
+            s = mdumps(i)[1:]
 
-	def save_float(self, object):
-		self.write(FLOAT + `object` + '\n')
-	dispatch[FloatType] = save_float
+            if (i < 256):
+                return BINGET + s[0]
 
-	def save_string(self, object):
-		d = id(object)
-		self.write(STRING + `object` + '\n')
-		self.write(PUT + `d` + '\n')
-		self.memo[d] = object
-	dispatch[StringType] = save_string
+            return LONG_BINGET + s
 
-	def save_tuple(self, object):
-		d = id(object)
-		write = self.write
-		save = self.save
-		has_key = self.memo.has_key
-		write(MARK)
-		n = len(object)
-		for k in range(n):
-			save(object[k])
-			if has_key(d):
-				# Saving object[k] has saved us!
-				while k >= 0:
-					write(POP)
-					k = k-1
-				write(GET + `d` + '\n')
-				break
-		else:
-			write(TUPLE + PUT + `d` + '\n')
-			self.memo[d] = object
-	dispatch[TupleType] = save_tuple
+        return GET + `i` + '\n'
+        
+    def save(self, object, pers_save = 0):
+        memo = self.memo
 
-	def save_list(self, object):
-		d = id(object)
-		write = self.write
-		save = self.save
-		write(MARK)
-		n = len(object)
-		for k in range(n):
-			item = object[k]
-			if not safe(item):
-				break
-			save(item)
-		else:
-			k = n
-		write(LIST + PUT + `d` + '\n')
-		self.memo[d] = object
-		for k in range(k, n):
-			item = object[k]
-			save(item)
-			write(APPEND)
-	dispatch[ListType] = save_list
+        if (not pers_save):
+	    pid = self.persistent_id(object)
+	    if (pid is not None):
+                self.save_pers(pid)
+                return
 
-	def save_dict(self, object):
-		d = id(object)
-		write = self.write
-		save = self.save
-		write(MARK)
-		items = object.items()
-		n = len(items)
-		for k in range(n):
-			key, value = items[k]
-			if not safe(key) or not safe(value):
-				break
-			save(key)
-			save(value)
-		else:
-			k = n
-		self.write(DICT + PUT + `d` + '\n')
-		self.memo[d] = object
-		for k in range(k, n):
-			key, value = items[k]
-			save(key)
-			save(value)
-			write(SETITEM)
-	dispatch[DictionaryType] = save_dict
+        d = id(object)
+ 
+        t = type(object)
 
-	def save_inst(self, object):
-		d = id(object)
-		cls = object.__class__
-		write = self.write
-		save = self.save
-		module = whichmodule(cls)
-		name = cls.__name__
-		if hasattr(object, '__getinitargs__'):
-			args = object.__getinitargs__()
-			len(args) # XXX Assert it's a sequence
-		else:
-			args = ()
-		write(MARK)
-		for arg in args:
-			save(arg)
-		write(INST + module + '\n' + name + '\n' +
-		      PUT + `d` + '\n')
-		self.memo[d] = object
-		try:
-			getstate = object.__getstate__
-		except AttributeError:
-			stuff = object.__dict__
-		else:
-			stuff = getstate()
-		save(stuff)
-		write(BUILD)
-	dispatch[InstanceType] = save_inst
+	if ((t is TupleType) and (len(object) == 0)):
+	    if (self.bin):
+                self.save_empty_tuple(object)
+            else:
+                self.save_tuple(object)
+            return
 
-	def save_class(self, object):
-		d = id(object)
-		module = whichmodule(object)
-		name = object.__name__
-		self.write(CLASS + module + '\n' + name + '\n' + 
-			   PUT + `d` + '\n')
-	dispatch[ClassType] = save_class
+        if memo.has_key(d):
+            self.write(self.get(memo[d][0]))
+            return
+
+        try:
+            f = self.dispatch[t]
+        except KeyError:
+            pid = self.inst_persistent_id(object)
+            if pid is not None:
+                self.save_pers(pid)
+                return
+
+            try:
+                reduce = dispatch_table[t]
+            except KeyError:
+                try:
+                    reduce = object.__reduce__
+                except AttributeError:
+                    raise PicklingError, \
+                        "can't pickle %s objects" % `t.__name__`
+                else:
+                    tup = reduce()
+            else:
+                tup = reduce(object)
+
+            if (type(tup) is not TupleType):
+                raise PicklingError, "Value returned by %s must be a " \
+                                     "tuple" % reduce
+
+            l = len(tup)
+   
+	    if ((l != 2) and (l != 3)):
+                raise PicklingError, "tuple returned by %s must contain " \
+                                     "only two or three elements" % reduce
+
+            callable = tup[0]
+            arg_tup  = tup[1]
+          
+            if (l > 2):
+                state = tup[2]
+            else:
+                state = None
+
+            if (type(arg_tup) is not TupleType):
+                raise PicklingError, "Second element of tuple returned " \
+                                     "by %s must be a tuple" % reduce
+
+            self.save_reduce(callable, arg_tup, state) 
+            return
+
+        f(self, object)
+
+    def persistent_id(self, object):
+        return None
+
+    def inst_persistent_id(self, object):
+        return None
+
+    def save_pers(self, pid):
+        if (not self.bin):
+            self.write(PERSID + str(pid) + '\n')
+        else:
+            self.save(pid, 1)
+            self.write(BINPERSID)
+
+    def save_reduce(self, callable, arg_tup, state = None):
+        write = self.write
+        save = self.save
+
+        save(callable)
+        save(arg_tup)
+        write(REDUCE)
+        
+	if (state is not None):
+            save(state)
+            write(BUILD)
+
+    dispatch = {}
+
+    def save_none(self, object):
+        self.write(NONE)
+    dispatch[NoneType] = save_none
+
+    def save_int(self, object):
+        if (self.bin):
+            i = mdumps(object)[1:]
+            if (i[-2:] == '\000\000'):
+                if (i[-3] == '\000'):
+                    self.write(BININT1 + i[:-3])
+                    return
+
+                self.write(BININT2 + i[:-2])
+                return
+
+            self.write(BININT + i)
+        else:
+            self.write(INT + `object` + '\n')
+    dispatch[IntType] = save_int
+
+    def save_long(self, object):
+        self.write(LONG + `object` + '\n')
+    dispatch[LongType] = save_long
+
+    def save_float(self, object):
+        self.write(FLOAT + `object` + '\n')
+    dispatch[FloatType] = save_float
+
+    def save_string(self, object):
+        d = id(object)
+        memo = self.memo
+
+        if (self.bin):
+            l = len(object)
+            s = mdumps(l)[1:]
+            if (l < 256):
+                self.write(SHORT_BINSTRING + s[0] + object)
+            else:
+                self.write(BINSTRING + s + object)
+        else:
+            self.write(STRING + `object` + '\n')
+
+        memo_len = len(memo)
+        self.write(self.put(memo_len))
+        memo[d] = (memo_len, object)
+    dispatch[StringType] = save_string
+
+    def save_tuple(self, object):
+
+        write = self.write
+        save  = self.save
+        memo  = self.memo
+
+        d = id(object)
+
+        write(MARK)
+
+        for element in object:
+            save(element)
+
+        if (len(object) and memo.has_key(d)):
+	    if (self.bin):
+                write(POP_MARK + self.get(memo[d][0]))
+                return
+           
+            write(POP * (len(object) + 1) + self.get(mem[d][0]))
+            return
+
+        memo_len = len(memo)
+        self.write(TUPLE + self.put(memo_len))
+        memo[d] = (memo_len, object)
+    dispatch[TupleType] = save_tuple
+
+    def save_empty_tuple(self, object):
+        self.write(EMPTY_TUPLE)
+
+    def save_list(self, object):
+        d = id(object)
+
+        write = self.write
+        save  = self.save
+        memo  = self.memo
+
+	if (self.bin):
+            write(EMPTY_LIST)
+        else:
+            write(MARK + LIST)
+
+        memo_len = len(memo)
+        write(self.put(memo_len))
+        memo[d] = (memo_len, object)
+
+        using_appends = (self.bin and (len(object) > 1))
+
+        if (using_appends):
+            write(MARK)
+
+        for element in object:
+            save(element)
+  
+            if (not using_appends):
+                write(APPEND)
+
+        if (using_appends):
+            write(APPENDS)
+    dispatch[ListType] = save_list
+
+    def save_dict(self, object):
+        d = id(object)
+
+        write = self.write
+        save  = self.save
+        memo  = self.memo
+
+	if (self.bin):
+            write(EMPTY_DICT)
+        else:
+            write(MARK + DICT)
+
+        memo_len = len(memo)
+        self.write(self.put(memo_len))
+        memo[d] = (memo_len, object)
+
+        using_setitems = (self.bin and (len(object) > 1))
+
+        if (using_setitems):
+            write(MARK)
+
+        items = object.items()
+        for key, value in items:
+            save(key)
+            save(value)
+
+            if (not using_setitems):
+                write(SETITEM)
+
+        if (using_setitems):
+            write(SETITEMS)
+
+    dispatch[DictionaryType] = save_dict
+
+    def save_inst(self, object):
+        d = id(object)
+        cls = object.__class__
+
+        memo  = self.memo
+        write = self.write
+        save  = self.save
+
+        if hasattr(object, '__getinitargs__'):
+            args = object.__getinitargs__()
+            len(args) # XXX Assert it's a sequence
+        else:
+            args = ()
+
+        write(MARK)
+
+        if (self.bin):
+            save(cls)
+
+        for arg in args:
+            save(arg)
+
+        memo_len = len(memo)
+        if (self.bin):
+            write(OBJ + self.put(memo_len))
+        else:
+            module = whichmodule(cls, cls.__name__)
+            name = cls.__name__
+            write(INST + module + '\n' + name + '\n' +
+                self.put(memo_len))
+
+        memo[d] = (memo_len, object)
+
+        try:
+            getstate = object.__getstate__
+        except AttributeError:
+            stuff = object.__dict__
+        else:
+            stuff = getstate()
+        save(stuff)
+        write(BUILD)
+    dispatch[InstanceType] = save_inst
+
+    def save_global(self, object, name = None):
+        write = self.write
+        memo = self.memo
+
+        if (name is None):
+            name = object.__name__
+
+        module = whichmodule(object, name)
+
+        memo_len = len(memo)
+        write(GLOBAL + module + '\n' + name + '\n' +
+            self.put(memo_len))
+        memo[id(object)] = (memo_len, object)
+    dispatch[ClassType] = save_global
+    dispatch[FunctionType] = save_global
+    dispatch[BuiltinFunctionType] = save_global
 
 
 classmap = {}
 
-def whichmodule(cls):
-	"""Figure out the module in which a class occurs.
+def whichmodule(cls, clsname):
+    """Figure out the module in which a class occurs.
 
-	Search sys.modules for the module.
-	Cache in classmap.
-	Return a module name.
-	If the class cannot be found, return __main__.
-	"""
-	if classmap.has_key(cls):
-		return classmap[cls]
-	import sys
-	clsname = cls.__name__
-	for name, module in sys.modules.items():
-		if name != '__main__' and \
-		   hasattr(module, clsname) and \
-		   getattr(module, clsname) is cls:
-			break
-	else:
-		name = '__main__'
-	classmap[cls] = name
-	return name
+    Search sys.modules for the module.
+    Cache in classmap.
+    Return a module name.
+    If the class cannot be found, return __main__.
+    """
+    if classmap.has_key(cls):
+        return classmap[cls]
+    import sys
+
+    for name, module in sys.modules.items():
+        if hasattr(module, clsname) and \
+            getattr(module, clsname) is cls:
+            break
+    else:
+        name = '__main__'
+    classmap[cls] = name
+    return name
 
 
 class Unpickler:
 
-	def __init__(self, file):
-		self.readline = file.readline
-		self.read = file.read
-		self.memo = {}
+    def __init__(self, file):
+        self.readline = file.readline
+        self.read = file.read
+        self.memo = {}
 
-	def load(self):
-		self.mark = ['spam'] # Any new unique object
-		self.stack = []
-		self.append = self.stack.append
-		read = self.read
-		dispatch = self.dispatch
+    def load(self):
+        self.mark = ['spam'] # Any new unique object
+        self.stack = []
+        self.append = self.stack.append
+        read = self.read
+        dispatch = self.dispatch
+        try:
+            while 1:
+                key = read(1)
+                dispatch[key](self)
+        except STOP, value:
+            return value
+
+    def marker(self):
+        stack = self.stack
+        mark = self.mark
+        k = len(stack)-1
+        while stack[k] is not mark: k = k-1
+        return k
+
+    dispatch = {}
+
+    def load_eof(self):
+        raise EOFError
+    dispatch[''] = load_eof
+
+    def load_persid(self):
+        pid = self.readline()[:-1]
+        self.append(self.persistent_load(pid))
+    dispatch[PERSID] = load_persid
+
+    def load_binpersid(self):
+        stack = self.stack
+         
+        pid = stack[-1]
+        del stack[-1]
+
+        self.append(self.persistent_load(pid))
+    dispatch[BINPERSID] = load_binpersid
+
+    def load_none(self):
+        self.append(None)
+    dispatch[NONE] = load_none
+
+    def load_int(self):
+        self.append(string.atoi(self.readline()[:-1], 0))
+    dispatch[INT] = load_int
+
+    def load_binint(self):
+        self.append(mloads('i' + self.read(4)))
+    dispatch[BININT] = load_binint
+
+    def load_binint1(self):
+        self.append(mloads('i' + self.read(1) + '\000\000\000'))
+    dispatch[BININT1] = load_binint1
+
+    def load_binint2(self):
+        self.append(mloads('i' + self.read(2) + '\000\000'))
+    dispatch[BININT2] = load_binint2
+ 
+    def load_long(self):
+        self.append(string.atol(self.readline()[:-1], 0))
+    dispatch[LONG] = load_long
+
+    def load_float(self):
+        self.append(string.atof(self.readline()[:-1]))
+    dispatch[FLOAT] = load_float
+
+    def load_string(self):
+        self.append(eval(self.readline()[:-1],
+                         {'__builtins__': {}})) # Let's be careful
+    dispatch[STRING] = load_string
+
+    def load_binstring(self):
+        len = mloads('i' + self.read(4))
+        self.append(self.read(len))
+    dispatch[BINSTRING] = load_binstring
+
+    def load_short_binstring(self):
+        len = mloads('i' + self.read(1) + '\000\000\000')
+        self.append(self.read(len))
+    dispatch[SHORT_BINSTRING] = load_short_binstring
+
+    def load_tuple(self):
+        k = self.marker()
+        self.stack[k:] = [tuple(self.stack[k+1:])]
+    dispatch[TUPLE] = load_tuple
+
+    def load_empty_tuple(self):
+        self.stack.append(())
+    dispatch[EMPTY_TUPLE] = load_empty_tuple
+
+    def load_empty_list(self):
+        self.stack.append([])
+    dispatch[EMPTY_LIST] = load_empty_list
+
+    def load_empty_dictionary(self):
+        self.stack.append({})
+    dispatch[EMPTY_DICT] = load_empty_dictionary
+
+    def load_list(self):
+        k = self.marker()
+        self.stack[k:] = [self.stack[k+1:]]
+    dispatch[LIST] = load_list
+
+    def load_dict(self):
+        k = self.marker()
+        d = {}
+        items = self.stack[k+1:]
+        for i in range(0, len(items), 2):
+            key = items[i]
+            value = items[i+1]
+            d[key] = value
+        self.stack[k:] = [d]
+    dispatch[DICT] = load_dict
+
+    def load_inst(self):
+        k = self.marker()
+        args = tuple(self.stack[k+1:])
+        del self.stack[k:]
+        module = self.readline()[:-1]
+        name = self.readline()[:-1]
+        klass = self.find_class(module, name)
+	if (type(klass) is not ClassType):
+            raise SystemError, "Imported object %s from module %s is " \
+                               "not a class" % (name, module)
+
+        value = apply(klass, args)
+        self.append(value)
+    dispatch[INST] = load_inst
+
+    def load_obj(self):
+        stack = self.stack
+        k = self.marker()
+        klass = stack[k + 1]
+        del stack[k + 1]
+        args = tuple(stack[k + 1:]) 
+        del stack[k:]
+        value = apply(klass, args)
+        self.append(value)
+    dispatch[OBJ] = load_obj                
+
+    def load_global(self):
+        module = self.readline()[:-1]
+        name = self.readline()[:-1]
+        klass = self.find_class(module, name)
+        self.append(klass)
+    dispatch[GLOBAL] = load_global
+
+    def find_class(self, module, name):
+        env = {}
+
+        try:
+            exec 'from %s import %s' % (module, name) in env
+        except ImportError:
+            raise SystemError, \
+                  "Failed to import class %s from module %s" % \
+                  (name, module)
+        klass = env[name]
+        return klass
+
+    def load_reduce(self):
+        stack = self.stack
+
+        callable = stack[-2]
+        arg_tup  = stack[-1]
+	del stack[-2:]
+
+	if (type(callable) is not ClassType):
+	    if (not safe_constructors.has_key(callable)):
 		try:
-			while 1:
-				key = read(1)
-				dispatch[key](self)
-		except STOP, value:
-			return value
+                    safe = callable.__safe_for_unpickling__
+                except AttributeError:
+                    safe = None
 
-	def marker(self):
-	        stack = self.stack
-		mark = self.mark
-		k = len(stack)-1
-		while stack[k] is not mark: k = k-1
-		return k
+                if (not safe):
+                   raise UnpicklingError, "%s is not safe for " \
+                                          "unpickling" % callable
 
-	dispatch = {}
+        value = apply(callable, arg_tup)
+        self.append(value)
+    dispatch[REDUCE] = load_reduce
 
-	def load_eof(self):
-		raise EOFError
-	dispatch[''] = load_eof
+    def load_pop(self):
+        del self.stack[-1]
+    dispatch[POP] = load_pop
 
-	def load_persid(self):
-		pid = self.readline()[:-1]
-		self.append(self.persistent_load(pid))
-	dispatch[PERSID] = load_persid
+    def load_pop_mark(self):
+        k = self.marker()
+	del self.stack[k:]
+    dispatch[POP_MARK] = load_pop_mark
 
-	def load_none(self):
-		self.append(None)
-	dispatch[NONE] = load_none
+    def load_dup(self):
+        self.append(stack[-1])
+    dispatch[DUP] = load_dup
 
-	def load_int(self):
-		self.append(string.atoi(self.readline()[:-1], 0))
-	dispatch[INT] = load_int
+    def load_get(self):
+        self.append(self.memo[self.readline()[:-1]])
+    dispatch[GET] = load_get
 
-	def load_long(self):
-		self.append(string.atol(self.readline()[:-1], 0))
-	dispatch[LONG] = load_long
+    def load_binget(self):
+        i = mloads('i' + self.read(1) + '\000\000\000')
+        self.append(self.memo[`i`])
+    dispatch[BINGET] = load_binget
 
-	def load_float(self):
-		self.append(string.atof(self.readline()[:-1]))
-	dispatch[FLOAT] = load_float
+    def load_long_binget(self):
+        i = mloads('i' + self.read(4))
+        self.append(self.memo[`i`])
+    dispatch[LONG_BINGET] = load_long_binget
 
-	def load_string(self):
-		self.append(eval(self.readline()[:-1],
-				 {'__builtins__': {}})) # Let's be careful
-	dispatch[STRING] = load_string
+    def load_put(self):
+        self.memo[self.readline()[:-1]] = self.stack[-1]
+    dispatch[PUT] = load_put
 
-	def load_tuple(self):
-		k = self.marker()
-		self.stack[k:] = [tuple(self.stack[k+1:])]
-	dispatch[TUPLE] = load_tuple
+    def load_binput(self):
+        i = mloads('i' + self.read(1) + '\000\000\000')
+        self.memo[`i`] = self.stack[-1]
+    dispatch[BINPUT] = load_binput
 
-	def load_list(self):
-		k = self.marker()
-		self.stack[k:] = [self.stack[k+1:]]
-	dispatch[LIST] = load_list
+    def load_long_binput(self):
+        i = mloads('i' + self.read(4))
+        self.memo[`i`] = self.stack[-1]
+    dispatch[LONG_BINPUT] = load_long_binput
 
-	def load_dict(self):
-		k = self.marker()
-		d = {}
-		items = self.stack[k+1:]
-		for i in range(0, len(items), 2):
-			key = items[i]
-			value = items[i+1]
-			d[key] = value
-		self.stack[k:] = [d]
-	dispatch[DICT] = load_dict
+    def load_append(self):
+        stack = self.stack
+        value = stack[-1]
+        del stack[-1]
+        list = stack[-1]
+        list.append(value)
+    dispatch[APPEND] = load_append
 
-	def load_inst(self):
-		k = self.marker()
-		args = tuple(self.stack[k+1:])
-		del self.stack[k:]
-		module = self.readline()[:-1]
-		name = self.readline()[:-1]
-		klass = self.find_class(module, name)
-		value = apply(klass, args)
-		self.append(value)
-	dispatch[INST] = load_inst
+    def load_appends(self):
+        stack = self.stack
+        mark = self.marker()
+        list = stack[mark - 1]
+	for i in range(mark + 1, len(stack)):
+            list.append(stack[i])
 
-	def load_class(self):
-		module = self.readline()[:-1]
-		name = self.readline()[:-1]
-		klass = self.find_class(module, name)
-		self.append(klass)
-		return klass
-	dispatch[CLASS] = load_class
+        del stack[mark:]
+    dispatch[APPENDS] = load_appends
+           
+    def load_setitem(self):
+        stack = self.stack
+        value = stack[-1]
+        key = stack[-2]
+        del stack[-2:]
+        dict = stack[-1]
+        dict[key] = value
+    dispatch[SETITEM] = load_setitem
 
-	def find_class(self, module, name):
-		try:
-			klass = getattr(__import__(module), name)
-		except (ImportError, AttributeError):
-			raise SystemError, \
-			      "Failed to import class %s from module %s" % \
-			      (name, module)
-		if type(klass) is BuiltinFunctionType:
-			raise SystemError, \
-			 "Imported object %s from module %s is not a class" % \
-			 (name, module)
-		return klass
+    def load_setitems(self):
+        stack = self.stack
+        mark = self.marker()
+        dict = stack[mark - 1]
+	for i in range(mark + 1, len(stack), 2):
+            dict[stack[i]] = stack[i + 1]
 
-	def load_pop(self):
-		del self.stack[-1]
-	dispatch[POP] = load_pop
+        del stack[mark:]
+    dispatch[SETITEMS] = load_setitems
 
-	def load_dup(self):
-		self.append(stack[-1])
-	dispatch[DUP] = load_dup
+    def load_build(self):
+        stack = self.stack
+        value = stack[-1]
+        del stack[-1]
+        inst = stack[-1]
+        try:
+            setstate = inst.__setstate__
+        except AttributeError:
+            for key in value.keys():
+                setattr(inst, key, value[key])
+        else:
+            setstate(value)
+    dispatch[BUILD] = load_build
 
-	def load_get(self):
-		self.append(self.memo[self.readline()[:-1]])
-	dispatch[GET] = load_get
+    def load_mark(self):
+        self.append(self.mark)
+    dispatch[MARK] = load_mark
 
-	def load_put(self):
-		self.memo[self.readline()[:-1]] = self.stack[-1]
-	dispatch[PUT] = load_put
-
-	def load_append(self):
-	        stack = self.stack
-		value = stack[-1]
-		del stack[-1]
-		list = stack[-1]
-		list.append(value)
-	dispatch[APPEND] = load_append
-
-	def load_setitem(self):
-	        stack = self.stack
-		value = stack[-1]
-		key = stack[-2]
-		del stack[-2:]
-		dict = stack[-1]
-		dict[key] = value
-	dispatch[SETITEM] = load_setitem
-
-	def load_build(self):
-	        stack = self.stack
-		value = stack[-1]
-		del stack[-1]
-		inst = stack[-1]
-		try:
-			setstate = inst.__setstate__
-		except AttributeError:
-			for key in value.keys():
-				setattr(inst, key, value[key])
-		else:
-			setstate(value)
-	dispatch[BUILD] = load_build
-
-	def load_mark(self):
-		self.append(self.mark)
-	dispatch[MARK] = load_mark
-
-	def load_stop(self):
-		value = self.stack[-1]
-		del self.stack[-1]
-		raise STOP, value
-	dispatch[STOP] = load_stop
+    def load_stop(self):
+        value = self.stack[-1]
+        del self.stack[-1]
+        raise STOP, value
+    dispatch[STOP] = load_stop
 
 
 # Shorthands
 
 from StringIO import StringIO
 
-def dump(object, file):
-	Pickler(file).dump(object)
+def dump(object, file, bin = 0):
+    Pickler(file, bin).dump(object)
 
-def dumps(object):
-	file = StringIO()
-	Pickler(file).dump(object)
-	return file.getvalue()
+def dumps(object, bin = 0):
+    file = StringIO()
+    Pickler(file, bin).dump(object)
+    return file.getvalue()
 
 def load(file):
-	return Unpickler(file).load()
+    return Unpickler(file).load()
 
 def loads(str):
-	file = StringIO(str)
-	return Unpickler(file).load()
+    file = StringIO(str)
+    return Unpickler(file).load()
 
 
 # The rest is used for testing only
 
 class C:
-	def __cmp__(self, other):
-		return cmp(self.__dict__, other.__dict__)
+    def __cmp__(self, other):
+        return cmp(self.__dict__, other.__dict__)
 
 def test():
-	fn = 'pickle_tmp'
-	c = C()
-	c.foo = 1
-	c.bar = 2L
-	x = [0, 1, 2, 3]
-	y = ('abc', 'abc', c, c)
-	x.append(y)
-	x.append(y)
-	x.append(5)
-	f = open(fn, 'w')
-	F = Pickler(f)
-	F.dump(x)
-	f.close()
-	f = open(fn, 'r')
-	U = Unpickler(f)
-	x2 = U.load()
-	print x
-	print x2
-	print x == x2
-	print map(id, x)
-	print map(id, x2)
-	print F.memo
-	print U.memo
+    fn = 'out'
+    c = C()
+    c.foo = 1
+    c.bar = 2
+    x = [0, 1, 2, 3]
+    y = ('abc', 'abc', c, c)
+    x.append(y)
+    x.append(y)
+    x.append(5)
+    f = open(fn, 'w')
+    F = Pickler(f)
+    F.dump(x)
+    f.close()
+    f = open(fn, 'r')
+    U = Unpickler(f)
+    x2 = U.load()
+    print x
+    print x2
+    print x == x2
+    print map(id, x)
+    print map(id, x2)
+    print F.memo
+    print U.memo
 
 if __name__ == '__main__':
-	test()
+    test()