[Top][All Lists]
[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_
- [Gnash-commit] gnash libbase/tu_swap.h libamf/amf.cpp server/p...,
Martin Guy <=