This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade CPAN from version 2.05-TRIAL2 to 2.05
[perl5.git] / pp_pack.c
index 2690b55..3aa7a73 100644 (file)
--- a/pp_pack.c
+++ b/pp_pack.c
@@ -129,46 +129,50 @@ typedef union {
 #  define OFF32(p)     ((char *) (p))
 #endif
 
 #  define OFF32(p)     ((char *) (p))
 #endif
 
-/* Only to be used inside a loop (see the break) */
-#define SHIFT16(utf8, s, strend, p, datumtype) STMT_START {            \
-    if (utf8) {                                                                \
-       if (!uni_to_bytes(aTHX_ &(s), strend, OFF16(p), SIZE16, datumtype)) break;      \
-    } else {                                                           \
-       Copy(s, OFF16(p), SIZE16, char);                                \
-       (s) += SIZE16;                                                  \
-    }                                                                  \
-} STMT_END
-
-/* Only to be used inside a loop (see the break) */
-#define SHIFT32(utf8, s, strend, p, datumtype) STMT_START {            \
-    if (utf8) {                                                                \
-       if (!uni_to_bytes(aTHX_ &(s), strend, OFF32(p), SIZE32, datumtype)) break;      \
-    } else {                                                           \
-       Copy(s, OFF32(p), SIZE32, char);                                \
-       (s) += SIZE32;                                                  \
-    }                                                                  \
-} STMT_END
+#define PUSH16(utf8, cur, p, needs_swap)                        \
+       PUSH_BYTES(utf8, cur, OFF16(p), SIZE16, needs_swap)
+#define PUSH32(utf8, cur, p, needs_swap)                        \
+       PUSH_BYTES(utf8, cur, OFF32(p), SIZE32, needs_swap)
 
 
-#define PUSH16(utf8, cur, p) PUSH_BYTES(utf8, cur, OFF16(p), SIZE16)
-#define PUSH32(utf8, cur, p) PUSH_BYTES(utf8, cur, OFF32(p), SIZE32)
+#if BYTEORDER == 0x4321 || BYTEORDER == 0x87654321  /* big-endian */
+#  define NEEDS_SWAP(d)     (TYPE_ENDIANNESS(d) == TYPE_IS_LITTLE_ENDIAN)
+#elif BYTEORDER == 0x1234 || BYTEORDER == 0x12345678  /* little-endian */
+#  define NEEDS_SWAP(d)     (TYPE_ENDIANNESS(d) == TYPE_IS_BIG_ENDIAN)
+#else
+#  error "Unsupported byteorder"
+        /* Need to add code here to re-instate mixed endian support.
+           NEEDS_SWAP would need to hold a flag indicating which action to
+           take, and S_reverse_copy and the code in uni_to_bytes would need
+           logic adding to deal with any mixed-endian transformations needed.
+        */
+#endif
 
 /* Only to be used inside a loop (see the break) */
 
 /* Only to be used inside a loop (see the break) */
-#define SHIFT_BYTES(utf8, s, strend, buf, len, datumtype)      \
+#define SHIFT_BYTES(utf8, s, strend, buf, len, datumtype, needs_swap)  \
 STMT_START {                                           \
 STMT_START {                                           \
-    if (utf8) {                                                \
+    if (UNLIKELY(utf8)) {                               \
         if (!uni_to_bytes(aTHX_ &s, strend,            \
          (char *) (buf), len, datumtype)) break;       \
     } else {                                           \
         if (!uni_to_bytes(aTHX_ &s, strend,            \
          (char *) (buf), len, datumtype)) break;       \
     } else {                                           \
-        Copy(s, (char *) (buf), len, char);            \
+        if (UNLIKELY(needs_swap))                       \
+            S_reverse_copy(s, (char *) (buf), len);     \
+        else                                            \
+            Copy(s, (char *) (buf), len, char);                \
         s += len;                                      \
     }                                                  \
 } STMT_END
 
         s += len;                                      \
     }                                                  \
 } STMT_END
 
-#define SHIFT_VAR(utf8, s, strend, var, datumtype)     \
-       SHIFT_BYTES(utf8, s, strend, &(var), sizeof(var), datumtype)
+#define SHIFT16(utf8, s, strend, p, datumtype, needs_swap)              \
+       SHIFT_BYTES(utf8, s, strend, OFF16(p), SIZE16, datumtype, needs_swap)
+
+#define SHIFT32(utf8, s, strend, p, datumtype, needs_swap)              \
+       SHIFT_BYTES(utf8, s, strend, OFF32(p), SIZE32, datumtype, needs_swap)
 
 
-#define PUSH_VAR(utf8, aptr, var)      \
-       PUSH_BYTES(utf8, aptr, &(var), sizeof(var))
+#define SHIFT_VAR(utf8, s, strend, var, datumtype, needs_swap)          \
+       SHIFT_BYTES(utf8, s, strend, &(var), sizeof(var), datumtype, needs_swap)
+
+#define PUSH_VAR(utf8, aptr, var, needs_swap)           \
+       PUSH_BYTES(utf8, aptr, &(var), sizeof(var), needs_swap)
 
 /* Avoid stack overflow due to pathological templates. 100 should be plenty. */
 #define MAX_SUB_TEMPLATE_LEVEL 100
 
 /* Avoid stack overflow due to pathological templates. 100 should be plenty. */
 #define MAX_SUB_TEMPLATE_LEVEL 100
@@ -237,146 +241,20 @@ S_mul128(pTHX_ SV *sv, U8 m)
 
 # define ENDIANNESS_ALLOWED_TYPES   "sSiIlLqQjJfFdDpP("
 
 
 # define ENDIANNESS_ALLOWED_TYPES   "sSiIlLqQjJfFdDpP("
 
