Fix up .gitignore files some more
[p5sagit/p5-mst-13.2.git] / ext / Storable / Storable.xs
index b4ff829..24de05f 100644 (file)
@@ -18,6 +18,9 @@
 #endif
 
 #if !defined(PERL_VERSION) || PERL_VERSION < 8
+#define NEED_load_module
+#define NEED_vload_module
+#define NEED_newCONSTSUB
 #include "ppport.h"             /* handle old perls */
 #endif
 
@@ -86,6 +89,13 @@ typedef double NV;                   /* Older perls lack the NV type */
 #endif
 #endif
 
+#ifndef SvRV_set
+#define SvRV_set(sv, val) \
+    STMT_START { \
+        assert(SvTYPE(sv) >=  SVt_RV); \
+        (((XRV*)SvANY(sv))->xrv_rv = (val)); \
+    } STMT_END
+#endif
 
 #ifndef PERL_UNUSED_DECL
 #  ifdef HASATTRIBUTE
@@ -108,10 +118,10 @@ typedef double NV;                        /* Older perls lack the NV type */
 #endif
 
 #ifndef HvRITER_set
-#  define HvRITER_set(hv,r)    (*HvRITER(hv) = r)
+#  define HvRITER_set(hv,r)    (HvRITER(hv) = r)
 #endif
 #ifndef HvEITER_set
-#  define HvEITER_set(hv,r)    (*HvEITER(hv) = r)
+#  define HvEITER_set(hv,r)    (HvEITER(hv) = r)
 #endif
 
 #ifndef HvRITER_get
@@ -372,7 +382,7 @@ typedef struct stcxt {
        PerlIO *fio;            /* where I/O are performed, NULL for memory */
        int ver_major;          /* major of version for retrieved object */
        int ver_minor;          /* minor of version for retrieved object */
-       SV *(**retrieve_vtbl)(pTHX_ struct stcxt *, char *);    /* retrieve dispatch table */
+       SV *(**retrieve_vtbl)(pTHX_ struct stcxt *, const char *);      /* retrieve dispatch table */
        SV *prev;               /* contexts chained backwards in real recursion */
        SV *my_sv;              /* the blessed scalar who's SvPVX() I am */
 } stcxt_t;
@@ -381,7 +391,7 @@ typedef struct stcxt {
   STMT_START {                                                                         \
        SV *self = newSV(sizeof(stcxt_t) - 1);                  \
        SV *my_sv = newRV_noinc(self);                                  \
-       sv_bless(my_sv, gv_stashpv("Storable::Cxt", TRUE));     \
+       sv_bless(my_sv, gv_stashpv("Storable::Cxt", GV_ADD));   \
        cxt = (stcxt_t *)SvPVX(self);                                   \
        Zero(cxt, 1, stcxt_t);                                                  \
        cxt->my_sv = my_sv;                                                             \
@@ -649,6 +659,17 @@ static stcxt_t *Context_ptr = NULL;
        }                                                               \
   } STMT_END
 
+#define MBUF_SAFEPVREAD(x,s,z)                 \
+  STMT_START {                                 \
+       if ((mptr + (s)) <= mend) {             \
+               memcpy(x, mptr, s);             \
+               mptr += s;                      \
+       } else {                                \
+               Safefree(z);                    \
+               return (SV *) 0;                \
+       }                                       \
+  } STMT_END
+
 #define MBUF_PUTC(c)                           \
   STMT_START {                                         \
        if (mptr < mend)                                \
@@ -979,6 +1000,16 @@ static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0};
        }                                                                                       \
   } STMT_END
 
+#define SAFEPVREAD(x,y,z)                                      \
+  STMT_START {                                                 \
+       if (!cxt->fio)                                          \
+               MBUF_SAFEPVREAD(x,y,z);                         \
+       else if (PerlIO_read(cxt->fio, x, y) != y)       {      \
+               Safefree(z);                                    \
+               return (SV *) 0;                                \
+       }                                                       \
+  } STMT_END
+
 /*
  * This macro is used at retrieve time, to remember where object 'y', bearing a
  * given tag 'tagnum', has been retrieved. Next time we see an SX_OBJECT marker,
@@ -1019,7 +1050,7 @@ static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0};
        SV *ref;                                                                \
        HV *stash;                                                              \
        TRACEME(("blessing 0x%"UVxf" in %s", PTR2UV(s), (p))); \
-       stash = gv_stashpv((p), TRUE);                  \
+       stash = gv_stashpv((p), GV_ADD);                        \
        ref = newRV_noinc(s);                                   \
        (void) sv_bless(ref, stash);                    \
        SvRV_set(ref, NULL);                                            \
@@ -1057,7 +1088,7 @@ static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0};
 #endif /* PATCHLEVEL <= 6 */
 
 static int store(pTHX_ stcxt_t *cxt, SV *sv);
