gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash libbase/tu_swap.h libamf/amf.cpp server/p...


From: Martin Guy
Subject: [Gnash-commit] gnash libbase/tu_swap.h libamf/amf.cpp server/p...
Date: Wed, 25 Apr 2007 11:29:12 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Martin Guy <martinwguy> 07/04/25 11:29:12

Modified files:
        libbase        : tu_swap.h 
        libamf         : amf.cpp 
        server/parser  : action_buffer.cpp 
        server/swf     : tag_loaders.cpp 

Log message:
        Replace compile-time endianness checking with runtime checks.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/tu_swap.h?cvsroot=gnash&r1=1.7&r2=1.8
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/amf.cpp?cvsroot=gnash&r1=1.31&r2=1.32
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/action_buffer.cpp?cvsroot=gnash&r1=1.18&r2=1.19
http://cvs.savannah.gnu.org/viewcvs/gnash/server/swf/tag_loaders.cpp?cvsroot=gnash&r1=1.91&r2=1.92

Patches:
Index: libbase/tu_swap.h
===================================================================
RCS file: /sources/gnash/gnash/libbase/tu_swap.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- libbase/tu_swap.h   11 Apr 2007 17:54:21 -0000      1.7
+++ libbase/tu_swap.h   25 Apr 2007 11:29:12 -0000      1.8
@@ -3,16 +3,13 @@
 // This source code has been donated to the Public Domain.  Do
 // whatever you want with it.
 
-// Basic endian-swapping stuff.
-
+// Basic swapping stuff and endian-dependent code.
 
 #ifndef TU_SWAP_H
 #define TU_SWAP_H
 
-
 #include "tu_config.h"
-#include "tu_types.h"
-
+//#include "tu_types.h"
 
 template<class T>
 void   swap(T* a, T* b)
@@ -23,125 +20,6 @@
        *b = temp;
 }
 
-
-//
-// endian conversions
-//
-
-#ifdef swap16
-#undef swap16
-#endif
-
-inline uint16_t swap16(uint16_t u)
-{ 
-       return ((u & 0x00FF) << 8) | 
-               ((u & 0xFF00) >> 8);
-}
-
-#ifdef swap32
-#undef swap32
-#endif
-inline uint32_t swap32(uint32_t u)
-{ 
-       return ((u & 0x000000FF) << 24) | 
-               ((u & 0x0000FF00) << 8)  |
-               ((u & 0x00FF0000) >> 8)  |
-               ((u & 0xFF000000) >> 24);
-}
-
-#ifdef swap64
-#undef swap64
-#endif
-inline uint64_t swap64(uint64_t u)
-{
-#ifdef __GNUC__
-       return ((u & 0x00000000000000FFLL) << 56) |
-               ((u & 0x000000000000FF00LL) << 40)  |
-               ((u & 0x0000000000FF0000LL) << 24)  |
-               ((u & 0x00000000FF000000LL) << 8) |
-               ((u & 0x000000FF00000000LL) >> 8) |
-               ((u & 0x0000FF0000000000LL) >> 24) |
-               ((u & 0x00FF000000000000LL) >> 40) |
-               ((u & 0xFF00000000000000LL) >> 56);
-#else
-       return ((u & 0x00000000000000FF) << 56) | 
-               ((u & 0x000000000000FF00) << 40)  |
-               ((u & 0x0000000000FF0000) << 24)  |
-               ((u & 0x00000000FF000000) << 8) |
-               ((u & 0x000000FF00000000) >> 8) |
-               ((u & 0x0000FF0000000000) >> 24) |
-               ((u & 0x00FF000000000000) >> 40) |
-               ((u & 0xFF00000000000000) >> 56);
-#endif
-}
-
-
-inline uint64_t        swap_le64(uint64_t le_64)
-// Given a 64-bit little-endian piece of data, return it as a 64-bit
-// integer in native endian-ness.  I.e., do a swap if we're on a
-// big-endian machine.
-{
-#ifdef _TU_LITTLE_ENDIAN_
-       return le_64;
-#else  // not _TU_LITTLE_ENDIAN_
-       return swap64(le_64);   // convert to big-endian.
-#endif // not _TU_LITTLE_ENDIAN_
-}
-
-
-inline uint32_t        swap_le32(uint32_t le_32)
-// Given a 32-bit little-endian piece of data, return it as a 32-bit
-// integer in native endian-ness.  I.e. on a little-endian machine,
-// this just returns the input; on a big-endian machine, this swaps
-// the bytes around first.
-{
-#ifdef _TU_LITTLE_ENDIAN_
-       return le_32;
-#else  // not _TU_LITTLE_ENDIAN_
-       return swap32(le_32);   // convert to big-endian.
-#endif // not _TU_LITTLE_ENDIAN_
-}
-
-
-inline uint16_t        swap_le16(uint16_t le_16)
-// Given a 16-bit little-endian piece of data, return it as a 16-bit
-// integer in native endianness.
-{
-#ifdef _TU_LITTLE_ENDIAN_
-       return le_16;
-#else  // not _TU_LITTLE_ENDIAN_
-       return swap16(le_16);   // convert to big-endian.
-#endif // not _TU_LITTLE_ENDIAN_
-}
-
-
-inline uint32_t        swap_be32(uint32_t le_32)
-// Given a 32-bit big-endian piece of data, return it as a 32-bit
-// integer in native endian-ness.  I.e. on a little-endian machine,
-// this swaps the bytes around; on a big-endian machine, it just
-// returns the input.
-{
-#ifdef _TU_LITTLE_ENDIAN_
-       return swap32(le_32);   // convert to little-endian.
-#else  // not _TU_LITTLE_ENDIAN_
-       return le_32;
-#endif // not _TU_LITTLE_ENDIAN_
-}
-
-
-inline uint16_t        swap_be16(uint16_t le_16)
-// Given a 16-bit big-endian piece of data, return it as a 16-bit
-// integer in native endianness.
-{
-#ifdef _TU_LITTLE_ENDIAN_
-       return swap16(le_16);   // convert to little-endian.
-#else  // not _TU_LITTLE_ENDIAN_
-       return le_16;
-#endif // not _TU_LITTLE_ENDIAN_
-}
-
-
-
 #endif // TU_SWAP_H
 
 // Local Variables:

Index: libamf/amf.cpp
===================================================================
RCS file: /sources/gnash/gnash/libamf/amf.cpp,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -b -r1.31 -r1.32
--- libamf/amf.cpp      18 Apr 2007 17:27:02 -0000      1.31
+++ libamf/amf.cpp      25 Apr 2007 11:29:12 -0000      1.32
@@ -16,7 +16,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-/* $Id: amf.cpp,v 1.31 2007/04/18 17:27:02 martinwguy Exp $ */
+/* $Id: amf.cpp,v 1.32 2007/04/25 11:29:12 martinwguy Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -114,40 +114,59 @@
 
 /// \brief Swap bytes from big to little endian.
 ///
-/// All Numberic values for AMF files are 64bit big endian, so we have
+/// All Numeric values for AMF files are big endian, so we have
 /// to swap the bytes to be little endian for most machines. Don't do
-/// anything if we happend to be on a big-endian machine.
+/// anything if we happen to be on a big-endian machine.
+///
+/// Returns its first parameter, pointing to the (maybe-byte-swapped) data.
 void *
 AMF::swapBytes(void *word, int size)
 {
-#if    __BYTE_ORDER == __LITTLE_ENDIAN
-    unsigned char       c;
-    unsigned short      s;
-    unsigned long       l;
-    char *x = static_cast<char *>(word);
+    union {
+       uint16_t s;
+       struct {
+           uint8_t c0;
+           uint8_t c1;
+       } c;
+    } u;
+          
+    u.s = 1;
+    if (u.c.c0 == 0) {
+       // Big-endian machine: do nothing
+        return word;
+    }
+
+    // Little-endian machine: byte-swap the word
+
+    // A conveniently-typed pointer to the source data
+    unsigned char *x = static_cast<unsigned char *>(word);
 
     switch (size) {
-      case 2: // swap two bytes
-          c = *x;
-          *x = *(x+1);
-          *(x+1) = c;
-          break;
-      case 4: // swap two shorts (2-byte words)
-          s = *(unsigned short *)x;
-          *(unsigned short *)x = *((unsigned short *)x + 1);
-          *((unsigned short *)x + 1) = s;
-          swapBytes((char *)x, 2);
-          swapBytes((char *)((unsigned short *)x+1), 2);
-          break;
-      case 8: // swap two longs (4-bytes words)
-          l = *(unsigned long *)x;
-          *(unsigned long *)x = *((unsigned long *)x + 1);
-          *((unsigned long *)x + 1) = l;
-          swapBytes((char *)x, 4);
-          swapBytes((char *)((unsigned long *)x+1), 4);
+    case 2: // 16-bit integer
+      {
+       unsigned char c;
+       c=x[0]; x[0]=x[1]; x[1]=c;
           break;
     }
-#endif
+    case 4: // 32-bit integer
+      {
+       unsigned char c;
+       c=x[0]; x[0]=x[3]; x[3]=c;
+       c=x[1]; x[1]=x[2]; x[2]=c;
+       break;
+      }
+    case 8: // 64-bit integer
+      {
+       unsigned char c;
+       c=x[0]; x[0]=x[7]; x[7]=c;
+       c=x[1]; x[1]=x[6]; x[6]=c;
+       c=x[2]; x[2]=x[5]; x[5]=c;
+       c=x[3]; x[3]=x[4]; x[4]=c;
+       break;
+      }
+    default:
+       assert(0);
+    }
 
     return word;
 }
@@ -166,6 +185,8 @@
     return true;
 }
 
+// @@ I don't believe this works, since it only advances x over the
+// @@ object's metafields (length etc), but not over its contents. -martin
 char *
 AMF::readElement(void *in)
 {
@@ -184,6 +205,7 @@
     x++;                        // skip the type byte
     switch (type) {
       case NUMBER:
+         // AMF numbers are 64-bit big-endian integers.
           num = *(amfnum_t *)swapBytes(x+1, 8);
           log_msg("Number is " AMFNUM_F, num);
           break;
@@ -255,6 +277,9 @@
       case TYPED_OBJECT:
           log_msg("TypedObject is unimplemented\n");
           break;
+      default:
+          log_msg("Warning: Unknown AMF element type %d\n", type);
+          break;
     }
     
     return x;

Index: server/parser/action_buffer.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/parser/action_buffer.cpp,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -b -r1.18 -r1.19
--- server/parser/action_buffer.cpp     20 Apr 2007 12:13:34 -0000      1.18
+++ server/parser/action_buffer.cpp     25 Apr 2007 11:29:12 -0000      1.19
@@ -17,7 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-/* $Id: action_buffer.cpp,v 1.18 2007/04/20 12:13:34 strk Exp $ */
+/* $Id: action_buffer.cpp,v 1.19 2007/04/25 11:29:12 martinwguy Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -43,6 +43,10 @@
 
 namespace gnash {
 
+// Forward declarations
+static float convert_float_little(const void *p);
+static double convert_double_wacky(const void *p);
+
 action_buffer::action_buffer()
     :
     m_decl_dict_processed_at(-1)
@@ -251,17 +255,9 @@
                    dbglogfile << "\t\"" << str.c_str() << "\"" << endl;
                } else if (type == 1) {
                    // float (little-endian)
-                   union {
-                       float   f;
-                       uint32_t        i;
-                   } u;
-                   compiler_assert(sizeof(u) == sizeof(u.i));
-                   
-                   memcpy(&u.i, instruction_data + 3 + i, 4);
-                   u.i = swap_le32(u.i);
+                   float f = convert_float_little(instruction_data + 3 + i);
                    i += 4;
-                   
-                   dbglogfile << "(float) " << u.f << endl;
+                   dbglogfile << "(float) " << f << endl;
                } else if (type == 2) {
                    dbglogfile << "NULL" << endl;
                } else if (type == 3) {
@@ -276,24 +272,10 @@
                    i++;
                    dbglogfile << "bool(" << bool_val << ")" << endl;
                } else if (type == 6) {
-                   // double
-                   // wacky format: 45670123
-                   union {
-                       double  d;
-                       uint64_t        i;
-                       struct {
-                           uint32_t    lo;
-                           uint32_t    hi;
-                       } sub;
-                   } u;
-                   compiler_assert(sizeof(u) == sizeof(u.i));
-                   
-                   memcpy(&u.sub.hi, instruction_data + 3 + i, 4);
-                   memcpy(&u.sub.lo, instruction_data + 3 + i + 4, 4);
-                   u.i = swap_le64(u.i);
+                   // double in wacky format: 45670123
+                   double d = convert_double_wacky(instruction_data + 3 + i);
                    i += 8;
-                   
-                   dbglogfile << "(double) " << u.d << endl;
+                   dbglogfile << "(double) " << d << endl;
                } else if (type == 7) {
                    // int32_t
                    int32_t     val = instruction_data[3 + i]
@@ -414,44 +396,150 @@
        disasm(instruction_data);
 }
 
-
-float
-action_buffer::read_float_little(size_t pc) const
+// Endian conversion routines.
+//
+// Flash format stores integers as little-endian,
+// floats as little-endian IEEE754,
+// and doubles as little-endian IEEE754 with the two 32-bit words swapped over.
+//
+// We detect endianness at runtime.
+// It looks hairy but the cost is small (one assignment, one switch),
+// and it is less of a maintenance/portability nightmare.
+// It also allows us to detect three existing variants instead of two and
+// to reject incompatible (non-IEEE754) floating point formats (VAX etc).
+// For these we would need to interpret the IEEE bitvalues explicitly.
+
+// Read a little-endian 32-bit float from m_buffer[pc]
+// and return it as a host-endian float.
+static float
+convert_float_little(const void *p)
 {
+       // Hairy union for endian detection and munging
        union {
                float   f;
                uint32_t        i;
+               struct {        // for endian detection
+                       uint16_t s0;
+                       uint16_t s1;
+               } s;
+               struct {        // for byte-swapping
+                       uint8_t c0;
+                       uint8_t c1;
+                       uint8_t c2;
+                       uint8_t c3;
+               } c;
        } u;
-       compiler_assert(sizeof(u) == sizeof(u.i));
-       memcpy(&u.i, &m_buffer[pc], 4);
-       u.i = swap_le32(u.i);
+
+       u.f = 1.0;
+       switch (u.s.s0) {
+       case 0x0000:    // little-endian host
+               memcpy(&u.i, p, 4);
+               break;
+       case 0x3f80:    // big-endian host
+           {
+               const uint8_t *cp = (const uint8_t *) p;
+               u.c.c0 = cp[3];
+               u.c.c1 = cp[2];
+               u.c.c2 = cp[1];
+               u.c.c3 = cp[0];
+           }
+           break;
+       default:
+           log_error(_("Native floating point format not recognised"));
+           assert(0);
+       }
+       
        return u.f;
 }
 
-double
-action_buffer::read_double_wacky(size_t pc) const
+// Read a 64-bit double from memory, stored in word-swapped little-endian
+// format and return it as a host-endian double.
+// "Wacky format" is 45670123.
+static double
+convert_double_wacky(const void *p)
 {
-       // double
-       // wacky format: 45670123
+       const uint8_t *cp = (const uint8_t *)p; // Handy uchar version
        union {
                double  d;
                uint64_t        i;
                struct {
-                       uint32_t        lo;
-                       uint32_t        hi;
-               } sub;
+                       uint32_t l0;
+                       uint32_t l1;
+               } l;
+               struct {
+                       uint16_t s0;
+                       uint16_t s1;
+                       uint16_t s2;
+                       uint16_t s3;
+               } s;
+               struct {
+                       uint8_t c0;
+                       uint8_t c1;
+                       uint8_t c2;
+                       uint8_t c3;
+                       uint8_t c4;
+                       uint8_t c5;
+                       uint8_t c6;
+                       uint8_t c7;
+               } c;
        } u;
 
        compiler_assert(sizeof(u) == sizeof(u.i));
 
-       // this works, but is pretty dirty
-       memcpy(&u.sub.hi, &m_buffer[pc], 4);
-       memcpy(&u.sub.lo, &m_buffer[pc + 4], 4);
-       u.i = swap_le64(u.i);
+       // Detect endianness of doubles by storing a value that is
+       // exactly representable and that has different values in the
+       // four 16-bit words.
+       // 0x11223344 is represented as 0x41b1 2233 4400 0000 (bigendian)
+       u.d = (double) 0x11223344;
+       switch (u.s.s0) {
+       case 0x0000:    // pure little-endian host: swap words only.
+               memcpy(&u.l.l1, cp, 4);
+               memcpy(&u.l.l0, cp + 4, 4);
+               break;
+       case 0x41b1:    // pure big-endian host: swap contents of 32-bit words
+               u.c.c0 = cp[3];
+               u.c.c1 = cp[2];
+               u.c.c2 = cp[1];
+               u.c.c3 = cp[0];
+               u.c.c4 = cp[7];
+               u.c.c5 = cp[6];
+               u.c.c6 = cp[5];
+               u.c.c7 = cp[4];
+               break;
+       case 0x2233:    // word-swapped little-endian host (PDP / ARM FPA)
+                       // is the same as wacky format.
+               memcpy(&u.i, cp, 8);
+               break;
+       case 0x4400:    // word-swapped big-endian host: does this exist?
+               u.c.c0 = cp[7];
+               u.c.c1 = cp[6];
+               u.c.c2 = cp[5];
+               u.c.c3 = cp[4];
+               u.c.c4 = cp[3];
+               u.c.c5 = cp[2];
+               u.c.c6 = cp[1];
+               u.c.c7 = cp[0];
+               break;
+       default:
+               log_error(_("Native double floating point format not 
recognised"));
+               assert(0);
+       }
 
        return u.d;
 }
 
+float
+action_buffer::read_float_little(size_t pc) const
+{
+       return(convert_float_little(&m_buffer[pc]));
+}
+
+double
+action_buffer::read_double_wacky(size_t pc) const
+{
+       return(convert_double_wacky(&m_buffer[pc]));
+}
+
 }
 
 // Local Variables:

Index: server/swf/tag_loaders.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/swf/tag_loaders.cpp,v
retrieving revision 1.91
retrieving revision 1.92
diff -u -b -r1.91 -r1.92
--- server/swf/tag_loaders.cpp  18 Apr 2007 21:05:15 -0000      1.91
+++ server/swf/tag_loaders.cpp  25 Apr 2007 11:29:12 -0000      1.92
@@ -17,7 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-/* $Id: tag_loaders.cpp,v 1.91 2007/04/18 21:05:15 martinwguy Exp $ */
+/* $Id: tag_loaders.cpp,v 1.92 2007/04/25 11:29:12 martinwguy Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -1176,6 +1176,9 @@
 // Sound
 //
 
+// @@ There are two sets of code to decode/expand/byteswap audio here.
+// @@ There should be one (search for ADPCM).
+
 // Load a DefineSound tag.
 void
 define_sound_loader(stream* in, tag_type tag, movie_definition* m)
@@ -1235,19 +1238,37 @@
                    data[i] = in->read_u8();
                }
 
+               // Samples are always little-endian.
                // Swap bytes on behalf of the host, to make it easier for the 
handler.
                // @@ I'm assuming this is a good idea?  Most sound handlers 
will prefer native endianness?
                if (format == sound_handler::FORMAT_UNCOMPRESSED
                    && sample_16bit)
                {
-#ifndef _TU_LITTLE_ENDIAN_
+                   // Runtime detection of host endianness costs almost
+                   // nothing and is less of a continual maintenance headache
+                   // than attempting compile-time detection.
+                   union u {
+                       uint16_t s;
+                       struct {
+                           uint8_t c0;
+                           uint8_t c1;
+                       } c;
+                   } u;
+                   u.s = 0x0001;
+                   switch (u.c.c0) {
+                   case 0x01:  // Little-endian host: sample is already native.
+                       break;
+                   case 0x00:  // Big-endian host
                    // Swap sample bytes to get big-endian format.
                    for (int i = 0; i < data_bytes - 1; i += 2)
                    {
                        swap(&data[i], &data[i+1]);
                    }
-#endif // not _TU_LITTLE_ENDIAN_
-
+                       break;
+                   default:    // Impossible
+                       log_error(_("Host endianness not detected in 
define-sound_loader"));
+                       assert(0);
+                   }
                    format = sound_handler::FORMAT_NATIVE16;
                }
            }
@@ -1435,6 +1456,10 @@
 
        // Swap bytes on behalf of the host, to make it easier for the handler.
        // @@ I'm assuming this is a good idea?  Most sound handlers will 
prefer native endianness?
+       // I dunno why this is commented-out, but if you want to re-enable it,
+       // recode it with the same runtime endian order detection as above.
+       // Or, better, unify the two routines as there is a lot of duplicated
+       // code here.
        /*if (format == sound_handler::FORMAT_UNCOMPRESSED && sample_16bit)
        {
 #ifndef _TU_LITTLE_ENDIAN_




reply via email to

[Prev in Thread] Current Thread [Next in Thread]