-#if BYTEORDER == 0x4321 || BYTEORDER == 0x87654321  /* big-endian */
-
-# define DO_BO_UNPACK(var, type)                                              \
-        STMT_START {                                                          \
-          if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_LITTLE_ENDIAN) {          \
-            var = my_letoh ## type (var);                                     \
-          }                                                                   \
-        } STMT_END
-
-# define DO_BO_PACK(var, type)                                                \
-        STMT_START {                                                          \
-          if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_LITTLE_ENDIAN) {          \
-            var = my_htole ## type (var);                                     \
-          }                                                                   \
-        } STMT_END
-
-# define DO_BO_UNPACK_PTR(var, type, pre_cast, post_cast)                     \
-        STMT_START {                                                          \
-          if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_LITTLE_ENDIAN) {          \
-              var = (post_cast *) my_letoh ## type ((pre_cast) var);          \
-          }                                                                   \
-        } STMT_END
-
-# define DO_BO_PACK_PTR(var, type, pre_cast, post_cast)                       \
-        STMT_START {                                                          \
-          if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_LITTLE_ENDIAN) {          \
-              var = (post_cast *) my_htole ## type ((pre_cast) var);          \
-          }                                                                   \
-        } STMT_END
-
-# define DO_BO_UNPACK_N(var, type)                                            \
-         STMT_START {                                                         \
-           if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_LITTLE_ENDIAN) {         \
-              my_letohn(&var, sizeof(type));                                  \
-           }                                                                  \
-         } STMT_END
-
-# define DO_BO_PACK_N(var, type)                                              \
-         STMT_START {                                                         \
-           if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_LITTLE_ENDIAN) {         \
-             my_htolen(&var, sizeof(type));                                   \
-           }                                                                  \
-         } STMT_END
-
-#  elif BYTEORDER == 0x1234 || BYTEORDER == 0x12345678    /* little-endian */
-
-# define DO_BO_UNPACK(var, type)                                              \
-        STMT_START {                                                          \
-          if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_BIG_ENDIAN) {             \
-            var = my_betoh ## type (var);                                     \
-          }                                                                   \
-        } STMT_END
-
-# define DO_BO_PACK(var, type)                                                \
-        STMT_START {                                                          \
-          if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_BIG_ENDIAN) {             \
-            var = my_htobe ## type (var);                                     \
-          }                                                                   \
-        } STMT_END
-
-# define DO_BO_UNPACK_PTR(var, type, pre_cast, post_cast)                     \
-        STMT_START {                                                          \
-          if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_BIG_ENDIAN) {             \
-              var = (post_cast *) my_betoh ## type ((pre_cast) var);          \
-          }                                                                   \
-        } STMT_END
-
-# define DO_BO_PACK_PTR(var, type, pre_cast, post_cast)                       \
-        STMT_START {                                                          \
-          if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_BIG_ENDIAN) {             \
-              var = (post_cast *) my_htobe ## type ((pre_cast) var);          \
-          }                                                                   \
-        } STMT_END
-
-# define DO_BO_UNPACK_N(var, type)                                            \
-         STMT_START {                                                         \
-           if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_BIG_ENDIAN) {            \
-              my_betohn(&var, sizeof(type));                                  \
-           }                                                                  \
-         } STMT_END
-
-# define DO_BO_PACK_N(var, type)                                              \
-         STMT_START {                                                         \
-           if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_BIG_ENDIAN) {            \
-             my_htoben(&var, sizeof(type));                                   \
-           }                                                                  \
-         } STMT_END
-
-#else
-# define DO_BO_UNPACK(var, type)    BO_CANT_DOIT(unpack, type)
-# define DO_BO_PACK(var, type)      BO_CANT_DOIT(pack, type)
-# define DO_BO_UNPACK_PTR(var, type, pre_cast, post_cast)                    \
-    BO_CANT_DOIT(unpack, type)
-# define DO_BO_PACK_PTR(var, type, pre_cast, post_cast)                      \
-    BO_CANT_DOIT(pack, type)
-# define DO_BO_UNPACK_N(var, type)  BO_CANT_DOIT(unpack, type)
-# define DO_BO_PACK_N(var, type)    BO_CANT_DOIT(pack, type)
-#endif
-
-# define BO_CANT_DOIT(action, type)                                           \
-        STMT_START {                                                          \
-          switch (TYPE_ENDIANNESS(datumtype)) {                               \
-             case TYPE_IS_BIG_ENDIAN:                                         \
-               Perl_croak(aTHX_ "Can't %s big-endian %ss on this "            \
-                                "platform", #action, #type);                  \
-               break;                                                         \
-             case TYPE_IS_LITTLE_ENDIAN:                                      \
-               Perl_croak(aTHX_ "Can't %s little-endian %ss on this "         \
-                                "platform", #action, #type);                  \
-               break;                                                         \
-             default:                                                         \
-               break;                                                         \
-           }                                                                  \
-         } STMT_END
-
-# if PTRSIZE == INTSIZE
-#  define DO_BO_UNPACK_PC(var) DO_BO_UNPACK_PTR(var, i, int, char)
-#  define DO_BO_PACK_PC(var)   DO_BO_PACK_PTR(var, i, int, char)
-# elif PTRSIZE == LONGSIZE
-#  if LONGSIZE < IVSIZE && IVSIZE == 8
-#   define DO_BO_UNPACK_PC(var)        DO_BO_UNPACK_PTR(var, 64, IV, char)
-#   define DO_BO_PACK_PC(var)  DO_BO_PACK_PTR(var, 64, IV, char)
-#  else
-#   define DO_BO_UNPACK_PC(var)        DO_BO_UNPACK_PTR(var, l, IV, char)
-#   define DO_BO_PACK_PC(var)  DO_BO_PACK_PTR(var, l, IV, char)
-#  endif
-# elif PTRSIZE == IVSIZE
-#  define DO_BO_UNPACK_PC(var) DO_BO_UNPACK_PTR(var, l, IV, char)
-#  define DO_BO_PACK_PC(var)   DO_BO_PACK_PTR(var, l, IV, char)
-# else
-#  define DO_BO_UNPACK_PC(var) BO_CANT_DOIT(unpack, pointer)
-#  define DO_BO_PACK_PC(var)   BO_CANT_DOIT(pack, pointer)
-# endif
-
 #define PACK_SIZE_CANNOT_CSUM          0x80
 #define PACK_SIZE_UNPREDICTABLE                0x40    /* Not a fixed size element */
 #define PACK_SIZE_MASK                 0x3F
 
 #include "packsizetables.c"
 
 #define PACK_SIZE_CANNOT_CSUM          0x80
 #define PACK_SIZE_UNPREDICTABLE                0x40    /* Not a fixed size element */
 #define PACK_SIZE_MASK                 0x3F
 
 #include "packsizetables.c"
 
+static void
+S_reverse_copy(const char *src, char *dest, STRLEN len)
+{
+    dest += len;
+    while (len--)
+        *--dest = *src++;
+}
+
 STATIC U8
 uni_to_byte(pTHX_ const char **s, const char *end, I32 datumtype)
 {
 STATIC U8
 uni_to_byte(pTHX_ const char **s, const char *end, I32 datumtype)
 {
@@ -412,6 +290,11 @@ uni_to_bytes(pTHX_ const char **s, const char *end, const char *buf, int buf_len
     int bad = 0;
     const U32 flags = ckWARN(WARN_UTF8) ?
        UTF8_CHECK_ONLY : (UTF8_CHECK_ONLY | UTF8_ALLOW_ANY);
     int bad = 0;
     const U32 flags = ckWARN(WARN_UTF8) ?
        UTF8_CHECK_ONLY : (UTF8_CHECK_ONLY | UTF8_ALLOW_ANY);
+    const bool needs_swap = NEEDS_SWAP(datumtype);
+
+    if (UNLIKELY(needs_swap))
+        buf += buf_len;
+
     for (;buf_len > 0; buf_len--) {
        if (from >= end) return FALSE;
        val = utf8n_to_uvchr((U8 *) from, end-from, &retlen, flags);
     for (;buf_len > 0; buf_len--) {
        if (from >= end) return FALSE;
        val = utf8n_to_uvchr((U8 *) from, end-from, &retlen, flags);
@@ -423,7 +306,10 @@ uni_to_bytes(pTHX_ const char **s, const char *end, const char *buf, int buf_len
            bad |= 2;
            val &= 0xff;
        }
            bad |= 2;
            val &= 0xff;
        }
-       *(U8 *)buf++ = (U8)val;
+        if (UNLIKELY(needs_swap))
+            *(U8 *)--buf = (U8)val;
+        else
+            *(U8 *)buf++ = (U8)val;
     }
     /* We have enough characters for the buffer. Did we have problems ? */
     if (bad) {
     }
     /* We have enough characters for the buffer. Did we have problems ? */
     if (bad) {
@@ -433,7 +319,7 @@ uni_to_bytes(pTHX_ const char **s, const char *end, const char *buf, int buf_len
            const int flags = ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANY;
            for (ptr = *s; ptr < from; ptr += UTF8SKIP(ptr)) {
                if (ptr >= end) break;
            const int flags = ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANY;
            for (ptr = *s; ptr < from; ptr += UTF8SKIP(ptr)) {
                if (ptr >= end) break;
-               utf8n_to_uvuni((U8 *) ptr, end-ptr, &retlen, flags);
+               utf8n_to_uvchr((U8 *) ptr, end-ptr, &retlen, flags);
            }
            if (from > end) from = end;
        }
            }
            if (from > end) from = end;
        }
@@ -465,30 +351,33 @@ next_uni_uu(pTHX_ const char **s, const char *end, I32 *out)
 }
 
 STATIC char *
 }
 
 STATIC char *
-S_bytes_to_uni(const U8 *start, STRLEN len, char *dest) {
-    const U8 * const end = start + len;
-
+S_bytes_to_uni(const U8 *start, STRLEN len, char *dest, const bool needs_swap) {
     PERL_ARGS_ASSERT_BYTES_TO_UNI;
 
     PERL_ARGS_ASSERT_BYTES_TO_UNI;
 
-    while (start < end) {
-       const UV uv = NATIVE_TO_ASCII(*start);
-       if (UNI_IS_INVARIANT(uv))
-           *dest++ = (char)(U8)UTF_TO_NATIVE(uv);
-       else {
-           *dest++ = (char)(U8)UTF8_EIGHT_BIT_HI(uv);
-           *dest++ = (char)(U8)UTF8_EIGHT_BIT_LO(uv);
-       }
-       start++;
+    if (UNLIKELY(needs_swap)) {
+        const U8 *p = start + len;
+        while (p-- > start) {
+            append_utf8_from_native_byte(*p, (U8 **) & dest);
+        }
+    } else {
+        const U8 * const end = start + len;
+        while (start < end) {
+            append_utf8_from_native_byte(*start, (U8 **) & dest);
+            start++;
+        }
     }
     return dest;
 }
 
     }
     return dest;
 }
 
-#define PUSH_BYTES(utf8, cur, buf, len)                                \
+#define PUSH_BYTES(utf8, cur, buf, len, needs_swap)             \
 STMT_START {                                                   \
 STMT_START {                                                   \
-    if (utf8)                                                  \
-       (cur) = bytes_to_uni((U8 *) buf, len, (cur));           \
+    if (UNLIKELY(utf8))                                                \
+       (cur) = S_bytes_to_uni((U8 *) buf, len, (cur), needs_swap);       \
     else {                                                     \
     else {                                                     \
-       Copy(buf, cur, len, char);                              \
+        if (UNLIKELY(needs_swap))                               \
+            S_reverse_copy((char *)(buf), cur, len);            \
+        else                                                    \
+            Copy(buf, cur, len, char);                         \
        (cur) += (len);                                         \
     }                                                          \
 } STMT_END
        (cur) += (len);                                         \
     }                                                          \
 } STMT_END
@@ -514,14 +403,14 @@ STMT_START {                                      \
        (start) = sv_exp_grow(cat, gl);         \
        (cur) = (start) + SvCUR(cat);           \
     }                                          \
        (start) = sv_exp_grow(cat, gl);         \
        (cur) = (start) + SvCUR(cat);           \
     }                                          \
-    PUSH_BYTES(utf8, cur, buf, glen);          \
+    PUSH_BYTES(utf8, cur, buf, glen, 0);        \
 } STMT_END
 
 #define PUSH_BYTE(utf8, s, byte)               \
 STMT_START {                                   \
     if (utf8) {                                        \
        const U8 au8 = (byte);                  \
 } STMT_END
 
 #define PUSH_BYTE(utf8, s, byte)               \
 STMT_START {                                   \
     if (utf8) {                                        \
        const U8 au8 = (byte);                  \
-       (s) = bytes_to_uni(&au8, 1, (s));       \
+       (s) = S_bytes_to_uni(&au8, 1, (s), 0);  \
     } else *(U8 *)(s)++ = (byte);              \
 } STMT_END
 
     } else *(U8 *)(s)++ = (byte);              \
 } STMT_END
 
