0001: /*
0002: * Copyright 1998 Finn Bock.
0003: *
0004: * This program contains material copyrighted by:
0005: * Copyright (c) 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
0006: * The Netherlands.
0007: */
0008:
0009: /* note about impl:
0010: instanceof vs. CPython type(.) is .
0011: */
0012:
0013: package org.python.modules;
0014:
0015: import java.util.*;
0016:
0017: import org.python.core.*;
0018: import org.python.core.imp;
0019:
0020: /**
0021: *
0022: * From the python documentation:
0023: * <p>
0024: * The <tt>cPickle.java</tt> module implements a basic but powerful algorithm
0025: * for ``pickling'' (a.k.a. serializing, marshalling or flattening) nearly
0026: * arbitrary Python objects. This is the act of converting objects to a
0027: * stream of bytes (and back: ``unpickling'').
0028: * This is a more primitive notion than
0029: * persistency -- although <tt>cPickle.java</tt> reads and writes file
0030: * objects, it does not handle the issue of naming persistent objects, nor
0031: * the (even more complicated) area of concurrent access to persistent
0032: * objects. The <tt>cPickle.java</tt> module can transform a complex object
0033: * into a byte stream and it can transform the byte stream into an object
0034: * with the same internal structure. The most obvious thing to do with these
0035: * byte streams is to write them onto a file, but it is also conceivable
0036: * to send them across a network or store them in a database. The module
0037: * <tt>shelve</tt> provides a simple interface to pickle and unpickle
0038: * objects on ``dbm''-style database files.
0039: * <P>
0040: * <b>Note:</b> The <tt>cPickle.java</tt> have the same interface as the
0041: * standard module <tt>pickle</tt>except that <tt>Pickler</tt> and
0042: * <tt>Unpickler</tt> are factory functions, not classes (so they cannot be
0043: * used as base classes for inheritance).
0044: * This limitation is similar for the original cPickle.c version.
0045: *
0046: * <P>
0047: * Unlike the built-in module <tt>marshal</tt>, <tt>cPickle.java</tt> handles
0048: * the following correctly:
0049: * <P>
0050: *
0051: * <UL><LI>recursive objects (objects containing references to themselves)
0052: *
0053: * <P>
0054: *
0055: * <LI>object sharing (references to the same object in different places)
0056: *
0057: * <P>
0058: *
0059: * <LI>user-defined classes and their instances
0060: *
0061: * <P>
0062: *
0063: * </UL>
0064: *
0065: * <P>
0066: * The data format used by <tt>cPickle.java</tt> is Python-specific. This has
0067: * the advantage that there are no restrictions imposed by external
0068: * standards such as XDR (which can't represent pointer sharing); however
0069: * it means that non-Python programs may not be able to reconstruct
0070: * pickled Python objects.
0071: *
0072: * <P>
0073: * By default, the <tt>cPickle.java</tt> data format uses a printable ASCII
0074: * representation. This is slightly more voluminous than a binary
0075: * representation. The big advantage of using printable ASCII (and of
0076: * some other characteristics of <tt>cPickle.java</tt>'s representation) is
0077: * that for debugging or recovery purposes it is possible for a human to read
0078: * the pickled file with a standard text editor.
0079: *
0080: * <P>
0081: * A binary format, which is slightly more efficient, can be chosen by
0082: * specifying a nonzero (true) value for the <i>bin</i> argument to the
0083: * <tt>Pickler</tt> constructor or the <tt>dump()</tt> and <tt>dumps()</tt>
0084: * functions. The binary format is not the default because of backwards
0085: * compatibility with the Python 1.4 pickle module. In a future version,
0086: * the default may change to binary.
0087: *
0088: * <P>
0089: * The <tt>cPickle.java</tt> module doesn't handle code objects.
0090: * <P>
0091: * For the benefit of persistency modules written using <tt>cPickle.java</tt>,
0092: * it supports the notion of a reference to an object outside the pickled
0093: * data stream. Such objects are referenced by a name, which is an
0094: * arbitrary string of printable ASCII characters. The resolution of
0095: * such names is not defined by the <tt>cPickle.java</tt> module -- the
0096: * persistent object module will have to implement a method
0097: * <tt>persistent_load()</tt>. To write references to persistent objects,
0098: * the persistent module must define a method <tt>persistent_id()</tt> which
0099: * returns either <tt>None</tt> or the persistent ID of the object.
0100: *
0101: * <P>
0102: * There are some restrictions on the pickling of class instances.
0103: *
0104: * <P>
0105: * First of all, the class must be defined at the top level in a module.
0106: * Furthermore, all its instance variables must be picklable.
0107: *
0108: * <P>
0109: *
0110: * <P>
0111: * When a pickled class instance is unpickled, its <tt>__init__()</tt> method
0112: * is normally <i>not</i> invoked. <b>Note:</b> This is a deviation
0113: * from previous versions of this module; the change was introduced in
0114: * Python 1.5b2. The reason for the change is that in many cases it is
0115: * desirable to have a constructor that requires arguments; it is a
0116: * (minor) nuisance to have to provide a <tt>__getinitargs__()</tt> method.
0117: *
0118: * <P>
0119: * If it is desirable that the <tt>__init__()</tt> method be called on
0120: * unpickling, a class can define a method <tt>__getinitargs__()</tt>,
0121: * which should return a <i>tuple</i> containing the arguments to be
0122: * passed to the class constructor (<tt>__init__()</tt>). This method is
0123: * called at pickle time; the tuple it returns is incorporated in the
0124: * pickle for the instance.
0125: * <P>
0126: * Classes can further influence how their instances are pickled -- if the
0127: * class defines the method <tt>__getstate__()</tt>, it is called and the
0128: * return state is pickled as the contents for the instance, and if the class
0129: * defines the method <tt>__setstate__()</tt>, it is called with the
0130: * unpickled state. (Note that these methods can also be used to
0131: * implement copying class instances.) If there is no
0132: * <tt>__getstate__()</tt> method, the instance's <tt>__dict__</tt> is
0133: * pickled. If there is no <tt>__setstate__()</tt> method, the pickled
0134: * object must be a dictionary and its items are assigned to the new
0135: * instance's dictionary. (If a class defines both <tt>__getstate__()</tt>
0136: * and <tt>__setstate__()</tt>, the state object needn't be a dictionary
0137: * -- these methods can do what they want.) This protocol is also used
0138: * by the shallow and deep copying operations defined in the <tt>copy</tt>
0139: * module.
0140: * <P>
0141: * Note that when class instances are pickled, their class's code and
0142: * data are not pickled along with them. Only the instance data are
0143: * pickled. This is done on purpose, so you can fix bugs in a class or
0144: * add methods and still load objects that were created with an earlier
0145: * version of the class. If you plan to have long-lived objects that
0146: * will see many versions of a class, it may be worthwhile to put a version
0147: * number in the objects so that suitable conversions can be made by the
0148: * class's <tt>__setstate__()</tt> method.
0149: *
0150: * <P>
0151: * When a class itself is pickled, only its name is pickled -- the class
0152: * definition is not pickled, but re-imported by the unpickling process.
0153: * Therefore, the restriction that the class must be defined at the top
0154: * level in a module applies to pickled classes as well.
0155: *
0156: * <P>
0157: *
0158: * <P>
0159: * The interface can be summarized as follows.
0160: *
0161: * <P>
0162: * To pickle an object <tt>x</tt> onto a file <tt>f</tt>, open for writing:
0163: *
0164: * <P>
0165: * <dl><dd><pre>
0166: * p = pickle.Pickler(f)
0167: * p.dump(x)
0168: * </pre></dl>
0169: *
0170: * <P>
0171: * A shorthand for this is:
0172: *
0173: * <P>
0174: * <dl><dd><pre>
0175: * pickle.dump(x, f)
0176: * </pre></dl>
0177: *
0178: * <P>
0179: * To unpickle an object <tt>x</tt> from a file <tt>f</tt>, open for reading:
0180: *
0181: * <P>
0182: * <dl><dd><pre>
0183: * u = pickle.Unpickler(f)
0184: * x = u.load()
0185: * </pre></dl>
0186: *
0187: * <P>
0188: * A shorthand is:
0189: *
0190: * <P>
0191: * <dl><dd><pre>
0192: * x = pickle.load(f)
0193: * </pre></dl>
0194: *
0195: * <P>
0196: * The <tt>Pickler</tt> class only calls the method <tt>f.write()</tt> with a
0197: * string argument. The <tt>Unpickler</tt> calls the methods
0198: * <tt>f.read()</tt> (with an integer argument) and <tt>f.readline()</tt>
0199: * (without argument), both returning a string. It is explicitly allowed to
0200: * pass non-file objects here, as long as they have the right methods.
0201: *
0202: * <P>
0203: * The constructor for the <tt>Pickler</tt> class has an optional second
0204: * argument, <i>bin</i>. If this is present and nonzero, the binary
0205: * pickle format is used; if it is zero or absent, the (less efficient,
0206: * but backwards compatible) text pickle format is used. The
0207: * <tt>Unpickler</tt> class does not have an argument to distinguish
0208: * between binary and text pickle formats; it accepts either format.
0209: *
0210: * <P>
0211: * The following types can be pickled:
0212: *
0213: * <UL><LI><tt>None</tt>
0214: *
0215: * <P>
0216: *
0217: * <LI>integers, long integers, floating point numbers
0218: *
0219: * <P>
0220: *
0221: * <LI>strings
0222: *
0223: * <P>
0224: *
0225: * <LI>tuples, lists and dictionaries containing only picklable objects
0226: *
0227: * <P>
0228: *
0229: * <LI>classes that are defined at the top level in a module
0230: *
0231: * <P>
0232: *
0233: * <LI>instances of such classes whose <tt>__dict__</tt> or
0234: * <tt>__setstate__()</tt> is picklable
0235: *
0236: * <P>
0237: *
0238: * </UL>
0239: *
0240: * <P>
0241: * Attempts to pickle unpicklable objects will raise the
0242: * <tt>PicklingError</tt> exception; when this happens, an unspecified
0243: * number of bytes may have been written to the file.
0244: *
0245: * <P>
0246: * It is possible to make multiple calls to the <tt>dump()</tt> method of
0247: * the same <tt>Pickler</tt> instance. These must then be matched to the
0248: * same number of calls to the <tt>load()</tt> method of the
0249: * corresponding <tt>Unpickler</tt> instance. If the same object is
0250: * pickled by multiple <tt>dump()</tt> calls, the <tt>load()</tt> will all
0251: * yield references to the same object. <i>Warning</i>: this is intended
0252: * for pickling multiple objects without intervening modifications to the
0253: * objects or their parts. If you modify an object and then pickle it
0254: * again using the same <tt>Pickler</tt> instance, the object is not
0255: * pickled again -- a reference to it is pickled and the
0256: * <tt>Unpickler</tt> will return the old value, not the modified one.
0257: * (There are two problems here: (a) detecting changes, and (b)
0258: * marshalling a minimal set of changes. I have no answers. Garbage
0259: * Collection may also become a problem here.)
0260: *
0261: * <P>
0262: * Apart from the <tt>Pickler</tt> and <tt>Unpickler</tt> classes, the
0263: * module defines the following functions, and an exception:
0264: *
0265: * <P>
0266: * <dl><dt><b><tt>dump</tt></a></b> (<var>object, file</var><big>[</big><var>,
0267: * bin</var><big>]</big>)
0268: * <dd>
0269: * Write a pickled representation of <i>obect</i> to the open file object
0270: * <i>file</i>. This is equivalent to
0271: * "<tt>Pickler(<i>file</i>, <i>bin</i>).dump(<i>object</i>)</tt>".
0272: * If the optional <i>bin</i> argument is present and nonzero, the binary
0273: * pickle format is used; if it is zero or absent, the (less efficient)
0274: * text pickle format is used.
0275: * </dl>
0276: *
0277: * <P>
0278: * <dl><dt><b><tt>load</tt></a></b> (<var>file</var>)
0279: * <dd>
0280: * Read a pickled object from the open file object <i>file</i>. This is
0281: * equivalent to "<tt>Unpickler(<i>file</i>).load()</tt>".
0282: * </dl>
0283: *
0284: * <P>
0285: * <dl><dt><b><tt>dumps</tt></a></b> (<var>object</var><big>[</big><var>,
0286: * bin</var><big>]</big>)
0287: * <dd>
0288: * Return the pickled representation of the object as a string, instead
0289: * of writing it to a file. If the optional <i>bin</i> argument is
0290: * present and nonzero, the binary pickle format is used; if it is zero
0291: * or absent, the (less efficient) text pickle format is used.
0292: * </dl>
0293: *
0294: * <P>
0295: * <dl><dt><b><tt>loads</tt></a></b> (<var>string</var>)
0296: * <dd>
0297: * Read a pickled object from a string instead of a file. Characters in
0298: * the string past the pickled object's representation are ignored.
0299: * </dl>
0300: *
0301: * <P>
0302: * <dl><dt><b><a name="l2h-3763"><tt>PicklingError</tt></a></b>
0303: * <dd>
0304: * This exception is raised when an unpicklable object is passed to
0305: * <tt>Pickler.dump()</tt>.
0306: * </dl>
0307: *
0308: *
0309: * <p>
0310: * For the complete documentation on the pickle module, please see the
0311: * "Python Library Reference"
0312: * <p><hr><p>
0313: *
0314: * The module is based on both original pickle.py and the cPickle.c
0315: * version, except that all mistakes and errors are my own.
0316: * <p>
0317: * @author Finn Bock, bckfnn@pipmail.dknet.dk
0318: * @version cPickle.java,v 1.30 1999/05/15 17:40:12 fb Exp
0319: */
0320: public class cPickle implements ClassDictInit {
0321: /**
0322: * The doc string
0323: */
0324: public static String __doc__ = "Java implementation and optimization of the Python pickle module\n"
0325: + "\n"
0326: + "$Id: cPickle.java 2945 2006-09-23 19:35:44Z cgroves $\n";
0327:
0328: /**
0329: * The program version.
0330: */
0331: public static String __version__ = "1.30";
0332:
0333: /**
0334: * File format version we write.
0335: */
0336: public static final String format_version = "1.3";
0337:
0338: /**
0339: * Old format versions we can read.
0340: */
0341: public static final String[] compatible_formats = new String[] {
0342: "1.0", "1.1", "1.2" };
0343:
0344: public static String[] __depends__ = new String[] { "copy_reg", };
0345:
0346: public static PyObject PickleError;
0347: public static PyObject PicklingError;
0348: public static PyObject UnpickleableError;
0349: public static PyObject UnpicklingError;
0350:
0351: public static final PyString BadPickleGet = new PyString(
0352: "cPickle.BadPickleGet");
0353:
0354: final static char MARK = '(';
0355: final static char STOP = '.';
0356: final static char POP = '0';
0357: final static char POP_MARK = '1';
0358: final static char DUP = '2';
0359: final static char FLOAT = 'F';
0360: final static char INT = 'I';
0361: final static char BININT = 'J';
0362: final static char BININT1 = 'K';
0363: final static char LONG = 'L';
0364: final static char BININT2 = 'M';
0365: final static char NONE = 'N';
0366: final static char PERSID = 'P';
0367: final static char BINPERSID = 'Q';
0368: final static char REDUCE = 'R';
0369: final static char STRING = 'S';
0370: final static char BINSTRING = 'T';
0371: final static char SHORT_BINSTRING = 'U';
0372: final static char UNICODE = 'V';
0373: final static char BINUNICODE = 'X';
0374: final static char APPEND = 'a';
0375: final static char BUILD = 'b';
0376: final static char GLOBAL = 'c';
0377: final static char DICT = 'd';
0378: final static char EMPTY_DICT = '}';
0379: final static char APPENDS = 'e';
0380: final static char GET = 'g';
0381: final static char BINGET = 'h';
0382: final static char INST = 'i';
0383: final static char LONG_BINGET = 'j';
0384: final static char LIST = 'l';
0385: final static char EMPTY_LIST = ']';
0386: final static char OBJ = 'o';
0387: final static char PUT = 'p';
0388: final static char BINPUT = 'q';
0389: final static char LONG_BINPUT = 'r';
0390: final static char SETITEM = 's';
0391: final static char TUPLE = 't';
0392: final static char EMPTY_TUPLE = ')';
0393: final static char SETITEMS = 'u';
0394: final static char BINFLOAT = 'G';
0395:
0396: private static PyDictionary dispatch_table = null;
0397: private static PyDictionary safe_constructors = null;
0398:
0399: private static PyType BuiltinFunctionType = PyType
0400: .fromClass(PyReflectedFunction.class);
0401: private static PyType BuiltinMethodType = PyType
0402: .fromClass(PyMethod.class);
0403: private static PyType ClassType = PyType.fromClass(PyClass.class);
0404: private static PyType TypeType = PyType.fromClass(PyType.class);
0405: private static PyType DictionaryType = PyType
0406: .fromClass(PyDictionary.class);
0407: private static PyType StringMapType = PyType
0408: .fromClass(PyStringMap.class);
0409: private static PyType FloatType = PyType.fromClass(PyFloat.class);
0410: private static PyType FunctionType = PyType
0411: .fromClass(PyFunction.class);
0412: private static PyType InstanceType = PyType
0413: .fromClass(PyInstance.class);
0414: private static PyType IntType = PyType.fromClass(PyInteger.class);
0415: private static PyType ListType = PyType.fromClass(PyList.class);
0416: private static PyType LongType = PyType.fromClass(PyLong.class);
0417: private static PyType NoneType = PyType.fromClass(PyNone.class);
0418: private static PyType StringType = PyType.fromClass(PyString.class);
0419: private static PyType TupleType = PyType.fromClass(PyTuple.class);
0420: private static PyType FileType = PyType.fromClass(PyFile.class);
0421:
0422: private static PyObject dict;
0423:
0424: /**
0425: * Initialization when module is imported.
0426: */
0427: public static void classDictInit(PyObject dict) {
0428: cPickle.dict = dict;
0429:
0430: // XXX: Hack for JPython 1.0.1. By default __builtin__ is not in
0431: // sys.modules.
0432: imp.importName("__builtin__", true);
0433:
0434: PyModule copyreg = (PyModule) importModule("copy_reg");
0435:
0436: dispatch_table = (PyDictionary) copyreg
0437: .__getattr__("dispatch_table");
0438: safe_constructors = (PyDictionary) copyreg
0439: .__getattr__("safe_constructors");
0440:
0441: PickleError = buildClass("PickleError", Py.Exception,
0442: "_PickleError", "");
0443: PicklingError = buildClass("PicklingError", PickleError,
0444: "_empty__init__", "");
0445: UnpickleableError = buildClass("UnpickleableError",
0446: PicklingError, "_UnpickleableError", "");
0447: UnpicklingError = buildClass("UnpicklingError", PickleError,
0448: "_empty__init__", "");
0449: }
0450:
0451: // An empty __init__ method
0452: public static PyObject _empty__init__(PyObject[] arg, String[] kws) {
0453: PyObject dict = new PyStringMap();
0454: dict.__setitem__("__module__", new PyString("cPickle"));
0455: return dict;
0456: }
0457:
0458: public static PyObject _PickleError(PyObject[] arg, String[] kws) {
0459: PyObject dict = _empty__init__(arg, kws);
0460: dict.__setitem__("__init__",
0461: getJavaFunc("_PickleError__init__"));
0462: dict.__setitem__("__str__", getJavaFunc("_PickleError__str__"));
0463: return dict;
0464: }
0465:
0466: public static void _PickleError__init__(PyObject[] arg, String[] kws) {
0467: ArgParser ap = new ArgParser("__init__", arg, kws, "self",
0468: "args");
0469: PyObject self = ap.getPyObject(0);
0470: PyObject args = ap.getList(1);
0471:
0472: self.__setattr__("args", args);
0473: }
0474:
0475: public static PyString _PickleError__str__(PyObject[] arg,
0476: String[] kws) {
0477: ArgParser ap = new ArgParser("__str__", arg, kws, "self");
0478: PyObject self = ap.getPyObject(0);
0479:
0480: PyObject args = self.__getattr__("args");
0481: if (args.__len__() > 0 && args.__getitem__(0).__len__() > 0)
0482: return args.__getitem__(0).__str__();
0483: else
0484: return new PyString("(what)");
0485: }
0486:
0487: public static PyObject _UnpickleableError(PyObject[] arg,
0488: String[] kws) {
0489: PyObject dict = _empty__init__(arg, kws);
0490: dict.__setitem__("__init__",
0491: getJavaFunc("_UnpickleableError__init__"));
0492: dict.__setitem__("__str__",
0493: getJavaFunc("_UnpickleableError__str__"));
0494: return dict;
0495: }
0496:
0497: public static void _UnpickleableError__init__(PyObject[] arg,
0498: String[] kws) {
0499: ArgParser ap = new ArgParser("__init__", arg, kws, "self",
0500: "args");
0501: PyObject self = ap.getPyObject(0);
0502: PyObject args = ap.getList(1);
0503:
0504: self.__setattr__("args", args);
0505: }
0506:
0507: public static PyString _UnpickleableError__str__(PyObject[] arg,
0508: String[] kws) {
0509: ArgParser ap = new ArgParser("__str__", arg, kws, "self");
0510: PyObject self = ap.getPyObject(0);
0511:
0512: PyObject args = self.__getattr__("args");
0513: PyObject a = args.__len__() > 0 ? args.__getitem__(0)
0514: : new PyString("(what)");
0515: return new PyString("Cannot pickle %s objects").__mod__(a)
0516: .__str__();
0517: }
0518:
0519: public cPickle() {
0520: }
0521:
0522: /**
0523: * Returns a pickler instance.
0524: * @param file a file-like object, can be a cStringIO.StringIO,
0525: * a PyFile or any python object which implements a
0526: * <i>write</i> method. The data will be written as text.
0527: * @returns a new Pickler instance.
0528: */
0529: public static Pickler Pickler(PyObject file) {
0530: return new Pickler(file, false);
0531: }
0532:
0533: /**
0534: * Returns a pickler instance.
0535: * @param file a file-like object, can be a cStringIO.StringIO,
0536: * a PyFile or any python object which implements a
0537: * <i>write</i> method.
0538: * @param bin when true, the output will be written as binary data.
0539: * @returns a new Pickler instance.
0540: */
0541: public static Pickler Pickler(PyObject file, boolean bin) {
0542: return new Pickler(file, bin);
0543: }
0544:
0545: /**
0546: * Returns a unpickler instance.
0547: * @param file a file-like object, can be a cStringIO.StringIO,
0548: * a PyFile or any python object which implements a
0549: * <i>read</i> and <i>readline</i> method.
0550: * @returns a new Unpickler instance.
0551: */
0552: public static Unpickler Unpickler(PyObject file) {
0553: return new Unpickler(file);
0554: }
0555:
0556: /**
0557: * Shorthand function which pickles the object on the file.
0558: * @param object a data object which should be pickled.
0559: * @param file a file-like object, can be a cStringIO.StringIO,
0560: * a PyFile or any python object which implements a
0561: * <i>write</i> method. The data will be written as
0562: * text.
0563: * @returns a new Unpickler instance.
0564: */
0565: public static void dump(PyObject object, PyObject file) {
0566: dump(object, file, false);
0567: }
0568:
0569: /**
0570: * Shorthand function which pickles the object on the file.
0571: * @param object a data object which should be pickled.
0572: * @param file a file-like object, can be a cStringIO.StringIO,
0573: * a PyFile or any python object which implements a
0574: * <i>write</i> method.
0575: * @param bin when true, the output will be written as binary data.
0576: * @returns a new Unpickler instance.
0577: */
0578: public static void dump(PyObject object, PyObject file, boolean bin) {
0579: new Pickler(file, bin).dump(object);
0580: }
0581:
0582: /**
0583: * Shorthand function which pickles and returns the string representation.
0584: * @param object a data object which should be pickled.
0585: * @returns a string representing the pickled object.
0586: */
0587: public static String dumps(PyObject object) {
0588: return dumps(object, false);
0589: }
0590:
0591: /**
0592: * Shorthand function which pickles and returns the string representation.
0593: * @param object a data object which should be pickled.
0594: * @param bin when true, the output will be written as binary data.
0595: * @returns a string representing the pickled object.
0596: */
0597: public static String dumps(PyObject object, boolean bin) {
0598: cStringIO.StringIO file = cStringIO.StringIO();
0599: dump(object, file, bin);
0600: return file.getvalue();
0601: }
0602:
0603: /**
0604: * Shorthand function which unpickles a object from the file and returns
0605: * the new object.
0606: * @param file a file-like object, can be a cStringIO.StringIO,
0607: * a PyFile or any python object which implements a
0608: * <i>read</i> and <i>readline</i> method.
0609: * @returns a new object.
0610: */
0611: public static Object load(PyObject file) {
0612: return new Unpickler(file).load();
0613: }
0614:
0615: /**
0616: * Shorthand function which unpickles a object from the string and
0617: * returns the new object.
0618: * @param str a strings which must contain a pickled object
0619: * representation.
0620: * @returns a new object.
0621: */
0622: public static Object loads(PyObject str) {
0623: cStringIO.StringIO file = cStringIO.StringIO(str.toString());
0624: return new Unpickler(file).load();
0625: }
0626:
0627: // Factory for creating IOFile representation.
0628: private static IOFile createIOFile(PyObject file) {
0629: Object f = file.__tojava__(cStringIO.StringIO.class);
0630: if (f != Py.NoConversion)
0631: return new cStringIOFile((cStringIO.StringIO) file);
0632: else if (__builtin__.isinstance(file, FileType))
0633: return new FileIOFile(file);
0634: else
0635: return new ObjectIOFile(file);
0636: }
0637:
0638: // IOFiles encapsulates and optimise access to the different file
0639: // representation.
0640: interface IOFile {
0641: public abstract void write(String str);
0642:
0643: // Usefull optimization since most data written are chars.
0644: public abstract void write(char str);
0645:
0646: public abstract void flush();
0647:
0648: public abstract String read(int len);
0649:
0650: // Usefull optimization since all readlines removes the
0651: // trainling newline.
0652: public abstract String readlineNoNl();
0653:
0654: }
0655:
0656: // Use a cStringIO as a file.
0657: static class cStringIOFile implements IOFile {
0658: cStringIO.StringIO file;
0659:
0660: cStringIOFile(PyObject file) {
0661: this .file = (cStringIO.StringIO) file
0662: .__tojava__(Object.class);
0663: }
0664:
0665: public void write(String str) {
0666: file.write(str);
0667: }
0668:
0669: public void write(char ch) {
0670: file.writeChar(ch);
0671: }
0672:
0673: public void flush() {
0674: }
0675:
0676: public String read(int len) {
0677: return file.read(len);
0678: }
0679:
0680: public String readlineNoNl() {
0681: return file.readlineNoNl();
0682: }
0683: }
0684:
0685: // Use a PyFile as a file.
0686: static class FileIOFile implements IOFile {
0687: PyFile file;
0688:
0689: FileIOFile(PyObject file) {
0690: this .file = (PyFile) file.__tojava__(PyFile.class);
0691: if (this .file.closed)
0692: throw Py.ValueError("I/O operation on closed file");
0693: }
0694:
0695: public void write(String str) {
0696: file.write(str);
0697: }
0698:
0699: public void write(char ch) {
0700: file.write(cStringIO.getString(ch));
0701: }
0702:
0703: public void flush() {
0704: }
0705:
0706: public String read(int len) {
0707: return file.read(len).toString();
0708: }
0709:
0710: public String readlineNoNl() {
0711: String line = file.readline().toString();
0712: return line.substring(0, line.length() - 1);
0713: }
0714: }
0715:
0716: // Use any python object as a file.
0717: static class ObjectIOFile implements IOFile {
0718: char[] charr = new char[1];
0719: StringBuffer buff = new StringBuffer();
0720: PyObject write;
0721: PyObject read;
0722: PyObject readline;
0723: final int BUF_SIZE = 256;
0724:
0725: ObjectIOFile(PyObject file) {
0726: // this.file = file;
0727: write = file.__findattr__("write");
0728: read = file.__findattr__("read");
0729: readline = file.__findattr__("readline");
0730: }
0731:
0732: public void write(String str) {
0733: buff.append(str);
0734: if (buff.length() > BUF_SIZE)
0735: flush();
0736: }
0737:
0738: public void write(char ch) {
0739: buff.append(ch);
0740: if (buff.length() > BUF_SIZE)
0741: flush();
0742: }
0743:
0744: public void flush() {
0745: write.__call__(new PyString(buff.toString()));
0746: buff.setLength(0);
0747: }
0748:
0749: public String read(int len) {
0750: return read.__call__(new PyInteger(len)).toString();
0751: }
0752:
0753: public String readlineNoNl() {
0754: String line = readline.__call__().toString();
0755: return line.substring(0, line.length() - 1);
0756: }
0757: }
0758:
0759: /**
0760: * The Pickler object
0761: * @see cPickle#Pickler(PyObject)
0762: * @see cPickle#Pickler(PyObject,boolean)
0763: */
0764: static public class Pickler {
0765: private IOFile file;
0766: private boolean bin;
0767:
0768: /**
0769: * The undocumented attribute fast of the C version of cPickle disables
0770: * memoization. Since having memoization on won't break anything, having
0771: * this dummy setter for fast here won't break any code expecting it to
0772: * do something. However without it code that sets fast fails(ie
0773: * test_cpickle.py), so it's worth having.
0774: */
0775: public boolean fast = false;
0776:
0777: /**
0778: * Hmm, not documented, perhaps it shouldn't be public? XXX: fixme.
0779: */
0780: private PickleMemo memo = new PickleMemo();
0781:
0782: /**
0783: * To write references to persistent objects, the persistent module
0784: * must assign a method to persistent_id which returns either None
0785: * or the persistent ID of the object.
0786: * For the benefit of persistency modules written using pickle,
0787: * it supports the notion of a reference to an object outside
0788: * the pickled data stream.
0789: * Such objects are referenced by a name, which is an arbitrary
0790: * string of printable ASCII characters.
0791: */
0792: public PyObject persistent_id = null;
0793:
0794: /**
0795: * Hmm, not documented, perhaps it shouldn't be public? XXX: fixme.
0796: */
0797: public PyObject inst_persistent_id = null;
0798:
0799: public Pickler(PyObject file, boolean bin) {
0800: this .file = createIOFile(file);
0801: this .bin = bin;
0802: }
0803:
0804: /**
0805: * Write a pickled representation of the object.
0806: * @param object The object which will be pickled.
0807: */
0808: public void dump(PyObject object) {
0809: save(object);
0810: file.write(STOP);
0811: file.flush();
0812: }
0813:
0814: private static final int get_id(PyObject o) {
0815: // we don't pickle Java instances so we don't have to consider that case
0816: return System.identityHashCode(o);
0817: }
0818:
0819: // Save name as in pickle.py but semantics are slightly changed.
0820: private void put(int i) {
0821: if (bin) {
0822: if (i < 256) {
0823: file.write(BINPUT);
0824: file.write((char) i);
0825: return;
0826: }
0827: file.write(LONG_BINPUT);
0828: file.write((char) (i & 0xFF));
0829: file.write((char) ((i >>> 8) & 0xFF));
0830: file.write((char) ((i >>> 16) & 0xFF));
0831: file.write((char) ((i >>> 24) & 0xFF));
0832: return;
0833: }
0834: file.write(PUT);
0835: file.write(String.valueOf(i));
0836: file.write("\n");
0837: }
0838:
0839: // Same name as in pickle.py but semantics are slightly changed.
0840: private void get(int i) {
0841: if (bin) {
0842: if (i < 256) {
0843: file.write(BINGET);
0844: file.write((char) i);
0845: return;
0846: }
0847: file.write(LONG_BINGET);
0848: file.write((char) (i & 0xFF));
0849: file.write((char) ((i >>> 8) & 0xFF));
0850: file.write((char) ((i >>> 16) & 0xFF));
0851: file.write((char) ((i >>> 24) & 0xFF));
0852: return;
0853: }
0854: file.write(GET);
0855: file.write(String.valueOf(i));
0856: file.write("\n");
0857: }
0858:
0859: private void save(PyObject object) {
0860: save(object, false);
0861: }
0862:
0863: private void save(PyObject object, boolean pers_save) {
0864: if (!pers_save) {
0865: if (persistent_id != null) {
0866: PyObject pid = persistent_id.__call__(object);
0867: if (pid != Py.None) {
0868: save_pers(pid);
0869: return;
0870: }
0871: }
0872: }
0873:
0874: int d = get_id(object);
0875:
0876: PyType t = object.getType();
0877:
0878: if (t == TupleType && object.__len__() == 0) {
0879: if (bin)
0880: save_empty_tuple(object);
0881: else
0882: save_tuple(object);
0883: return;
0884: }
0885:
0886: int m = getMemoPosition(d, object);
0887: if (m >= 0) {
0888: get(m);
0889: return;
0890: }
0891:
0892: if (save_type(object, t))
0893: return;
0894:
0895: if (inst_persistent_id != null) {
0896: PyObject pid = inst_persistent_id.__call__(object);
0897: if (pid != Py.None) {
0898: save_pers(pid);
0899: return;
0900: }
0901: }
0902:
0903: PyObject tup = null;
0904: PyObject reduce = dispatch_table.__finditem__(t);
0905: if (reduce == null) {
0906: reduce = object.__findattr__("__reduce__");
0907: if (reduce == null)
0908: throw new PyException(UnpickleableError, object);
0909: tup = reduce.__call__();
0910: } else {
0911: tup = reduce.__call__(object);
0912: }
0913:
0914: if (tup instanceof PyString) {
0915: save_global(object, tup);
0916: return;
0917: }
0918:
0919: if (!(tup instanceof PyTuple)) {
0920: throw new PyException(PicklingError,
0921: "Value returned by " + reduce.__repr__()
0922: + " must be a tuple");
0923: }
0924:
0925: int l = tup.__len__();
0926: if (l != 2 && l != 3) {
0927: throw new PyException(
0928: PicklingError,
0929: "tuple returned by "
0930: + reduce.__repr__()
0931: + " must contain only two or three elements");
0932: }
0933:
0934: PyObject callable = tup.__finditem__(0);
0935: PyObject arg_tup = tup.__finditem__(1);
0936: PyObject state = (l > 2) ? tup.__finditem__(2) : Py.None;
0937:
0938: if (!(arg_tup instanceof PyTuple) && arg_tup != Py.None) {
0939: throw new PyException(PicklingError,
0940: "Second element of tupe returned by "
0941: + reduce.__repr__()
0942: + " must be a tuple");
0943: }
0944:
0945: save_reduce(callable, arg_tup, state);
0946:
0947: put(putMemo(d, object));
0948: }
0949:
0950: final private void save_pers(PyObject pid) {
0951: if (!bin) {
0952: file.write(PERSID);
0953: file.write(pid.toString());
0954: file.write("\n");
0955: } else {
0956: save(pid, true);
0957: file.write(BINPERSID);
0958: }
0959: }
0960:
0961: final private void save_reduce(PyObject callable,
0962: PyObject arg_tup, PyObject state) {
0963: save(callable);
0964: save(arg_tup);
0965: file.write(REDUCE);
0966: if (state != Py.None) {
0967: save(state);
0968: file.write(BUILD);
0969: }
0970: }
0971:
0972: final private boolean save_type(PyObject object, PyType type) {
0973: //System.out.println("save_type " + object + " " + cls);
0974: if (type == NoneType)
0975: save_none(object);
0976: else if (type == StringType)
0977: save_string(object);
0978: else if (type == IntType)
0979: save_int(object);
0980: else if (type == LongType)
0981: save_long(object);
0982: else if (type == FloatType)
0983: save_float(object);
0984: else if (type == TupleType)
0985: save_tuple(object);
0986: else if (type == ListType)
0987: save_list(object);
0988: else if (type == DictionaryType || type == StringMapType)
0989: save_dict(object);
0990: else if (type == InstanceType)
0991: save_inst((PyInstance) object);
0992: else if (type == ClassType)
0993: save_global(object);
0994: else if (type == TypeType)
0995: save_global(object);
0996: else if (type == FunctionType)
0997: save_global(object);
0998: else if (type == BuiltinFunctionType)
0999: save_global(object);
1000: else
1001: return false;
1002: return true;
1003: }
1004:
1005: final private void save_none(PyObject object) {
1006: file.write(NONE);
1007: }
1008:
1009: final private void save_int(PyObject object) {
1010: if (bin) {
1011: int l = ((PyInteger) object).getValue();
1012: char i1 = (char) (l & 0xFF);
1013: char i2 = (char) ((l >>> 8) & 0xFF);
1014: char i3 = (char) ((l >>> 16) & 0xFF);
1015: char i4 = (char) ((l >>> 24) & 0xFF);
1016:
1017: if (i3 == '\0' && i4 == '\0') {
1018: if (i2 == '\0') {
1019: file.write(BININT1);
1020: file.write(i1);
1021: return;
1022: }
1023: file.write(BININT2);
1024: file.write(i1);
1025: file.write(i2);
1026: return;
1027: }
1028: file.write(BININT);
1029: file.write(i1);
1030: file.write(i2);
1031: file.write(i3);
1032: file.write(i4);
1033: } else {
1034: file.write(INT);
1035: file.write(object.toString());
1036: file.write("\n");
1037: }
1038: }
1039:
1040: final private void save_long(PyObject object) {
1041: file.write(LONG);
1042: file.write(object.toString());
1043: file.write("\n");
1044: }
1045:
1046: final private void save_float(PyObject object) {
1047: if (bin) {
1048: file.write(BINFLOAT);
1049: double value = ((PyFloat) object).getValue();
1050: // It seems that struct.pack('>d', ..) and doubleToLongBits
1051: // are the same. Good for me :-)
1052: long bits = Double.doubleToLongBits(value);
1053: file.write((char) ((bits >>> 56) & 0xFF));
1054: file.write((char) ((bits >>> 48) & 0xFF));
1055: file.write((char) ((bits >>> 40) & 0xFF));
1056: file.write((char) ((bits >>> 32) & 0xFF));
1057: file.write((char) ((bits >>> 24) & 0xFF));
1058: file.write((char) ((bits >>> 16) & 0xFF));
1059: file.write((char) ((bits >>> 8) & 0xFF));
1060: file.write((char) ((bits >>> 0) & 0xFF));
1061: } else {
1062: file.write(FLOAT);
1063: file.write(object.toString());
1064: file.write("\n");
1065: }
1066: }
1067:
1068: final private void save_string(PyObject object) {
1069: boolean unicode = ((PyString) object).isunicode();
1070: String str = object.toString();
1071:
1072: if (bin) {
1073: if (unicode)
1074: str = codecs.PyUnicode_EncodeUTF8(str, "struct");
1075: int l = str.length();
1076: if (l < 256 && !unicode) {
1077: file.write(SHORT_BINSTRING);
1078: file.write((char) l);
1079: } else {
1080: if (unicode)
1081: file.write(BINUNICODE);
1082: else
1083: file.write(BINSTRING);
1084: file.write((char) (l & 0xFF));
1085: file.write((char) ((l >>> 8) & 0xFF));
1086: file.write((char) ((l >>> 16) & 0xFF));
1087: file.write((char) ((l >>> 24) & 0xFF));
1088: }
1089: file.write(str);
1090: } else {
1091: if (unicode) {
1092: file.write(UNICODE);
1093: file.write(codecs.PyUnicode_EncodeRawUnicodeEscape(
1094: str, "strict", true));
1095: } else {
1096: file.write(STRING);
1097: file.write(object.__repr__().toString());
1098: }
1099: file.write("\n");
1100: }
1101: put(putMemo(get_id(object), object));
1102: }
1103:
1104: final private void save_tuple(PyObject object) {
1105: int d = get_id(object);
1106:
1107: file.write(MARK);
1108:
1109: int len = object.__len__();
1110:
1111: for (int i = 0; i < len; i++)
1112: save(object.__finditem__(i));
1113:
1114: if (len > 0) {
1115: int m = getMemoPosition(d, object);
1116: if (m >= 0) {
1117: if (bin) {
1118: file.write(POP_MARK);
1119: get(m);
1120: return;
1121: }
1122: for (int i = 0; i < len + 1; i++)
1123: file.write(POP);
1124: get(m);
1125: return;
1126: }
1127: }
1128: file.write(TUPLE);
1129: put(putMemo(d, object));
1130: }
1131:
1132: final private void save_empty_tuple(PyObject object) {
1133: file.write(EMPTY_TUPLE);
1134: }
1135:
1136: final private void save_list(PyObject object) {
1137: if (bin)
1138: file.write(EMPTY_LIST);
1139: else {
1140: file.write(MARK);
1141: file.write(LIST);
1142: }
1143:
1144: put(putMemo(get_id(object), object));
1145:
1146: int len = object.__len__();
1147: boolean using_appends = bin && len > 1;
1148:
1149: if (using_appends)
1150: file.write(MARK);
1151:
1152: for (int i = 0; i < len; i++) {
1153: save(object.__finditem__(i));
1154: if (!using_appends)
1155: file.write(APPEND);
1156: }
1157: if (using_appends)
1158: file.write(APPENDS);
1159: }
1160:
1161: final private void save_dict(PyObject object) {
1162: if (bin)
1163: file.write(EMPTY_DICT);
1164: else {
1165: file.write(MARK);
1166: file.write(DICT);
1167: }
1168:
1169: put(putMemo(get_id(object), object));
1170:
1171: PyObject list = object.invoke("keys");
1172: int len = list.__len__();
1173:
1174: boolean using_setitems = (bin && len > 1);
1175:
1176: if (using_setitems)
1177: file.write(MARK);
1178:
1179: for (int i = 0; i < len; i++) {
1180: PyObject key = list.__finditem__(i);
1181: PyObject value = object.__finditem__(key);
1182: save(key);
1183: save(value);
1184:
1185: if (!using_setitems)
1186: file.write(SETITEM);
1187: }
1188: if (using_setitems)
1189: file.write(SETITEMS);
1190: }
1191:
1192: final private void save_inst(PyInstance object) {
1193: if (object instanceof PyJavaInstance)
1194: throw new PyException(PicklingError,
1195: "Unable to pickle java objects.");
1196:
1197: PyClass cls = object.instclass;
1198:
1199: PySequence args = null;
1200: PyObject getinitargs = object
1201: .__findattr__("__getinitargs__");
1202: if (getinitargs != null) {
1203: args = (PySequence) getinitargs.__call__();
1204: // XXX Assert it's a sequence
1205: keep_alive(args);
1206: }
1207:
1208: file.write(MARK);
1209: if (bin)
1210: save(cls);
1211:
1212: if (args != null) {
1213: int len = args.__len__();
1214: for (int i = 0; i < len; i++)
1215: save(args.__finditem__(i));
1216: }
1217:
1218: int mid = putMemo(get_id(object), object);
1219: if (bin) {
1220: file.write(OBJ);
1221: put(mid);
1222: } else {
1223: file.write(INST);
1224: file.write(cls.__findattr__("__module__").toString());
1225: file.write("\n");
1226: file.write(cls.__name__);
1227: file.write("\n");
1228: put(mid);
1229: }
1230:
1231: PyObject stuff = null;
1232: PyObject getstate = object.__findattr__("__getstate__");
1233: if (getstate == null) {
1234: stuff = object.__dict__;
1235: } else {
1236: stuff = getstate.__call__();
1237: keep_alive(stuff);
1238: }
1239: save(stuff);
1240: file.write(BUILD);
1241: }
1242:
1243: final private void save_global(PyObject object) {
1244: save_global(object, null);
1245: }
1246:
1247: final private void save_global(PyObject object, PyObject name) {
1248: if (name == null)
1249: name = object.__findattr__("__name__");
1250:
1251: PyObject module = object.__findattr__("__module__");
1252: if (module == null || module == Py.None)
1253: module = whichmodule(object, name);
1254:
1255: file.write(GLOBAL);
1256: file.write(module.toString());
1257: file.write("\n");
1258: file.write(name.toString());
1259: file.write("\n");
1260: put(putMemo(get_id(object), object));
1261: }
1262:
1263: final private int getMemoPosition(int id, Object o) {
1264: return memo.findPosition(id, o);
1265: }
1266:
1267: final private int putMemo(int id, PyObject object) {
1268: int memo_len = memo.size() + 1;
1269: memo.put(id, memo_len, object);
1270: return memo_len;
1271: }
1272:
1273: /**
1274: * Keeps a reference to the object x in the memo.
1275: *
1276: * Because we remember objects by their id, we have
1277: * to assure that possibly temporary objects are kept
1278: * alive by referencing them.
1279: * We store a reference at the id of the memo, which should
1280: * normally not be used unless someone tries to deepcopy
1281: * the memo itself...
1282: */
1283: final private void keep_alive(PyObject obj) {
1284: int id = System.identityHashCode(memo);
1285: PyList list = (PyList) memo.findValue(id, memo);
1286: if (list == null) {
1287: list = new PyList();
1288: memo.put(id, -1, list);
1289: }
1290: list.append(obj);
1291: }
1292:
1293: }
1294:
1295: private static Hashtable classmap = new Hashtable();
1296:
1297: final private static PyObject whichmodule(PyObject cls,
1298: PyObject clsname) {
1299: PyObject name = (PyObject) classmap.get(cls);
1300: if (name != null)
1301: return name;
1302:
1303: name = new PyString("__main__");
1304:
1305: // For use with JPython1.0.x
1306: //PyObject modules = sys.modules;
1307:
1308: // For use with JPython1.1.x
1309: //PyObject modules = Py.getSystemState().modules;
1310:
1311: PyObject sys = imp.importName("sys", true);
1312: PyObject modules = sys.__findattr__("modules");
1313: PyObject keylist = modules.invoke("keys");
1314:
1315: int len = keylist.__len__();
1316: for (int i = 0; i < len; i++) {
1317: PyObject key = keylist.__finditem__(i);
1318: PyObject value = modules.__finditem__(key);
1319:
1320: if (!key.equals("__main__")
1321: && value.__findattr__(clsname.toString().intern()) == cls) {
1322: name = key;
1323: break;
1324: }
1325: }
1326:
1327: classmap.put(cls, name);
1328: //System.out.println(name);
1329: return name;
1330: }
1331:
1332: /*
1333: * A very specialized and simplified version of PyStringMap. It can
1334: * only use integers as keys and stores both an integer and an object
1335: * as value. It is very private!
1336: */
1337: static private class PickleMemo {
1338: //Table of primes to cycle through
1339: private final int[] primes = { 13, 61, 251, 1021, 4093, 5987,
1340: 9551, 15683, 19609, 31397, 65521, 131071, 262139,
1341: 524287, 1048573, 2097143, 4194301, 8388593, 16777213,
1342: 33554393, 67108859, 134217689, 268435399, 536870909,
1343: 1073741789, };
1344:
1345: private transient int[] keys;
1346: private transient int[] position;
1347: private transient Object[] values;
1348:
1349: private int size;
1350: private transient int filled;
1351: private transient int prime;
1352:
1353: public PickleMemo(int capacity) {
1354: prime = 0;
1355: keys = null;
1356: values = null;
1357: resize(capacity);
1358: }
1359:
1360: public PickleMemo() {
1361: this (4);
1362: }
1363:
1364: public synchronized int size() {
1365: return size;
1366: }
1367:
1368: private int findIndex(int key, Object value) {
1369: int[] table = keys;
1370: int maxindex = table.length;
1371: int index = (key & 0x7fffffff) % maxindex;
1372:
1373: // Fairly aribtrary choice for stepsize...
1374: int stepsize = maxindex / 5;
1375:
1376: // Cycle through possible positions for the key;
1377: //int collisions = 0;
1378: while (true) {
1379: int tkey = table[index];
1380: if (tkey == key && value == values[index]) {
1381: return index;
1382: }
1383: if (values[index] == null)
1384: return -1;
1385: index = (index + stepsize) % maxindex;
1386: }
1387: }
1388:
1389: public int findPosition(int key, Object value) {
1390: int idx = findIndex(key, value);
1391: if (idx < 0)
1392: return -1;
1393: return position[idx];
1394: }
1395:
1396: public Object findValue(int key, Object value) {
1397: int idx = findIndex(key, value);
1398: if (idx < 0)
1399: return null;
1400: return values[idx];
1401: }
1402:
1403: private final void insertkey(int key, int pos, Object value) {
1404: int[] table = keys;
1405: int maxindex = table.length;
1406: int index = (key & 0x7fffffff) % maxindex;
1407:
1408: // Fairly aribtrary choice for stepsize...
1409: int stepsize = maxindex / 5;
1410:
1411: // Cycle through possible positions for the key;
1412: while (true) {
1413: int tkey = table[index];
1414: if (values[index] == null) {
1415: table[index] = key;
1416: position[index] = pos;
1417: values[index] = value;
1418: filled++;
1419: size++;
1420: break;
1421: } else if (tkey == key && values[index] == value) {
1422: position[index] = pos;
1423: break;
1424: }
1425: index = (index + stepsize) % maxindex;
1426: }
1427: }
1428:
1429: private synchronized final void resize(int capacity) {
1430: int p = prime;
1431: for (; p < primes.length; p++) {
1432: if (primes[p] >= capacity)
1433: break;
1434: }
1435: if (primes[p] < capacity) {
1436: throw Py.ValueError("can't make hashtable of size: "
1437: + capacity);
1438: }
1439: capacity = primes[p];
1440: prime = p;
1441:
1442: int[] oldKeys = keys;
1443: int[] oldPositions = position;
1444: Object[] oldValues = values;
1445:
1446: keys = new int[capacity];
1447: position = new int[capacity];
1448: values = new Object[capacity];
1449: size = 0;
1450: filled = 0;
1451:
1452: if (oldValues != null) {
1453: int n = oldValues.length;
1454:
1455: for (int i = 0; i < n; i++) {
1456: Object value = oldValues[i];
1457: if (value == null)
1458: continue;
1459: insertkey(oldKeys[i], oldPositions[i], value);
1460: }
1461: }
1462: }
1463:
1464: public void put(int key, int pos, Object value) {
1465: if (2 * filled > keys.length)
1466: resize(keys.length + 1);
1467: insertkey(key, pos, value);
1468: }
1469: }
1470:
1471: /**
1472: * The Unpickler object. Unpickler instances are create by the factory
1473: * methods Unpickler.
1474: * @see cPickle#Unpickler(PyObject)
1475: */
1476: static public class Unpickler {
1477:
1478: private IOFile file;
1479:
1480: public Hashtable memo = new Hashtable();
1481:
1482: /**
1483: * For the benefit of persistency modules written using pickle,
1484: * it supports the notion of a reference to an object outside
1485: * the pickled data stream.
1486: * Such objects are referenced by a name, which is an arbitrary
1487: * string of printable ASCII characters.
1488: * The resolution of such names is not defined by the pickle module
1489: * -- the persistent object module will have to add a method
1490: * persistent_load().
1491: */
1492: public PyObject persistent_load = null;
1493:
1494: private PyObject mark = new PyString("spam");
1495:
1496: private int stackTop;
1497: private PyObject[] stack;
1498:
1499: Unpickler(PyObject file) {
1500: this .file = createIOFile(file);
1501: }
1502:
1503: /**
1504: * Unpickle and return an instance of the object represented by
1505: * the file.
1506: */
1507: public PyObject load() {
1508: stackTop = 0;
1509: stack = new PyObject[10];
1510:
1511: while (true) {
1512: String s = file.read(1);
1513: // System.out.println("load:" + s);
1514: // for (int i = 0; i < stackTop; i++)
1515: // System.out.println(" " + stack[i]);
1516: if (s.length() < 1)
1517: load_eof();
1518: char key = s.charAt(0);
1519: switch (key) {
1520: case PERSID:
1521: load_persid();
1522: break;
1523: case BINPERSID:
1524: load_binpersid();
1525: break;
1526: case NONE:
1527: load_none();
1528: break;
1529: case INT:
1530: load_int();
1531: break;
1532: case BININT:
1533: load_binint();
1534: break;
1535: case BININT1:
1536: load_binint1();
1537: break;
1538: case BININT2:
1539: load_binint2();
1540: break;
1541: case LONG:
1542: load_long();
1543: break;
1544: case FLOAT:
1545: load_float();
1546: break;
1547: case BINFLOAT:
1548: load_binfloat();
1549: break;
1550: case STRING:
1551: load_string();
1552: break;
1553: case BINSTRING:
1554: load_binstring();
1555: break;
1556: case SHORT_BINSTRING:
1557: load_short_binstring();
1558: break;
1559: case UNICODE:
1560: load_unicode();
1561: break;
1562: case BINUNICODE:
1563: load_binunicode();
1564: break;
1565: case TUPLE:
1566: load_tuple();
1567: break;
1568: case EMPTY_TUPLE:
1569: load_empty_tuple();
1570: break;
1571: case EMPTY_LIST:
1572: load_empty_list();
1573: break;
1574: case EMPTY_DICT:
1575: load_empty_dictionary();
1576: break;
1577: case LIST:
1578: load_list();
1579: break;
1580: case DICT:
1581: load_dict();
1582: break;
1583: case INST:
1584: load_inst();
1585: break;
1586: case OBJ:
1587: load_obj();
1588: break;
1589: case GLOBAL:
1590: load_global();
1591: break;
1592: case REDUCE:
1593: load_reduce();
1594: break;
1595: case POP:
1596: load_pop();
1597: break;
1598: case POP_MARK:
1599: load_pop_mark();
1600: break;
1601: case DUP:
1602: load_dup();
1603: break;
1604: case GET:
1605: load_get();
1606: break;
1607: case BINGET:
1608: load_binget();
1609: break;
1610: case LONG_BINGET:
1611: load_long_binget();
1612: break;
1613: case PUT:
1614: load_put();
1615: break;
1616: case BINPUT:
1617: load_binput();
1618: break;
1619: case LONG_BINPUT:
1620: load_long_binput();
1621: break;
1622: case APPEND:
1623: load_append();
1624: break;
1625: case APPENDS:
1626: load_appends();
1627: break;
1628: case SETITEM:
1629: load_setitem();
1630: break;
1631: case SETITEMS:
1632: load_setitems();
1633: break;
1634: case BUILD:
1635: load_build();
1636: break;
1637: case MARK:
1638: load_mark();
1639: break;
1640: case STOP:
1641: return load_stop();
1642: }
1643: }
1644: }
1645:
1646: final private int marker() {
1647: for (int k = stackTop - 1; k >= 0; k--)
1648: if (stack[k] == mark)
1649: return stackTop - k - 1;
1650: throw new PyException(UnpicklingError,
1651: "Inputstream corrupt, marker not found");
1652: }
1653:
1654: final private void load_eof() {
1655: throw new PyException(Py.EOFError);
1656: }
1657:
1658: final private void load_persid() {
1659: String pid = file.readlineNoNl();
1660: push(persistent_load.__call__(new PyString(pid)));
1661: }
1662:
1663: final private void load_binpersid() {
1664: PyObject pid = pop();
1665: push(persistent_load.__call__(pid));
1666: }
1667:
1668: final private void load_none() {
1669: push(Py.None);
1670: }
1671:
1672: final private void load_int() {
1673: String line = file.readlineNoNl();
1674: PyObject value;
1675: // The following could be abstracted into a common string
1676: // -> int/long method.
1677: try {
1678: value = Py.newInteger(Integer.parseInt(line));
1679: } catch (NumberFormatException e) {
1680: try {
1681: value = Py.newLong(line);
1682: } catch (NumberFormatException e2) {
1683: throw Py
1684: .ValueError("could not convert string to int");
1685: }
1686: }
1687: push(value);
1688: }
1689:
1690: final private void load_binint() {
1691: String s = file.read(4);
1692: int x = s.charAt(0) | (s.charAt(1) << 8)
1693: | (s.charAt(2) << 16) | (s.charAt(3) << 24);
1694: push(new PyInteger(x));
1695: }
1696:
1697: final private void load_binint1() {
1698: int val = (int) file.read(1).charAt(0);
1699: push(new PyInteger(val));
1700: }
1701:
1702: final private void load_binint2() {
1703: String s = file.read(2);
1704: int val = ((int) s.charAt(1)) << 8 | ((int) s.charAt(0));
1705: push(new PyInteger(val));
1706: }
1707:
1708: final private void load_long() {
1709: String line = file.readlineNoNl();
1710: push(new PyLong(line.substring(0, line.length() - 1)));
1711: }
1712:
1713: final private void load_float() {
1714: String line = file.readlineNoNl();
1715: push(new PyFloat(Double.valueOf(line).doubleValue()));
1716: }
1717:
1718: final private void load_binfloat() {
1719: String s = file.read(8);
1720: long bits = (long) s.charAt(7) | ((long) s.charAt(6) << 8)
1721: | ((long) s.charAt(5) << 16)
1722: | ((long) s.charAt(4) << 24)
1723: | ((long) s.charAt(3) << 32)
1724: | ((long) s.charAt(2) << 40)
1725: | ((long) s.charAt(1) << 48)
1726: | ((long) s.charAt(0) << 56);
1727: push(new PyFloat(Double.longBitsToDouble(bits)));
1728: }
1729:
1730: final private void load_string() {
1731: String line = file.readlineNoNl();
1732:
1733: String value;
1734: char quote = line.charAt(0);
1735: if (quote != '"' && quote != '\'')
1736: throw Py.ValueError("insecure string pickle");
1737:
1738: int nslash = 0;
1739: int i;
1740: char ch = '\0';
1741: int n = line.length();
1742: for (i = 1; i < n; i++) {
1743: ch = line.charAt(i);
1744: if (ch == quote && nslash % 2 == 0)
1745: break;
1746: if (ch == '\\')
1747: nslash++;
1748: else
1749: nslash = 0;
1750: }
1751: if (ch != quote)
1752: throw Py.ValueError("insecure string pickle");
1753:
1754: for (i++; i < line.length(); i++) {
1755: if (line.charAt(i) > ' ')
1756: throw Py.ValueError("insecure string pickle " + i);
1757: }
1758: value = PyString.decode_UnicodeEscape(line, 1, n - 1,
1759: "strict", false);
1760:
1761: push(new PyString(value));
1762: }
1763:
1764: final private void load_binstring() {
1765: String d = file.read(4);
1766: int len = d.charAt(0) | (d.charAt(1) << 8)
1767: | (d.charAt(2) << 16) | (d.charAt(3) << 24);
1768: push(new PyString(file.read(len)));
1769: }
1770:
1771: final private void load_short_binstring() {
1772: int len = (int) file.read(1).charAt(0);
1773: push(new PyString(file.read(len)));
1774: }
1775:
1776: final private void load_unicode() {
1777: String line = file.readlineNoNl();
1778: int n = line.length();
1779: String value = codecs.PyUnicode_DecodeRawUnicodeEscape(
1780: line, "strict");
1781: push(new PyString(value));
1782: }
1783:
1784: final private void load_binunicode() {
1785: String d = file.read(4);
1786: int len = d.charAt(0) | (d.charAt(1) << 8)
1787: | (d.charAt(2) << 16) | (d.charAt(3) << 24);
1788: String line = file.read(len);
1789: push(new PyString(codecs.PyUnicode_DecodeUTF8(line,
1790: "strict")));
1791: }
1792:
1793: final private void load_tuple() {
1794: PyObject[] arr = new PyObject[marker()];
1795: pop(arr);
1796: pop();
1797: push(new PyTuple(arr));
1798: }
1799:
1800: final private void load_empty_tuple() {
1801: push(new PyTuple(Py.EmptyObjects));
1802: }
1803:
1804: final private void load_empty_list() {
1805: push(new PyList(Py.EmptyObjects));
1806: }
1807:
1808: final private void load_empty_dictionary() {
1809: push(new PyDictionary());
1810: }
1811:
1812: final private void load_list() {
1813: PyObject[] arr = new PyObject[marker()];
1814: pop(arr);
1815: pop();
1816: push(new PyList(arr));
1817: }
1818:
1819: final private void load_dict() {
1820: int k = marker();
1821: PyDictionary d = new PyDictionary();
1822: for (int i = 0; i < k; i += 2) {
1823: PyObject value = pop();
1824: PyObject key = pop();
1825: d.__setitem__(key, value);
1826: }
1827: pop();
1828: push(d);
1829: }
1830:
1831: final private void load_inst() {
1832: PyObject[] args = new PyObject[marker()];
1833: pop(args);
1834: pop();
1835:
1836: String module = file.readlineNoNl();
1837: String name = file.readlineNoNl();
1838: PyObject klass = find_class(module, name);
1839:
1840: PyObject value = null;
1841: if (args.length == 0 && klass instanceof PyClass
1842: && klass.__findattr__("__getinitargs__") == null) {
1843: value = new PyInstance((PyClass) klass);
1844: } else {
1845: value = klass.__call__(args);
1846: }
1847: push(value);
1848: }
1849:
1850: final private void load_obj() {
1851: PyObject[] args = new PyObject[marker() - 1];
1852: pop(args);
1853: PyObject klass = pop();
1854: pop();
1855:
1856: PyObject value = null;
1857: if (args.length == 0 && klass instanceof PyClass
1858: && klass.__findattr__("__getinitargs__") == null) {
1859: value = new PyInstance((PyClass) klass);
1860: } else {
1861: value = klass.__call__(args);
1862: }
1863: push(value);
1864: }
1865:
1866: final private void load_global() {
1867: String module = file.readlineNoNl();
1868: String name = file.readlineNoNl();
1869: PyObject klass = find_class(module, name);
1870: push(klass);
1871: }
1872:
1873: final private PyObject find_class(String module, String name) {
1874: PyObject fc = dict.__finditem__("find_global");
1875: if (fc != null) {
1876: if (fc == Py.None)
1877: throw new PyException(UnpicklingError,
1878: "Global and instance pickles are not supported.");
1879: return fc.__call__(new PyString(module), new PyString(
1880: name));
1881: }
1882:
1883: PyObject modules = Py.getSystemState().modules;
1884: PyObject mod = modules.__finditem__(module.intern());
1885: if (mod == null) {
1886: mod = importModule(module);
1887: }
1888: PyObject global = mod.__findattr__(name.intern());
1889: if (global == null) {
1890: throw new PyException(Py.SystemError,
1891: "Failed to import class " + name
1892: + " from module " + module);
1893: }
1894: return global;
1895: }
1896:
1897: final private void load_reduce() {
1898: PyObject arg_tup = pop();
1899: PyObject callable = pop();
1900: if (!((callable instanceof PyClass) || (callable instanceof PyType))) {
1901: if (safe_constructors.__finditem__(callable) == null) {
1902: if (callable
1903: .__findattr__("__safe_for_unpickling__") == null)
1904: throw new PyException(UnpicklingError, callable
1905: + " is not safe for unpickling");
1906: }
1907: }
1908:
1909: PyObject value = null;
1910: if (arg_tup == Py.None) {
1911: // XXX __basicnew__ ?
1912: value = callable.__findattr__("__basicnew__")
1913: .__call__();
1914: } else {
1915: value = callable.__call__(make_array(arg_tup));
1916: }
1917: push(value);
1918: }
1919:
1920: final private PyObject[] make_array(PyObject seq) {
1921: int n = seq.__len__();
1922: PyObject[] objs = new PyObject[n];
1923:
1924: for (int i = 0; i < n; i++)
1925: objs[i] = seq.__finditem__(i);
1926: return objs;
1927: }
1928:
1929: final private void load_pop() {
1930: pop();
1931: }
1932:
1933: final private void load_pop_mark() {
1934: pop(marker());
1935: }
1936:
1937: final private void load_dup() {
1938: push(peek());
1939: }
1940:
1941: final private void load_get() {
1942: String py_str = file.readlineNoNl();
1943: PyObject value = (PyObject) memo.get(py_str);
1944: if (value == null)
1945: throw new PyException(BadPickleGet, py_str);
1946: push(value);
1947: }
1948:
1949: final private void load_binget() {
1950: String py_key = String
1951: .valueOf((int) file.read(1).charAt(0));
1952: PyObject value = (PyObject) memo.get(py_key);
1953: if (value == null)
1954: throw new PyException(BadPickleGet, py_key);
1955: push(value);
1956: }
1957:
1958: final private void load_long_binget() {
1959: String d = file.read(4);
1960: int i = d.charAt(0) | (d.charAt(1) << 8)
1961: | (d.charAt(2) << 16) | (d.charAt(3) << 24);
1962: String py_key = String.valueOf(i);
1963: PyObject value = (PyObject) memo.get(py_key);
1964: if (value == null)
1965: throw new PyException(BadPickleGet, py_key);
1966: push(value);
1967: }
1968:
1969: final private void load_put() {
1970: memo.put(file.readlineNoNl(), peek());
1971: }
1972:
1973: final private void load_binput() {
1974: int i = (int) file.read(1).charAt(0);
1975: memo.put(String.valueOf(i), peek());
1976: }
1977:
1978: final private void load_long_binput() {
1979: String d = file.read(4);
1980: int i = d.charAt(0) | (d.charAt(1) << 8)
1981: | (d.charAt(2) << 16) | (d.charAt(3) << 24);
1982: memo.put(String.valueOf(i), peek());
1983: }
1984:
1985: final private void load_append() {
1986: PyObject value = pop();
1987: PyList list = (PyList) peek();
1988: list.append(value);
1989: }
1990:
1991: final private void load_appends() {
1992: int mark = marker();
1993: PyList list = (PyList) peek(mark + 1);
1994: for (int i = mark - 1; i >= 0; i--)
1995: list.append(peek(i));
1996: pop(mark + 1);
1997: }
1998:
1999: final private void load_setitem() {
2000: PyObject value = pop();
2001: PyObject key = pop();
2002: PyDictionary dict = (PyDictionary) peek();
2003: dict.__setitem__(key, value);
2004: }
2005:
2006: final private void load_setitems() {
2007: int mark = marker();
2008: PyDictionary dict = (PyDictionary) peek(mark + 1);
2009: for (int i = 0; i < mark; i += 2) {
2010: PyObject key = peek(i + 1);
2011: PyObject value = peek(i);
2012: dict.__setitem__(key, value);
2013: }
2014: pop(mark + 1);
2015: }
2016:
2017: final private void load_build() {
2018: PyObject value = pop();
2019: PyInstance inst = (PyInstance) peek();
2020: PyObject setstate = inst.__findattr__("__setstate__");
2021: if (setstate == null) {
2022: inst.__dict__.__findattr__("update").__call__(value);
2023: } else {
2024: setstate.__call__(value);
2025: }
2026: }
2027:
2028: final private void load_mark() {
2029: push(mark);
2030: }
2031:
2032: final private PyObject load_stop() {
2033: return pop();
2034: }
2035:
2036: final private PyObject peek() {
2037: return stack[stackTop - 1];
2038: }
2039:
2040: final private PyObject peek(int count) {
2041: return stack[stackTop - count - 1];
2042: }
2043:
2044: final private PyObject pop() {
2045: PyObject val = stack[--stackTop];
2046: stack[stackTop] = null;
2047: return val;
2048: }
2049:
2050: final private void pop(int count) {
2051: for (int i = 0; i < count; i++)
2052: stack[--stackTop] = null;
2053: }
2054:
2055: final private void pop(PyObject[] arr) {
2056: int len = arr.length;
2057: System.arraycopy(stack, stackTop - len, arr, 0, len);
2058: stackTop -= len;
2059: }
2060:
2061: final private void push(PyObject val) {
2062: if (stackTop >= stack.length) {
2063: PyObject[] newStack = new PyObject[(stackTop + 1) * 2];
2064: System.arraycopy(stack, 0, newStack, 0, stack.length);
2065: stack = newStack;
2066: }
2067: stack[stackTop++] = val;
2068: }
2069: }
2070:
2071: private static PyObject importModule(String name) {
2072: PyObject silly_list = new PyTuple(new PyString[] { Py
2073: .newString("__doc__"), });
2074: return __builtin__.__import__(name, null, null, silly_list);
2075: }
2076:
2077: private static PyObject getJavaFunc(String name) {
2078: return Py.newJavaFunc(cPickle.class, name);
2079: }
2080:
2081: private static PyObject buildClass(String classname,
2082: PyObject super class, String classCodeName, String doc) {
2083: PyObject[] sclass = Py.EmptyObjects;
2084: if (super class != null)
2085: sclass = new PyObject[] { super class };
2086: PyObject cls = Py.makeClass(classname, sclass, Py.newJavaCode(
2087: cPickle.class, classCodeName), new PyString(doc));
2088: return cls;
2089: }
2090: }
|