-static SV *retrieve(pTHX_ stcxt_t *cxt, char *cname);
+static SV *retrieve(pTHX_ stcxt_t *cxt, const char *cname);
 
 /*
  * Dynamic dispatching table for SV store.
@@ -1075,7 +1106,7 @@ static int store_blessed(pTHX_ stcxt_t *cxt, SV *sv, int type, HV *pkg);
 
 typedef int (*sv_store_t)(pTHX_ stcxt_t *cxt, SV *sv);
 
-static sv_store_t sv_store[] = {
+static const sv_store_t sv_store[] = {
        (sv_store_t)store_ref,          /* svis_REF */
        (sv_store_t)store_scalar,       /* svis_SCALAR */
        (sv_store_t)store_array,        /* svis_ARRAY */
@@ -1092,24 +1123,24 @@ static sv_store_t sv_store[] = {
  * Dynamic dispatching tables for SV retrieval.
  */
 
-static SV *retrieve_lscalar(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_lutf8str(pTHX_ stcxt_t *cxt, char *cname);
-static SV *old_retrieve_array(pTHX_ stcxt_t *cxt, char *cname);
-static SV *old_retrieve_hash(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_ref(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_undef(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_integer(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_double(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_byte(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_netint(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_scalar(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_utf8str(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_tied_array(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_tied_hash(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_tied_scalar(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_other(pTHX_ stcxt_t *cxt, char *cname);
-
-typedef SV* (*sv_retrieve_t)(pTHX_ stcxt_t *cxt, char *name);
+static SV *retrieve_lscalar(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_lutf8str(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *old_retrieve_array(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *old_retrieve_hash(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_ref(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_undef(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_integer(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_double(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_byte(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_netint(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_scalar(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_utf8str(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_tied_array(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_tied_hash(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_tied_scalar(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_other(pTHX_ stcxt_t *cxt, const char *cname);
+
+typedef SV* (*sv_retrieve_t)(pTHX_ stcxt_t *cxt, const char *name);
 
 static const sv_retrieve_t sv_old_retrieve[] = {
        0,                      /* SX_OBJECT -- entry unused dynamically */
@@ -1144,21 +1175,21 @@ static const sv_retrieve_t sv_old_retrieve[] = {
        (sv_retrieve_t)retrieve_other,  /* SX_ERROR */
 };
 
-static SV *retrieve_array(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_hash(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_sv_undef(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_sv_yes(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_sv_no(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_blessed(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_idx_blessed(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_hook(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_overloaded(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_tied_key(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_tied_idx(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_flag_hash(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_code(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_weakref(pTHX_ stcxt_t *cxt, char *cname);
-static SV *retrieve_weakoverloaded(pTHX_ stcxt_t *cxt, char *cname);
+static SV *retrieve_array(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_hash(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_sv_undef(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_sv_yes(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_sv_no(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_blessed(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_idx_blessed(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_hook(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_overloaded(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_tied_key(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_tied_idx(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_flag_hash(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_code(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_weakref(pTHX_ stcxt_t *cxt, const char *cname);
+static SV *retrieve_weakoverloaded(pTHX_ stcxt_t *cxt, const char *cname);
 
 static const sv_retrieve_t sv_retrieve[] = {
        0,                      /* SX_OBJECT -- entry unused dynamically */
@@ -1601,7 +1632,7 @@ static void free_context(pTHX_ stcxt_t *cxt)
  *
  * Tells whether we're in the middle of a store operation.
  */
-int is_storing(pTHX)
+static int is_storing(pTHX)
 {
        dSTCXT;
 
@@ -1613,7 +1644,7 @@ int is_storing(pTHX)
  *
  * Tells whether we're in the middle of a retrieve operation.
  */
-int is_retrieving(pTHX)
+static int is_retrieving(pTHX)
 {
        dSTCXT;
 
@@ -1628,7 +1659,7 @@ int is_retrieving(pTHX)
  * This is typically out-of-band information that might prove useful
  * to people wishing to convert native to network order data when used.
  */
-int last_op_in_netorder(pTHX)
+static int last_op_in_netorder(pTHX)
 {
        dSTCXT;
 
@@ -1651,7 +1682,7 @@ static SV *pkg_fetchmeth(
         pTHX_
        HV *cache,
        HV *pkg,
-       char *method)
+       const char *method)
 {
        GV *gv;
        SV *sv;
@@ -1691,7 +1722,7 @@ static void pkg_hide(
         pTHX_
        HV *cache,
        HV *pkg,
-       char *method)
+       const char *method)
 {
        const char *hvname = HvNAME_get(pkg);
        (void) hv_store(cache,
@@ -1707,7 +1738,7 @@ static void pkg_uncache(
         pTHX_
        HV *cache,
        HV *pkg,
-       char *method)
+       const char *method)
 {
        const char *hvname = HvNAME_get(pkg);
        (void) hv_delete(cache, hvname, strlen(hvname), G_DISCARD);
@@ -1725,7 +1756,7 @@ static SV *pkg_can(
         pTHX_
        HV *cache,
        HV *pkg,
-       char *method)
+       const char *method)
 {
        SV **svh;
        SV *sv;
@@ -2322,7 +2353,11 @@ static int store_hash(pTHX_ stcxt_t *cxt, HV *hv)
 #else
                        HE *he = hv_iternext(hv);
 #endif
-                       SV *key = hv_iterkeysv(he);
+                       SV *key;
+
+                       if (!he)
+                               CROAK(("Hash %p inconsistent - expected %d keys, %dth is NULL", hv, len, i));
+                       key = hv_iterkeysv(he);
                        av_store(av, AvFILLp(av)+1, key);       /* av_push(), really */
                }
                        
@@ -2460,7 +2495,7 @@ static int store_hash(pTHX_ stcxt_t *cxt, HV *hv)
                 */
   
                for (i = 0; i < len; i++) {
-                       char *key;
+                       char *key = 0;
                        I32 len;
                         unsigned char flags;
 #ifdef HV_ITERNEXT_WANTPLACEHOLDERS
@@ -2595,6 +2630,7 @@ static int store_code(pTHX_ stcxt_t *cxt, CV *cv)
         */
        /* Ownership of both SVs is passed to load_module, which frees them. */
        load_module(PERL_LOADMOD_NOIMPORT, newSVpvn("B::Deparse",10), newSVnv(0.61));
+        SPAGAIN;
 
        ENTER;
        SAVETMPS;
@@ -2626,7 +2662,7 @@ static int store_code(pTHX_ stcxt_t *cxt, CV *cv)
                CROAK(("Unexpected return value from B::Deparse::coderef2text\n"));
 
        text = POPs;
-       len = SvLEN(text);
+       len = SvCUR(text);
        reallen = strlen(SvPV_nolen(text));
 
        /*
@@ -3017,7 +3053,7 @@ static int store_hook(
                   failure, whereas the existing code assumes that it can
                   safely store a tag zero. So for ptr_tables we store tag+1
                */
-               if (fake_tag = ptr_table_fetch(cxt->pseen, xsv))
+               if ((fake_tag = (char *)ptr_table_fetch(cxt->pseen, xsv)))
                        goto sv_seen;           /* Avoid moving code too far to the right */
 #else
                if ((svh = hv_fetch(cxt->hseen, (char *) &xsv, sizeof(xsv), FALSE)))
@@ -3050,7 +3086,7 @@ static int store_hook(
                        return ret;
 
 #ifdef USE_PTR_TABLE
-               fake_tag = ptr_table_fetch(cxt->pseen, xsv);
+               fake_tag = (char *)ptr_table_fetch(cxt->pseen, xsv);
                if (!sv)
                        CROAK(("Could not serialize item #%d from hook in %s", i, classname));
 #else
@@ -3092,7 +3128,7 @@ static int store_hook(
 #else
                tag = *svh;
 #endif
-               ary[i] = tag
+               ary[i] = tag;
                TRACEME(("listed object %d at 0x%"UVxf" is tag #%"UVuf,
                         i-1, PTR2UV(xsv), PTR2UV(tag)));
        }
@@ -3398,7 +3434,9 @@ static int sv_type(pTHX_ SV *sv)
 {
        switch (SvTYPE(sv)) {
        case SVt_NULL:
+#if PERL_VERSION <= 10
        case SVt_IV:
+#endif
        case SVt_NV:
                /*
                 * No need to check for ROK, that can't be set here since there
@@ -3406,7 +3444,11 @@ static int sv_type(pTHX_ SV *sv)
                 */
                return svis_SCALAR;
        case SVt_PV:
+#if PERL_VERSION <= 10
        case SVt_RV:
+#else
+       case SVt_IV:
+#endif
        case SVt_PVIV:
        case SVt_PVNV:
                /*
@@ -3424,7 +3466,9 @@ static int sv_type(pTHX_ SV *sv)
                if (SvRMAGICAL(sv) && (mg_find(sv, 'p')))
                        return svis_TIED_ITEM;
                /* FALL THROUGH */
+#if PERL_VERSION < 9
        case SVt_PVBM:
+#endif
                if (SvRMAGICAL(sv) && (mg_find(sv, 'q')))
                        return svis_TIED;
                return SvROK(sv) ? svis_REF : svis_SCALAR;
@@ -3438,6 +3482,9 @@ static int sv_type(pTHX_ SV *sv)
                return svis_HASH;
        case SVt_PVCV:
                return svis_CODE;
+#if PERL_VERSION > 8
+       /* case SVt_BIND: */
+#endif
        default:
                break;
        }
@@ -3480,7 +3527,7 @@ static int store(pTHX_ stcxt_t *cxt, SV *sv)
         */
 
 #ifdef USE_PTR_TABLE
-       svh = ptr_table_fetch(pseen, sv);
+       svh = (SV **)ptr_table_fetch(pseen, sv);
 #else
        svh = hv_fetch(hseen, (char *) &sv, sizeof(sv), FALSE);
 #endif
@@ -3799,7 +3846,7 @@ static int do_store(
  * Store the transitive data closure of given object to disk.
  * Returns 0 on error, a true value otherwise.
  */
-int pstore(pTHX_ PerlIO *f, SV *sv)
+static int pstore(pTHX_ PerlIO *f, SV *sv)
 {
        TRACEME(("pstore"));
        return do_store(aTHX_ f, sv, 0, FALSE, (SV**) 0);
@@ -3812,7 +3859,7 @@ int pstore(pTHX_ PerlIO *f, SV *sv)
  * Same as pstore(), but network order is used for integers and doubles are
  * emitted as strings.
  */
-int net_pstore(pTHX_ PerlIO *f, SV *sv)
+static int net_pstore(pTHX_ PerlIO *f, SV *sv)
 {
        TRACEME(("net_pstore"));
        return do_store(aTHX_ f, sv, 0, TRUE, (SV**) 0);
@@ -3840,7 +3887,7 @@ static SV *mbuf2sv(pTHX)
  * Store the transitive data closure of given object to memory.
  * Returns undef on error, a scalar value containing the data otherwise.
  */
-SV *mstore(pTHX_ SV *sv)
+static SV *mstore(pTHX_ SV *sv)
 {
        SV *out;
 
@@ -3858,7 +3905,7 @@ SV *mstore(pTHX_ SV *sv)
  * Same as mstore(), but network order is used for integers and doubles are
  * emitted as strings.
  */
-SV *net_mstore(pTHX_ SV *sv)
+static SV *net_mstore(pTHX_ SV *sv)
 {
        SV *out;
 
@@ -3880,7 +3927,7 @@ SV *net_mstore(pTHX_ SV *sv)
  * Return an error via croak, since it is not possible that we get here
  * under normal conditions, when facing a file produced via pstore().
  */
-static SV *retrieve_other(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_other(pTHX_ stcxt_t *cxt, const char *cname)
 {
        if (
                cxt->ver_major != STORABLE_BIN_MAJOR &&
@@ -3905,10 +3952,10 @@ static SV *retrieve_other(pTHX_ stcxt_t *cxt, char *cname)
  * Layout is SX_IX_BLESS <index> <object> with SX_IX_BLESS already read.
  * <index> can be coded on either 1 or 5 bytes.
  */
-static SV *retrieve_idx_blessed(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_idx_blessed(pTHX_ stcxt_t *cxt, const char *cname)
 {
        I32 idx;
-       char *classname;
+       const char *classname;
        SV **sva;
        SV *sv;
 
@@ -3946,12 +3993,13 @@ static SV *retrieve_idx_blessed(pTHX_ stcxt_t *cxt, char *cname)
  * Layout is SX_BLESS <len> <classname> <object> with SX_BLESS already read.
  * <len> can be coded on either 1 or 5 bytes.
  */
-static SV *retrieve_blessed(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_blessed(pTHX_ stcxt_t *cxt, const char *cname)
 {
        I32 len;
        SV *sv;
        char buf[LG_BLESS + 1];         /* Avoid malloc() if possible */
        char *classname = buf;
+       char *malloced_classname = NULL;
 
        TRACEME(("retrieve_blessed (#%d)", cxt->tagnum));
        ASSERT(!cname, ("no bless-into class given here, got %s", cname));
@@ -3968,8 +4016,9 @@ static SV *retrieve_blessed(pTHX_ stcxt_t *cxt, char *cname)
                RLEN(len);
                TRACEME(("** allocating %d bytes for class name", len+1));
                New(10003, classname, len+1, char);
+               malloced_classname = classname;
        }
-       READ(classname, len);
+       SAFEPVREAD(classname, len, malloced_classname);
        classname[len] = '\0';          /* Mark string end */
 
        /*
@@ -3978,16 +4027,18 @@ static SV *retrieve_blessed(pTHX_ stcxt_t *cxt, char *cname)
 
        TRACEME(("new class name \"%s\" will bear ID = %d", classname, cxt->classnum));
 
-       if (!av_store(cxt->aclass, cxt->classnum++, newSVpvn(classname, len)))
+       if (!av_store(cxt->aclass, cxt->classnum++, newSVpvn(classname, len))) {
+               Safefree(malloced_classname);
                return (SV *) 0;
+       }
 
        /*
         * Retrieve object and bless it.
         */
 
        sv = retrieve(aTHX_ cxt, classname);    /* First SV which is SEEN will be blessed */
-       if (classname != buf)
-               Safefree(classname);
+       if (malloced_classname)
+               Safefree(malloced_classname);
 
        return sv;
 }
@@ -4012,7 +4063,7 @@ static SV *retrieve_blessed(pTHX_ stcxt_t *cxt, char *cname)
  * processing (since we won't have seen the magic object by the time the hook
  * is called).  See comments below for why it was done that way.
  */
-static SV *retrieve_hook(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_hook(pTHX_ stcxt_t *cxt, const char *cname)
 {
        I32 len;
        char buf[LG_BLESS + 1];         /* Avoid malloc() if possible */
@@ -4139,6 +4190,7 @@ static SV *retrieve_hook(pTHX_ stcxt_t *cxt, char *cname)
                 * on the stack.  Just like retrieve_blessed(), we limit the name to
                 * LG_BLESS bytes.  This is an arbitrary decision.
                 */
+               char *malloced_classname = NULL;
 
                if (flags & SHF_LARGE_CLASSLEN)
                        RLEN(len);
@@ -4148,17 +4200,20 @@ static SV *retrieve_hook(pTHX_ stcxt_t *cxt, char *cname)
                if (len > LG_BLESS) {
                        TRACEME(("** allocating %d bytes for class name", len+1));
                        New(10003, classname, len+1, char);
+                       malloced_classname = classname;
                }
 
-               READ(classname, len);
+               SAFEPVREAD(classname, len, malloced_classname);
                classname[len] = '\0';          /* Mark string end */
 
                /*
                 * Record new classname.
                 */
 
-               if (!av_store(cxt->aclass, cxt->classnum++, newSVpvn(classname, len)))
+               if (!av_store(cxt->aclass, cxt->classnum++, newSVpvn(classname, len))) {
+                       Safefree(malloced_classname);
                        return (SV *) 0;
+               }
        }
 
        TRACEME(("class name: %s", classname));
@@ -4276,19 +4331,14 @@ static SV *retrieve_hook(pTHX_ stcxt_t *cxt, char *cname)
                 * Hook not found.  Maybe they did not require the module where this
                 * hook is defined yet?
                 *
-                * If the require below succeeds, we'll be able to find the hook.
+                * If the load below succeeds, we'll be able to find the hook.
                 * Still, it only works reliably when each class is defined in a
                 * file of its own.
                 */
 
-               SV *psv = newSVpvn("require ", 8);
-               sv_catpv(psv, classname);
-
                TRACEME(("No STORABLE_thaw defined for objects of class %s", classname));
-               TRACEME(("Going to require module '%s' with '%s'", classname, SvPVX(psv)));
-
-               perl_eval_sv(psv, G_DISCARD);
-               sv_free(psv);
+               TRACEME(("Going to load module '%s'", classname));
+               load_module(PERL_LOADMOD_NOIMPORT, newSVpv(classname, 0), Nullsv);
 
                /*
                 * We cache results of pkg_can, so we need to uncache before attempting
@@ -4400,7 +4450,7 @@ static SV *retrieve_hook(pTHX_ stcxt_t *cxt, char *cname)
         * into the existing design.  -- RAM, 17/02/2001
         */
 
-       sv_magic(sv, rv, mtype, Nullch, 0);
+       sv_magic(sv, rv, mtype, (char *)NULL, 0);
        SvREFCNT_dec(rv);                       /* Undo refcnt inc from sv_magic() */
 
        return sv;
@@ -4412,7 +4462,7 @@ static SV *retrieve_hook(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve reference to some other scalar.
  * Layout is SX_REF <object>, with SX_REF already read.
  */
-static SV *retrieve_ref(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_ref(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *rv;
        SV *sv;
@@ -4453,7 +4503,7 @@ static SV *retrieve_ref(pTHX_ stcxt_t *cxt, char *cname)
 
        if (cname) {
                /* No need to do anything, as rv will already be PVMG.  */
-               assert (SvTYPE(rv) >= SVt_RV);
+               assert (SvTYPE(rv) == SVt_RV || SvTYPE(rv) >= SVt_PV);
        } else {
                sv_upgrade(rv, SVt_RV);
        }
@@ -4472,7 +4522,7 @@ static SV *retrieve_ref(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve weak reference to some other scalar.
  * Layout is SX_WEAKREF <object>, with SX_WEAKREF already read.
  */
-static SV *retrieve_weakref(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_weakref(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv;
 
@@ -4495,7 +4545,7 @@ static SV *retrieve_weakref(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve reference to some other scalar with overloading.
  * Layout is SX_OVERLOAD <object>, with SX_OVERLOAD already read.
  */
-static SV *retrieve_overloaded(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_overloaded(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *rv;
        SV *sv;
@@ -4517,7 +4567,7 @@ static SV *retrieve_overloaded(pTHX_ stcxt_t *cxt, char *cname)
         * WARNING: breaks RV encapsulation.
         */
 
-       sv_upgrade(rv, SVt_RV);
+       SvUPGRADE(rv, SVt_RV);
        SvRV_set(rv, sv);                               /* $rv = \$sv */
        SvROK_on(rv);
 
@@ -4533,15 +4583,10 @@ static SV *retrieve_overloaded(pTHX_ stcxt_t *cxt, char *cname)
                       PTR2UV(sv)));
        }
        if (!Gv_AMG(stash)) {
-               SV *psv = newSVpvn("require ", 8);
-               const char *package = HvNAME_get(stash);
-               sv_catpv(psv, package);
-
+               const char *package = HvNAME_get(stash);
                TRACEME(("No overloading defined for package %s", package));
-               TRACEME(("Going to require module '%s' with '%s'", package, SvPVX(psv)));
-
-               perl_eval_sv(psv, G_DISCARD);
-               sv_free(psv);
+               TRACEME(("Going to load module '%s'", package));
+               load_module(PERL_LOADMOD_NOIMPORT, newSVpv(package, 0), Nullsv);
                if (!Gv_AMG(stash)) {
                        CROAK(("Cannot restore overloading on %s(0x%"UVxf
                               ") (package %s) (even after a \"require %s;\")",
@@ -4564,7 +4609,7 @@ static SV *retrieve_overloaded(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve weak overloaded reference to some other scalar.
  * Layout is SX_WEAKOVERLOADED <object>, with SX_WEAKOVERLOADED already read.
  */
-static SV *retrieve_weakoverloaded(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_weakoverloaded(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv;
 
@@ -4587,7 +4632,7 @@ static SV *retrieve_weakoverloaded(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve tied array
  * Layout is SX_TIED_ARRAY <object>, with SX_TIED_ARRAY already read.
  */
-static SV *retrieve_tied_array(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_tied_array(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *tv;
        SV *sv;
@@ -4602,7 +4647,7 @@ static SV *retrieve_tied_array(pTHX_ stcxt_t *cxt, char *cname)
 
        sv_upgrade(tv, SVt_PVAV);
        AvREAL_off((AV *)tv);
-       sv_magic(tv, sv, 'P', Nullch, 0);
+       sv_magic(tv, sv, 'P', (char *)NULL, 0);
        SvREFCNT_dec(sv);                       /* Undo refcnt inc from sv_magic() */
 
        TRACEME(("ok (retrieve_tied_array at 0x%"UVxf")", PTR2UV(tv)));
@@ -4616,7 +4661,7 @@ static SV *retrieve_tied_array(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve tied hash
  * Layout is SX_TIED_HASH <object>, with SX_TIED_HASH already read.
  */
-static SV *retrieve_tied_hash(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_tied_hash(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *tv;
        SV *sv;
@@ -4630,7 +4675,7 @@ static SV *retrieve_tied_hash(pTHX_ stcxt_t *cxt, char *cname)
                return (SV *) 0;                /* Failed */
 
        sv_upgrade(tv, SVt_PVHV);
-       sv_magic(tv, sv, 'P', Nullch, 0);
+       sv_magic(tv, sv, 'P', (char *)NULL, 0);
        SvREFCNT_dec(sv);                       /* Undo refcnt inc from sv_magic() */
 
        TRACEME(("ok (retrieve_tied_hash at 0x%"UVxf")", PTR2UV(tv)));
@@ -4644,7 +4689,7 @@ static SV *retrieve_tied_hash(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve tied scalar
  * Layout is SX_TIED_SCALAR <object>, with SX_TIED_SCALAR already read.
  */
-static SV *retrieve_tied_scalar(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_tied_scalar(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *tv;
        SV *sv, *obj = NULL;
@@ -4662,7 +4707,7 @@ static SV *retrieve_tied_scalar(pTHX_ stcxt_t *cxt, char *cname)
        }
 
        sv_upgrade(tv, SVt_PVMG);
-       sv_magic(tv, obj, 'q', Nullch, 0);
+       sv_magic(tv, obj, 'q', (char *)NULL, 0);
 
        if (obj) {
                /* Undo refcnt inc from sv_magic() */
@@ -4680,7 +4725,7 @@ static SV *retrieve_tied_scalar(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve reference to value in a tied hash.
  * Layout is SX_TIED_KEY <object> <key>, with SX_TIED_KEY already read.
  */
-static SV *retrieve_tied_key(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_tied_key(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *tv;
        SV *sv;
@@ -4712,7 +4757,7 @@ static SV *retrieve_tied_key(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve reference to value in a tied array.
  * Layout is SX_TIED_IDX <object> <idx>, with SX_TIED_IDX already read.
  */
-static SV *retrieve_tied_idx(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_tied_idx(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *tv;
        SV *sv;
@@ -4729,7 +4774,7 @@ static SV *retrieve_tied_idx(pTHX_ stcxt_t *cxt, char *cname)
        RLEN(idx);                                      /* Retrieve <idx> */
 
        sv_upgrade(tv, SVt_PVMG);
-       sv_magic(tv, sv, 'p', Nullch, idx);
+       sv_magic(tv, sv, 'p', (char *)NULL, idx);
        SvREFCNT_dec(sv);                       /* Undo refcnt inc from sv_magic() */
 
        return tv;
@@ -4745,7 +4790,7 @@ static SV *retrieve_tied_idx(pTHX_ stcxt_t *cxt, char *cname)
  * The scalar is "long" in that <length> is larger than LG_SCALAR so it
  * was not stored on a single byte.
  */
-static SV *retrieve_lscalar(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_lscalar(pTHX_ stcxt_t *cxt, const char *cname)
 {
        I32 len;
        SV *sv;
@@ -4760,6 +4805,11 @@ static SV *retrieve_lscalar(pTHX_ stcxt_t *cxt, char *cname)
        sv = NEWSV(10002, len);
        SEEN(sv, cname, 0);     /* Associate this new scalar with tag "tagnum" */
 
+       if (len ==  0) {
+           sv_setpvn(sv, "", 0);
+           return sv;
+       }
+
        /*
         * WARNING: duplicates parts of sv_setpv and breaks SV data encapsulation.
         *
@@ -4791,7 +4841,7 @@ static SV *retrieve_lscalar(pTHX_ stcxt_t *cxt, char *cname)
  * The scalar is "short" so <length> is single byte. If it is 0, there
  * is no <data> section.
  */
-static SV *retrieve_scalar(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_scalar(pTHX_ stcxt_t *cxt, const char *cname)
 {
        int len;
        SV *sv;
@@ -4850,7 +4900,7 @@ static SV *retrieve_scalar(pTHX_ stcxt_t *cxt, char *cname)
  * Like retrieve_scalar(), but tag result as utf8.
  * If we're retrieving UTF8 data in a non-UTF8 perl, croaks.
  */
-static SV *retrieve_utf8str(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_utf8str(pTHX_ stcxt_t *cxt, const char *cname)
 {
     SV *sv;
 
@@ -4879,7 +4929,7 @@ static SV *retrieve_utf8str(pTHX_ stcxt_t *cxt, char *cname)
  * Like retrieve_lscalar(), but tag result as utf8.
  * If we're retrieving UTF8 data in a non-UTF8 perl, croaks.
  */
-static SV *retrieve_lutf8str(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_lutf8str(pTHX_ stcxt_t *cxt, const char *cname)
 {
     SV *sv;
 
@@ -4907,7 +4957,7 @@ static SV *retrieve_lutf8str(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve defined integer.
  * Layout is SX_INTEGER <data>, whith SX_INTEGER already read.
  */
-static SV *retrieve_integer(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_integer(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv;
        IV iv;
@@ -4930,7 +4980,7 @@ static SV *retrieve_integer(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve defined integer in network order.
  * Layout is SX_NETINT <data>, whith SX_NETINT already read.
  */
-static SV *retrieve_netint(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_netint(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv;
        I32 iv;
@@ -4958,7 +5008,7 @@ static SV *retrieve_netint(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve defined double.
  * Layout is SX_DOUBLE <data>, whith SX_DOUBLE already read.
  */
-static SV *retrieve_double(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_double(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv;
        NV nv;
@@ -4981,7 +5031,7 @@ static SV *retrieve_double(pTHX_ stcxt_t *cxt, char *cname)
  * Retrieve defined byte (small integer within the [-128, +127] range).
  * Layout is SX_BYTE <data>, whith SX_BYTE already read.
  */
-static SV *retrieve_byte(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_byte(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv;
        int siv;
@@ -5006,7 +5056,7 @@ static SV *retrieve_byte(pTHX_ stcxt_t *cxt, char *cname)
  *
  * Return the undefined value.
  */
-static SV *retrieve_undef(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_undef(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV* sv;
 
@@ -5023,7 +5073,7 @@ static SV *retrieve_undef(pTHX_ stcxt_t *cxt, char *cname)
  *
  * Return the immortal undefined value.
  */
-static SV *retrieve_sv_undef(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_sv_undef(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv = &PL_sv_undef;
 
@@ -5044,7 +5094,7 @@ static SV *retrieve_sv_undef(pTHX_ stcxt_t *cxt, char *cname)
  *
  * Return the immortal yes value.
  */
-static SV *retrieve_sv_yes(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_sv_yes(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv = &PL_sv_yes;
 
@@ -5059,7 +5109,7 @@ static SV *retrieve_sv_yes(pTHX_ stcxt_t *cxt, char *cname)
  *
  * Return the immortal no value.
  */
-static SV *retrieve_sv_no(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_sv_no(pTHX_ stcxt_t *cxt, const char *cname)
 {
        SV *sv = &PL_sv_no;
 
@@ -5078,7 +5128,7 @@ static SV *retrieve_sv_no(pTHX_ stcxt_t *cxt, char *cname)
  *
  * When we come here, SX_ARRAY has been read already.
  */
-static SV *retrieve_array(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_array(pTHX_ stcxt_t *cxt, const char *cname)
 {
        I32 len;
        I32 i;
@@ -5129,7 +5179,7 @@ static SV *retrieve_array(pTHX_ stcxt_t *cxt, char *cname)
  *
  * When we come here, SX_HASH has been read already.
  */
-static SV *retrieve_hash(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_hash(pTHX_ stcxt_t *cxt, const char *cname)
 {
        I32 len;
        I32 size;
@@ -5203,7 +5253,7 @@ static SV *retrieve_hash(pTHX_ stcxt_t *cxt, char *cname)
  *
  * When we come here, SX_HASH has been read already.
  */
-static SV *retrieve_flag_hash(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_flag_hash(pTHX_ stcxt_t *cxt, const char *cname)
 {
     dVAR;
     I32 len;
@@ -5340,7 +5390,7 @@ static SV *retrieve_flag_hash(pTHX_ stcxt_t *cxt, char *cname)
  *
  * Return a code reference.
  */
-static SV *retrieve_code(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve_code(pTHX_ stcxt_t *cxt, const char *cname)
 {
 #if PERL_VERSION < 6
     CROAK(("retrieve_code does not work with perl 5.005 or less\n"));
@@ -5461,7 +5511,7 @@ static SV *retrieve_code(pTHX_ stcxt_t *cxt, char *cname)
  *
  * When we come here, SX_ARRAY has been read already.
  */
-static SV *old_retrieve_array(pTHX_ stcxt_t *cxt, char *cname)
+static SV *old_retrieve_array(pTHX_ stcxt_t *cxt, const char *cname)
 {
        I32 len;
        I32 i;
@@ -5521,7 +5571,7 @@ static SV *old_retrieve_array(pTHX_ stcxt_t *cxt, char *cname)
  *
  * When we come here, SX_HASH has been read already.
  */
-static SV *old_retrieve_hash(pTHX_ stcxt_t *cxt, char *cname)
+static SV *old_retrieve_hash(pTHX_ stcxt_t *cxt, const char *cname)
 {
        I32 len;
        I32 size;
@@ -5634,6 +5684,7 @@ static SV *magic_check(pTHX_ stcxt_t *cxt)
     int length;
     int use_network_order;
     int use_NV_size;
+    int old_magic = 0;
     int version_major;
     int version_minor = 0;
 
@@ -5667,6 +5718,7 @@ static SV *magic_check(pTHX_ stcxt_t *cxt)
             
             if (memNE(buf, old_magicstr, old_len))
                 CROAK(("File is not a perl storable"));
+           old_magic++;
             current = buf + old_len;
         }
         use_network_order = *current;
@@ -5678,9 +5730,14 @@ static SV *magic_check(pTHX_ stcxt_t *cxt)
      * indicate the version number of the binary, and therefore governs the
      * setting of sv_retrieve_vtbl. See magic_write().
      */
-
-    version_major = use_network_order >> 1;
-    cxt->retrieve_vtbl = (SV*(**)(pTHX_ stcxt_t *cxt, char *cname)) (version_major ? sv_retrieve : sv_old_retrieve);
+    if (old_magic && use_network_order > 1) {
+       /*  0.1 dump - use_network_order is really byte order length */
+       version_major = -1;
+    }
+    else {
+        version_major = use_network_order >> 1;
+    }
+    cxt->retrieve_vtbl = (SV*(**)(pTHX_ stcxt_t *cxt, const char *cname)) (version_major > 0 ? sv_retrieve : sv_old_retrieve);
 
     TRACEME(("magic_check: netorder = 0x%x", use_network_order));
 
@@ -5743,7 +5800,12 @@ static SV *magic_check(pTHX_ stcxt_t *cxt)
     /* In C truth is 1, falsehood is 0. Very convienient.  */
     use_NV_size = version_major >= 2 && version_minor >= 2;
 
-    GETMARK(c);
+    if (version_major >= 0) {
+        GETMARK(c);
+    }
+    else {
+       c = use_network_order;
+    }
     length = c + 3 + use_NV_size;
     READ(buf, length); /* Not null-terminated */
 
@@ -5793,7 +5855,7 @@ static SV *magic_check(pTHX_ stcxt_t *cxt)
  * root SV (which may be an AV or an HV for what we care).
  * Returns null if there is a problem.
  */
-static SV *retrieve(pTHX_ stcxt_t *cxt, char *cname)
+static SV *retrieve(pTHX_ stcxt_t *cxt, const char *cname)
 {
        int type;
        SV **svh;
@@ -6185,7 +6247,7 @@ static SV *do_retrieve(
  *
  * Retrieve data held in file and return the root object, undef on error.
  */
-SV *pretrieve(pTHX_ PerlIO *f)
+static SV *pretrieve(pTHX_ PerlIO *f)
 {
        TRACEME(("pretrieve"));
        return do_retrieve(aTHX_ f, Nullsv, 0);
@@ -6196,7 +6258,7 @@ SV *pretrieve(pTHX_ PerlIO *f)
  *
  * Retrieve data held in scalar and return the root object, undef on error.
  */
-SV *mretrieve(pTHX_ SV *sv)
+static SV *mretrieve(pTHX_ SV *sv)
 {
        TRACEME(("mretrieve"));
        return do_retrieve(aTHX_ (PerlIO*) 0, sv, 0);
@@ -6215,7 +6277,7 @@ SV *mretrieve(pTHX_ SV *sv)
  * there. Not that efficient, but it should be faster than doing it from
  * pure perl anyway.
  */
-SV *dclone(pTHX_ SV *sv)
+static SV *dclone(pTHX_ SV *sv)
 {
        dSTCXT;
        int size;
@@ -6233,6 +6295,18 @@ SV *dclone(pTHX_ SV *sv)
                clean_context(aTHX_ cxt);
 
        /*
+        * Tied elements seem to need special handling.
+        */
+
+       if ((SvTYPE(sv) == SVt_PVLV
+#if PERL_VERSION < 8
+            || SvTYPE(sv) == SVt_PVMG
+#endif
+            ) && SvRMAGICAL(sv) && mg_find(sv, 'p')) {
+               mg_get(sv);
+       }
+
+       /*
         * do_store() optimizes for dclone by not freeing its context, should
         * we need to allocate one because we're deep cloning from a hook.
         */
@@ -6315,6 +6389,12 @@ MODULE = Storable        PACKAGE = Storable
 PROTOTYPES: ENABLE
 
 BOOT:
+{
+    HV *stash = gv_stashpvn("Storable", 8, GV_ADD);
+    newCONSTSUB(stash, "BIN_MAJOR", newSViv(STORABLE_BIN_MAJOR));
+    newCONSTSUB(stash, "BIN_MINOR", newSViv(STORABLE_BIN_MINOR));
+    newCONSTSUB(stash, "BIN_WRITE_MINOR", newSViv(STORABLE_BIN_WRITE_MINOR));
+
     init_perinterp(aTHX);
     gv_fetchpv("Storable::drop_utf8",   GV_ADDMULTI, SVt_PV);
 #ifdef DEBUGME
@@ -6324,6 +6404,7 @@ BOOT:
 #ifdef USE_56_INTERWORK_KLUDGE
     gv_fetchpv("Storable::interwork_56_64bit",   GV_ADDMULTI, SVt_PV);
 #endif
+}
 
 void
 init_perinterp()