@@ -928,7 +817,7 @@ The engine implementing the unpack() Perl function.
 Using the template pat..patend, this function unpacks the string
 s..strend into a number of mortal SVs, which it pushes onto the perl
 argument (@_) stack (so you will need to issue a C<PUTBACK> before and
 Using the template pat..patend, this function unpacks the string
 s..strend into a number of mortal SVs, which it pushes onto the perl
 argument (@_) stack (so you will need to issue a C<PUTBACK> before and
-C<SPAGAIN> after the call to this function). It returns the number of
+C<SPAGAIN> after the call to this function).  It returns the number of
 pushed elements.
 
 The strend and patend pointers should point to the byte following the last
 pushed elements.
 
 The strend and patend pointers should point to the byte following the last
@@ -991,6 +880,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        packprops_t props;
        I32 len;
         I32 datumtype = symptr->code;
        packprops_t props;
        I32 len;
         I32 datumtype = symptr->code;
+        bool needs_swap;
        /* do first one only unless in list context
           / is implemented by unpacking the count, then popping it from the
           stack, so must check that we're not in the middle of a /  */
        /* do first one only unless in list context
           / is implemented by unpacking the count, then popping it from the
           stack, so must check that we're not in the middle of a /  */
@@ -1028,6 +918,8 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
            }
        }
 
            }
        }
 
+        needs_swap = NEEDS_SWAP(datumtype);
+
        switch(TYPE_NO_ENDIANNESS(datumtype)) {
        default:
            Perl_croak(aTHX_ "Invalid type '%c' in unpack", (int)TYPE_NO_MODIFIERS(datumtype) );
        switch(TYPE_NO_ENDIANNESS(datumtype)) {
        default:
            Perl_croak(aTHX_ "Invalid type '%c' in unpack", (int)TYPE_NO_MODIFIERS(datumtype) );
@@ -1424,10 +1316,10 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
                    len = UTF8SKIP(result);
                    if (!uni_to_bytes(aTHX_ &ptr, strend,
                                      (char *) &result[1], len-1, 'U')) break;
                    len = UTF8SKIP(result);
                    if (!uni_to_bytes(aTHX_ &ptr, strend,
                                      (char *) &result[1], len-1, 'U')) break;
-                   auv = utf8n_to_uvuni(result, len, &retlen, UTF8_ALLOW_DEFAULT);
+                   auv = utf8n_to_uvchr(result, len, &retlen, UTF8_ALLOW_DEFAULT);
                    s = ptr;
                } else {
                    s = ptr;
                } else {
-                   auv = utf8n_to_uvuni((U8*)s, strend - s, &retlen, UTF8_ALLOW_DEFAULT);
+                   auv = utf8n_to_uvchr((U8*)s, strend - s, &retlen, UTF8_ALLOW_DEFAULT);
                    if (retlen == (STRLEN) -1 || retlen == 0)
                        Perl_croak(aTHX_ "Malformed UTF-8 string in unpack");
                    s += retlen;
                    if (retlen == (STRLEN) -1 || retlen == 0)
                        Perl_croak(aTHX_ "Malformed UTF-8 string in unpack");
                    s += retlen;
@@ -1444,8 +1336,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if SHORTSIZE != SIZE16
            while (len-- > 0) {
                short ashort;
 #if SHORTSIZE != SIZE16
            while (len-- > 0) {
                short ashort;
-               SHIFT_VAR(utf8, s, strend, ashort, datumtype);
-               DO_BO_UNPACK(ashort, s);
+                SHIFT_VAR(utf8, s, strend, ashort, datumtype, needs_swap);
                if (!checksum)
                    mPUSHi(ashort);
                else if (checksum > bits_in_uv)
                if (!checksum)
                    mPUSHi(ashort);
                else if (checksum > bits_in_uv)
@@ -1464,8 +1355,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if U16SIZE > SIZE16
                ai16 = 0;
 #endif
 #if U16SIZE > SIZE16
                ai16 = 0;
 #endif
-               SHIFT16(utf8, s, strend, &ai16, datumtype);
-               DO_BO_UNPACK(ai16, 16);
+                SHIFT16(utf8, s, strend, &ai16, datumtype, needs_swap);
 #if U16SIZE > SIZE16
                if (ai16 > 32767)
                    ai16 -= 65536;
 #if U16SIZE > SIZE16
                if (ai16 > 32767)
                    ai16 -= 65536;
@@ -1482,8 +1372,8 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if SHORTSIZE != SIZE16
            while (len-- > 0) {
                unsigned short aushort;
 #if SHORTSIZE != SIZE16
            while (len-- > 0) {
                unsigned short aushort;
-               SHIFT_VAR(utf8, s, strend, aushort, datumtype);
-               DO_BO_UNPACK(aushort, s);
+                SHIFT_VAR(utf8, s, strend, aushort, datumtype, needs_swap,
+                          needs_swap);
                if (!checksum)
                    mPUSHu(aushort);
                else if (checksum > bits_in_uv)
                if (!checksum)
                    mPUSHu(aushort);
                else if (checksum > bits_in_uv)
@@ -1503,8 +1393,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if U16SIZE > SIZE16
                au16 = 0;
 #endif
 #if U16SIZE > SIZE16
                au16 = 0;
 #endif
-               SHIFT16(utf8, s, strend, &au16, datumtype);
-               DO_BO_UNPACK(au16, 16);
+                SHIFT16(utf8, s, strend, &au16, datumtype, needs_swap);
                if (datumtype == 'n')
                    au16 = PerlSock_ntohs(au16);
                if (datumtype == 'v')
                if (datumtype == 'n')
                    au16 = PerlSock_ntohs(au16);
                if (datumtype == 'v')
@@ -1524,7 +1413,9 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 # if U16SIZE > SIZE16
                ai16 = 0;
 # endif
 # if U16SIZE > SIZE16
                ai16 = 0;
 # endif
-               SHIFT16(utf8, s, strend, &ai16, datumtype);
+                SHIFT16(utf8, s, strend, &ai16, datumtype, needs_swap);
+                /* There should never be any byte-swapping here.  */
+                assert(!TYPE_ENDIANNESS(datumtype));
                if (datumtype == ('n' | TYPE_IS_SHRIEKING))
                    ai16 = (I16) PerlSock_ntohs((U16) ai16);
                if (datumtype == ('v' | TYPE_IS_SHRIEKING))
                if (datumtype == ('n' | TYPE_IS_SHRIEKING))
                    ai16 = (I16) PerlSock_ntohs((U16) ai16);
                if (datumtype == ('v' | TYPE_IS_SHRIEKING))
@@ -1541,8 +1432,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'i' | TYPE_IS_SHRIEKING:
            while (len-- > 0) {
                int aint;
        case 'i' | TYPE_IS_SHRIEKING:
            while (len-- > 0) {
                int aint;
-               SHIFT_VAR(utf8, s, strend, aint, datumtype);
-               DO_BO_UNPACK(aint, i);
+                SHIFT_VAR(utf8, s, strend, aint, datumtype, needs_swap);
                if (!checksum)
                    mPUSHi(aint);
                else if (checksum > bits_in_uv)
                if (!checksum)
                    mPUSHi(aint);
                else if (checksum > bits_in_uv)
@@ -1555,8 +1445,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'I' | TYPE_IS_SHRIEKING:
            while (len-- > 0) {
                unsigned int auint;
        case 'I' | TYPE_IS_SHRIEKING:
            while (len-- > 0) {
                unsigned int auint;
-               SHIFT_VAR(utf8, s, strend, auint, datumtype);
-               DO_BO_UNPACK(auint, i);
+                SHIFT_VAR(utf8, s, strend, auint, datumtype, needs_swap);
                if (!checksum)
                    mPUSHu(auint);
                else if (checksum > bits_in_uv)
                if (!checksum)
                    mPUSHu(auint);
                else if (checksum > bits_in_uv)
@@ -1568,16 +1457,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'j':
            while (len-- > 0) {
                IV aiv;
        case 'j':
            while (len-- > 0) {
                IV aiv;
-               SHIFT_VAR(utf8, s, strend, aiv, datumtype);
-#if IVSIZE == INTSIZE
-               DO_BO_UNPACK(aiv, i);
-#elif IVSIZE == LONGSIZE
-               DO_BO_UNPACK(aiv, l);
-#elif defined(HAS_QUAD) && IVSIZE == U64SIZE
-               DO_BO_UNPACK(aiv, 64);
-#else
-               Perl_croak(aTHX_ "'j' not supported on this platform");
-#endif
+                SHIFT_VAR(utf8, s, strend, aiv, datumtype, needs_swap);
                if (!checksum)
                    mPUSHi(aiv);
                else if (checksum > bits_in_uv)
                if (!checksum)
                    mPUSHi(aiv);
                else if (checksum > bits_in_uv)
@@ -1589,16 +1469,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'J':
            while (len-- > 0) {
                UV auv;
        case 'J':
            while (len-- > 0) {
                UV auv;
-               SHIFT_VAR(utf8, s, strend, auv, datumtype);
-#if IVSIZE == INTSIZE
-               DO_BO_UNPACK(auv, i);
-#elif IVSIZE == LONGSIZE
-               DO_BO_UNPACK(auv, l);
-#elif defined(HAS_QUAD) && IVSIZE == U64SIZE
-               DO_BO_UNPACK(auv, 64);
-#else
-               Perl_croak(aTHX_ "'J' not supported on this platform");
-#endif
+                SHIFT_VAR(utf8, s, strend, auv, datumtype, needs_swap);
                if (!checksum)
                    mPUSHu(auv);
                else if (checksum > bits_in_uv)
                if (!checksum)
                    mPUSHu(auv);
                else if (checksum > bits_in_uv)
@@ -1611,8 +1482,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if LONGSIZE != SIZE32
            while (len-- > 0) {
                long along;
 #if LONGSIZE != SIZE32
            while (len-- > 0) {
                long along;
-               SHIFT_VAR(utf8, s, strend, along, datumtype);
-               DO_BO_UNPACK(along, l);
+                SHIFT_VAR(utf8, s, strend, along, datumtype, needs_swap);
                if (!checksum)
                    mPUSHi(along);
                else if (checksum > bits_in_uv)
                if (!checksum)
                    mPUSHi(along);
                else if (checksum > bits_in_uv)
@@ -1630,8 +1500,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if U32SIZE > SIZE32
                ai32 = 0;
 #endif
 #if U32SIZE > SIZE32
                ai32 = 0;
 #endif
-               SHIFT32(utf8, s, strend, &ai32, datumtype);
-               DO_BO_UNPACK(ai32, 32);
+                SHIFT32(utf8, s, strend, &ai32, datumtype, needs_swap);
 #if U32SIZE > SIZE32
                if (ai32 > 2147483647) ai32 -= 4294967296;
 #endif
 #if U32SIZE > SIZE32
                if (ai32 > 2147483647) ai32 -= 4294967296;
 #endif
@@ -1647,8 +1516,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if LONGSIZE != SIZE32
            while (len-- > 0) {
                unsigned long aulong;
 #if LONGSIZE != SIZE32
            while (len-- > 0) {
                unsigned long aulong;
-               SHIFT_VAR(utf8, s, strend, aulong, datumtype);
-               DO_BO_UNPACK(aulong, l);
+                SHIFT_VAR(utf8, s, strend, aulong, datumtype, needs_swap);
                if (!checksum)
                    mPUSHu(aulong);
                else if (checksum > bits_in_uv)
                if (!checksum)
                    mPUSHu(aulong);
                else if (checksum > bits_in_uv)
@@ -1668,8 +1536,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if U32SIZE > SIZE32
                au32 = 0;
 #endif
 #if U32SIZE > SIZE32
                au32 = 0;
 #endif
-               SHIFT32(utf8, s, strend, &au32, datumtype);
-               DO_BO_UNPACK(au32, 32);
+                SHIFT32(utf8, s, strend, &au32, datumtype, needs_swap);
                if (datumtype == 'N')
                    au32 = PerlSock_ntohl(au32);
                if (datumtype == 'V')
                if (datumtype == 'N')
                    au32 = PerlSock_ntohl(au32);
                if (datumtype == 'V')
@@ -1689,7 +1556,9 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
 #if U32SIZE > SIZE32
                ai32 = 0;
 #endif
 #if U32SIZE > SIZE32
                ai32 = 0;
 #endif
-               SHIFT32(utf8, s, strend, &ai32, datumtype);
+                SHIFT32(utf8, s, strend, &ai32, datumtype, needs_swap);
+                /* There should never be any byte swapping here.  */
+                assert(!TYPE_ENDIANNESS(datumtype));
                if (datumtype == ('N' | TYPE_IS_SHRIEKING))
                    ai32 = (I32)PerlSock_ntohl((U32)ai32);
                if (datumtype == ('V' | TYPE_IS_SHRIEKING))
                if (datumtype == ('N' | TYPE_IS_SHRIEKING))
                    ai32 = (I32)PerlSock_ntohl((U32)ai32);
                if (datumtype == ('V' | TYPE_IS_SHRIEKING))
@@ -1705,8 +1574,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'p':
            while (len-- > 0) {
                const char *aptr;
        case 'p':
            while (len-- > 0) {
                const char *aptr;
-               SHIFT_VAR(utf8, s, strend, aptr, datumtype);
-               DO_BO_UNPACK_PC(aptr);
+                SHIFT_VAR(utf8, s, strend, aptr, datumtype, needs_swap);
                /* newSVpv generates undef if aptr is NULL */
                mPUSHs(newSVpv(aptr, 0));
            }
                /* newSVpv generates undef if aptr is NULL */
                mPUSHs(newSVpv(aptr, 0));
            }
@@ -1759,18 +1627,16 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
            EXTEND(SP, 1);
            if (s + sizeof(char*) <= strend) {
                char *aptr;
            EXTEND(SP, 1);
            if (s + sizeof(char*) <= strend) {
                char *aptr;
-               SHIFT_VAR(utf8, s, strend, aptr, datumtype);
-               DO_BO_UNPACK_PC(aptr);
+                SHIFT_VAR(utf8, s, strend, aptr, datumtype, needs_swap);
                /* newSVpvn generates undef if aptr is NULL */
                PUSHs(newSVpvn_flags(aptr, len, SVs_TEMP));
            }
            break;
                /* newSVpvn generates undef if aptr is NULL */
                PUSHs(newSVpvn_flags(aptr, len, SVs_TEMP));
            }
            break;
-#ifdef HAS_QUAD
+#if IVSIZE >= 8
        case 'q':
            while (len-- > 0) {
                Quad_t aquad;
        case 'q':
            while (len-- > 0) {
                Quad_t aquad;
-               SHIFT_VAR(utf8, s, strend, aquad, datumtype);
-               DO_BO_UNPACK(aquad, 64);
+                SHIFT_VAR(utf8, s, strend, aquad, datumtype, needs_swap);
                if (!checksum)
                     mPUSHs(aquad >= IV_MIN && aquad <= IV_MAX ?
                           newSViv((IV)aquad) : newSVnv((NV)aquad));
                if (!checksum)
                     mPUSHs(aquad >= IV_MIN && aquad <= IV_MAX ?
                           newSViv((IV)aquad) : newSVnv((NV)aquad));
@@ -1783,8 +1649,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'Q':
            while (len-- > 0) {
                Uquad_t auquad;
        case 'Q':
            while (len-- > 0) {
                Uquad_t auquad;
-               SHIFT_VAR(utf8, s, strend, auquad, datumtype);
-               DO_BO_UNPACK(auquad, 64);
+                SHIFT_VAR(utf8, s, strend, auquad, datumtype, needs_swap);
                if (!checksum)
                    mPUSHs(auquad <= UV_MAX ?
                           newSVuv((UV)auquad) : newSVnv((NV)auquad));
                if (!checksum)
                    mPUSHs(auquad <= UV_MAX ?
                           newSVuv((UV)auquad) : newSVnv((NV)auquad));
@@ -1794,13 +1659,12 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
                    cuv += auquad;
            }
            break;
                    cuv += auquad;
            }
            break;
-#endif /* HAS_QUAD */
+#endif
        /* float and double added gnb@melba.bby.oz.au 22/11/89 */
        case 'f':
            while (len-- > 0) {
                float afloat;
        /* float and double added gnb@melba.bby.oz.au 22/11/89 */
        case 'f':
            while (len-- > 0) {
                float afloat;
-               SHIFT_VAR(utf8, s, strend, afloat, datumtype);
-               DO_BO_UNPACK_N(afloat, float);
+                SHIFT_VAR(utf8, s, strend, afloat, datumtype, needs_swap);
                if (!checksum)
                    mPUSHn(afloat);
                else
                if (!checksum)
                    mPUSHn(afloat);
                else
@@ -1810,8 +1674,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'd':
            while (len-- > 0) {
                double adouble;
        case 'd':
            while (len-- > 0) {
                double adouble;
-               SHIFT_VAR(utf8, s, strend, adouble, datumtype);
-               DO_BO_UNPACK_N(adouble, double);
+                SHIFT_VAR(utf8, s, strend, adouble, datumtype, needs_swap);
                if (!checksum)
                    mPUSHn(adouble);
                else
                if (!checksum)
                    mPUSHn(adouble);
                else
@@ -1821,8 +1684,8 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'F':
            while (len-- > 0) {
                NV_bytes anv;
        case 'F':
            while (len-- > 0) {
                NV_bytes anv;
-               SHIFT_BYTES(utf8, s, strend, anv.bytes, sizeof(anv.bytes), datumtype);
-               DO_BO_UNPACK_N(anv.nv, NV);
+                SHIFT_BYTES(utf8, s, strend, anv.bytes, sizeof(anv.bytes),
+                            datumtype, needs_swap);
                if (!checksum)
                    mPUSHn(anv.nv);
                else
                if (!checksum)
                    mPUSHn(anv.nv);
                else
@@ -1833,8 +1696,8 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
        case 'D':
            while (len-- > 0) {
                ld_bytes aldouble;
        case 'D':
            while (len-- > 0) {
                ld_bytes aldouble;
-               SHIFT_BYTES(utf8, s, strend, aldouble.bytes, sizeof(aldouble.bytes), datumtype);
-               DO_BO_UNPACK_N(aldouble.ld, long double);
+                SHIFT_BYTES(utf8, s, strend, aldouble.bytes,
+                            sizeof(aldouble.bytes), datumtype, needs_swap);
                if (!checksum)
                    mPUSHn(aldouble.ld);
                else
                if (!checksum)
                    mPUSHn(aldouble.ld);
                else
@@ -2140,7 +2003,7 @@ marked_upgrade(pTHX_ SV *sv, tempsym_t *sym_ptr) {
     from_start = SvPVX_const(sv);
     from_end = from_start + SvCUR(sv);
     for (from_ptr = from_start; from_ptr < from_end; from_ptr++)
     from_start = SvPVX_const(sv);
     from_end = from_start + SvCUR(sv);
     for (from_ptr = from_start; from_ptr < from_end; from_ptr++)
-       if (!NATIVE_IS_INVARIANT(*from_ptr)) break;
+       if (!NATIVE_BYTE_IS_INVARIANT(*from_ptr)) break;
     if (from_ptr == from_end) {
        /* Simple case: no character needs to be changed */
        SvUTF8_on(sv);
     if (from_ptr == from_end) {
        /* Simple case: no character needs to be changed */
        SvUTF8_on(sv);
@@ -2238,6 +2101,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
         howlen_t howlen = symptr->howlen;
        char *start = SvPVX(cat);
        char *cur   = start + SvCUR(cat);
         howlen_t howlen = symptr->howlen;
        char *start = SvPVX(cat);
        char *cur   = start + SvCUR(cat);
+        bool needs_swap;
 
 #define NEXTFROM (lengthcode ? lengthcode : items-- > 0 ? *beglist++ : &PL_sv_no)
 
 
 #define NEXTFROM (lengthcode ? lengthcode : items-- > 0 ? *beglist++ : &PL_sv_no)
 
@@ -2287,6 +2151,8 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
            lengthcode = sv_2mortal(newSViv(count));
        }
 
            lengthcode = sv_2mortal(newSViv(count));
        }
 
+        needs_swap = NEEDS_SWAP(datumtype);
+
        /* Code inside the switch must take care to properly update
           cat (CUR length and '\0' termination) if it updated *cur and
           doesn't simply leave using break */
        /* Code inside the switch must take care to properly update
           cat (CUR length and '\0' termination) if it updated *cur and
           doesn't simply leave using break */
@@ -2719,8 +2585,8 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                        GROWING(0, cat, start, cur, len+UTF8_MAXLEN);
                        end = start+SvLEN(cat)-UTF8_MAXLEN;
                    }
                        GROWING(0, cat, start, cur, len+UTF8_MAXLEN);
                        end = start+SvLEN(cat)-UTF8_MAXLEN;
                    }
-                   cur = (char *) uvuni_to_utf8_flags((U8 *) cur,
-                                                      NATIVE_TO_UNI(auv),
+                   cur = (char *) uvchr_to_utf8_flags((U8 *) cur,
+                                                      auv,
                                                       warn_utf8 ?
                                                       0 : UNICODE_ALLOW_ANY);
                } else {
                                                       warn_utf8 ?
                                                       0 : UNICODE_ALLOW_ANY);
                } else {
@@ -2773,7 +2639,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                auv = SvUV(fromstr);
                if (utf8) {
                    U8 buffer[UTF8_MAXLEN], *endb;
                auv = SvUV(fromstr);
                if (utf8) {
                    U8 buffer[UTF8_MAXLEN], *endb;
-                   endb = uvuni_to_utf8_flags(buffer, auv,
+                   endb = uvchr_to_utf8_flags(buffer, auv,
                                               warn_utf8 ?
                                               0 : UNICODE_ALLOW_ANY);
                    if (cur+(endb-buffer)*UTF8_EXPAND >= end) {
                                               warn_utf8 ?
                                               0 : UNICODE_ALLOW_ANY);
                    if (cur+(endb-buffer)*UTF8_EXPAND >= end) {
@@ -2783,7 +2649,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                                len+(endb-buffer)*UTF8_EXPAND);
                        end = start+SvLEN(cat);
                    }
                                len+(endb-buffer)*UTF8_EXPAND);
                        end = start+SvLEN(cat);
                    }
-                   cur = bytes_to_uni(buffer, endb-buffer, cur);
+                    cur = S_bytes_to_uni(buffer, endb-buffer, cur, 0);
                } else {
                    if (cur >= end) {
                        *cur = '\0';
                } else {
                    if (cur >= end) {
                        *cur = '\0';
@@ -2791,7 +2657,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                        GROWING(0, cat, start, cur, len+UTF8_MAXLEN);
                        end = start+SvLEN(cat)-UTF8_MAXLEN;
                    }
                        GROWING(0, cat, start, cur, len+UTF8_MAXLEN);
                        end = start+SvLEN(cat)-UTF8_MAXLEN;
                    }
-                   cur = (char *) uvuni_to_utf8_flags((U8 *) cur, auv,
+                   cur = (char *) uvchr_to_utf8_flags((U8 *) cur, auv,
                                                       warn_utf8 ?
                                                       0 : UNICODE_ALLOW_ANY);
                }
                                                       warn_utf8 ?
                                                       0 : UNICODE_ALLOW_ANY);
                }
@@ -2817,8 +2683,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
 # else
                afloat = (float)anv;
 # endif
 # else
                afloat = (float)anv;
 # endif
-               DO_BO_PACK_N(afloat, float);
-               PUSH_VAR(utf8, cur, afloat);
+                PUSH_VAR(utf8, cur, afloat, needs_swap);
            }
            break;
        case 'd':
            }
            break;
        case 'd':
@@ -2839,8 +2704,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
 # else
                adouble = (double)anv;
 # endif
 # else
                adouble = (double)anv;
 # endif
-               DO_BO_PACK_N(adouble, double);
-               PUSH_VAR(utf8, cur, adouble);
+                PUSH_VAR(utf8, cur, adouble, needs_swap);
            }
            break;
        case 'F': {
            }
            break;
        case 'F': {
@@ -2854,8 +2718,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
 #else
                anv.nv = SvNV(fromstr);
 #endif
 #else
                anv.nv = SvNV(fromstr);
 #endif
-               DO_BO_PACK_N(anv, NV);
-               PUSH_BYTES(utf8, cur, anv.bytes, sizeof(anv.bytes));
+                PUSH_BYTES(utf8, cur, anv.bytes, sizeof(anv.bytes), needs_swap);
            }
            break;
        }
            }
            break;
        }
@@ -2872,8 +2735,8 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
 #  else
                aldouble.ld = (long double)SvNV(fromstr);
 #  endif
 #  else
                aldouble.ld = (long double)SvNV(fromstr);
 #  endif
-               DO_BO_PACK_N(aldouble, long double);
-               PUSH_BYTES(utf8, cur, aldouble.bytes, sizeof(aldouble.bytes));
+                PUSH_BYTES(utf8, cur, aldouble.bytes, sizeof(aldouble.bytes),
+                           needs_swap);
            }
            break;
        }
            }
            break;
        }
@@ -2885,7 +2748,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                fromstr = NEXTFROM;
                ai16 = (I16)SvIV(fromstr);
                ai16 = PerlSock_htons(ai16);
                fromstr = NEXTFROM;
                ai16 = (I16)SvIV(fromstr);
                ai16 = PerlSock_htons(ai16);
-               PUSH16(utf8, cur, &ai16);
+                PUSH16(utf8, cur, &ai16, FALSE);
            }
            break;
        case 'v' | TYPE_IS_SHRIEKING:
            }
            break;
        case 'v' | TYPE_IS_SHRIEKING:
@@ -2895,7 +2758,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                fromstr = NEXTFROM;
                ai16 = (I16)SvIV(fromstr);
                ai16 = htovs(ai16);
                fromstr = NEXTFROM;
                ai16 = (I16)SvIV(fromstr);
                ai16 = htovs(ai16);
-               PUSH16(utf8, cur, &ai16);
+                PUSH16(utf8, cur, &ai16, FALSE);
            }
            break;
         case 'S' | TYPE_IS_SHRIEKING:
            }
            break;
         case 'S' | TYPE_IS_SHRIEKING:
@@ -2904,8 +2767,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                unsigned short aushort;
                fromstr = NEXTFROM;
                aushort = SvUV(fromstr);
                unsigned short aushort;
                fromstr = NEXTFROM;
                aushort = SvUV(fromstr);
-               DO_BO_PACK(aushort, s);
-               PUSH_VAR(utf8, cur, aushort);
+                PUSH_VAR(utf8, cur, aushort, needs_swap);
            }
             break;
 #else
            }
             break;
 #else
@@ -2916,8 +2778,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                U16 au16;
                fromstr = NEXTFROM;
                au16 = (U16)SvUV(fromstr);
                U16 au16;
                fromstr = NEXTFROM;
                au16 = (U16)SvUV(fromstr);
-               DO_BO_PACK(au16, 16);
-               PUSH16(utf8, cur, &au16);
+                PUSH16(utf8, cur, &au16, needs_swap);
            }
            break;
        case 's' | TYPE_IS_SHRIEKING:
            }
            break;
        case 's' | TYPE_IS_SHRIEKING:
@@ -2926,8 +2787,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                short ashort;
                fromstr = NEXTFROM;
                ashort = SvIV(fromstr);
                short ashort;
                fromstr = NEXTFROM;
                ashort = SvIV(fromstr);
-               DO_BO_PACK(ashort, s);
-               PUSH_VAR(utf8, cur, ashort);
+                PUSH_VAR(utf8, cur, ashort, needs_swap);
            }
             break;
 #else
            }
             break;
 #else
@@ -2938,8 +2798,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                I16 ai16;
                fromstr = NEXTFROM;
                ai16 = (I16)SvIV(fromstr);
                I16 ai16;
                fromstr = NEXTFROM;
                ai16 = (I16)SvIV(fromstr);
-               DO_BO_PACK(ai16, 16);
-               PUSH16(utf8, cur, &ai16);
+                PUSH16(utf8, cur, &ai16, needs_swap);
            }
            break;
        case 'I':
            }
            break;
        case 'I':
@@ -2948,8 +2807,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                unsigned int auint;
                fromstr = NEXTFROM;
                auint = SvUV(fromstr);
                unsigned int auint;
                fromstr = NEXTFROM;
                auint = SvUV(fromstr);
-               DO_BO_PACK(auint, i);
-               PUSH_VAR(utf8, cur, auint);
+                PUSH_VAR(utf8, cur, auint, needs_swap);
            }
            break;
        case 'j':
            }
            break;
        case 'j':
@@ -2957,16 +2815,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                IV aiv;
                fromstr = NEXTFROM;
                aiv = SvIV(fromstr);
                IV aiv;
                fromstr = NEXTFROM;
                aiv = SvIV(fromstr);
-#if IVSIZE == INTSIZE
-               DO_BO_PACK(aiv, i);
-#elif IVSIZE == LONGSIZE
-               DO_BO_PACK(aiv, l);
-#elif defined(HAS_QUAD) && IVSIZE == U64SIZE
-               DO_BO_PACK(aiv, 64);
-#else
-               Perl_croak(aTHX_ "'j' not supported on this platform");
-#endif
-               PUSH_VAR(utf8, cur, aiv);
+                PUSH_VAR(utf8, cur, aiv, needs_swap);
            }
            break;
        case 'J':
            }
            break;
        case 'J':
@@ -2974,16 +2823,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                UV auv;
                fromstr = NEXTFROM;
                auv = SvUV(fromstr);
                UV auv;
                fromstr = NEXTFROM;
                auv = SvUV(fromstr);
-#if UVSIZE == INTSIZE
-               DO_BO_PACK(auv, i);
-#elif UVSIZE == LONGSIZE
-               DO_BO_PACK(auv, l);
-#elif defined(HAS_QUAD) && UVSIZE == U64SIZE
-               DO_BO_PACK(auv, 64);
-#else
-               Perl_croak(aTHX_ "'J' not supported on this platform");
-#endif
-               PUSH_VAR(utf8, cur, auv);
+                PUSH_VAR(utf8, cur, auv, needs_swap);
            }
            break;
        case 'w':
            }
            break;
        case 'w':
@@ -3079,8 +2919,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                int aint;
                fromstr = NEXTFROM;
                aint = SvIV(fromstr);
                int aint;
                fromstr = NEXTFROM;
                aint = SvIV(fromstr);
-               DO_BO_PACK(aint, i);
-               PUSH_VAR(utf8, cur, aint);
+                PUSH_VAR(utf8, cur, aint, needs_swap);
            }
            break;
        case 'N' | TYPE_IS_SHRIEKING:
            }
            break;
        case 'N' | TYPE_IS_SHRIEKING:
@@ -3090,7 +2929,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                fromstr = NEXTFROM;
                au32 = SvUV(fromstr);
                au32 = PerlSock_htonl(au32);
                fromstr = NEXTFROM;
                au32 = SvUV(fromstr);
                au32 = PerlSock_htonl(au32);
-               PUSH32(utf8, cur, &au32);
+                PUSH32(utf8, cur, &au32, FALSE);
            }
            break;
        case 'V' | TYPE_IS_SHRIEKING:
            }
            break;
        case 'V' | TYPE_IS_SHRIEKING:
@@ -3100,7 +2939,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                fromstr = NEXTFROM;
                au32 = SvUV(fromstr);
                au32 = htovl(au32);
                fromstr = NEXTFROM;
                au32 = SvUV(fromstr);
                au32 = htovl(au32);
-               PUSH32(utf8, cur, &au32);
+                PUSH32(utf8, cur, &au32, FALSE);
            }
            break;
        case 'L' | TYPE_IS_SHRIEKING:
            }
            break;
        case 'L' | TYPE_IS_SHRIEKING:
@@ -3109,8 +2948,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                unsigned long aulong;
                fromstr = NEXTFROM;
                aulong = SvUV(fromstr);
                unsigned long aulong;
                fromstr = NEXTFROM;
                aulong = SvUV(fromstr);
-               DO_BO_PACK(aulong, l);
-               PUSH_VAR(utf8, cur, aulong);
+                PUSH_VAR(utf8, cur, aulong, needs_swap);
            }
            break;
 #else
            }
            break;
 #else
@@ -3121,8 +2959,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                U32 au32;
                fromstr = NEXTFROM;
                au32 = SvUV(fromstr);
                U32 au32;
                fromstr = NEXTFROM;
                au32 = SvUV(fromstr);
-               DO_BO_PACK(au32, 32);
-               PUSH32(utf8, cur, &au32);
+                PUSH32(utf8, cur, &au32, needs_swap);
            }
            break;
        case 'l' | TYPE_IS_SHRIEKING:
            }
            break;
        case 'l' | TYPE_IS_SHRIEKING:
@@ -3131,8 +2968,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                long along;
                fromstr = NEXTFROM;
                along = SvIV(fromstr);
                long along;
                fromstr = NEXTFROM;
                along = SvIV(fromstr);
-               DO_BO_PACK(along, l);
-               PUSH_VAR(utf8, cur, along);
+                PUSH_VAR(utf8, cur, along, needs_swap);
            }
            break;
 #else
            }
            break;
 #else
@@ -3143,18 +2979,16 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                I32 ai32;
                fromstr = NEXTFROM;
                ai32 = SvIV(fromstr);
                I32 ai32;
                fromstr = NEXTFROM;
                ai32 = SvIV(fromstr);
-               DO_BO_PACK(ai32, 32);
-               PUSH32(utf8, cur, &ai32);
+                PUSH32(utf8, cur, &ai32, needs_swap);
            }
            break;
            }
            break;
-#ifdef HAS_QUAD
+#if IVSIZE >= 8
        case 'Q':
            while (len-- > 0) {
                Uquad_t auquad;
                fromstr = NEXTFROM;
                auquad = (Uquad_t) SvUV(fromstr);
        case 'Q':
            while (len-- > 0) {
                Uquad_t auquad;
                fromstr = NEXTFROM;
                auquad = (Uquad_t) SvUV(fromstr);
-               DO_BO_PACK(auquad, 64);
-               PUSH_VAR(utf8, cur, auquad);
+                PUSH_VAR(utf8, cur, auquad, needs_swap);
            }
            break;
        case 'q':
            }
            break;
        case 'q':
@@ -3162,11 +2996,10 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                Quad_t aquad;
                fromstr = NEXTFROM;
                aquad = (Quad_t)SvIV(fromstr);
                Quad_t aquad;
                fromstr = NEXTFROM;
                aquad = (Quad_t)SvIV(fromstr);
-               DO_BO_PACK(aquad, 64);
-               PUSH_VAR(utf8, cur, aquad);
+                PUSH_VAR(utf8, cur, aquad, needs_swap);
            }
            break;
            }
            break;
-#endif /* HAS_QUAD */
+#endif
        case 'P':
            len = 1;            /* assume SV is correct length */
            GROWING(utf8, cat, start, cur, sizeof(char *));
        case 'P':
            len = 1;            /* assume SV is correct length */
            GROWING(utf8, cat, start, cur, sizeof(char *));
@@ -3194,8 +3027,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                    else
                        aptr = SvPV_force_flags_nolen(fromstr, 0);
                }
                    else
                        aptr = SvPV_force_flags_nolen(fromstr, 0);
                }
-               DO_BO_PACK_PC(aptr);
-               PUSH_VAR(utf8, cur, aptr);
+                PUSH_VAR(utf8, cur, aptr, needs_swap);
            }
            break;
        case 'u': {
            }
            break;
        case 'u': {
@@ -3241,7 +3073,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
                    end = doencodes(hunk, aptr, todo);
                    aptr += todo;
                }
                    end = doencodes(hunk, aptr, todo);
                    aptr += todo;
                }
-               PUSH_BYTES(utf8, cur, hunk, end-hunk);
+               PUSH_BYTES(utf8, cur, hunk, end-hunk, 0);
                fromlen -= todo;
            }
            break;
                fromlen -= todo;
            }
            break;