From b9592961fa7ad89bdb9a2b044934df2082a75400 Mon Sep 17 00:00:00 2001 From: Chow Loong Jin Date: Mon, 2 Oct 2017 05:01:51 +0800 Subject: [PATCH] Fix importing of binary STLs in big-endian architectures (#4143) Fix from https://github.com/admesh/admesh/pull/26 --- xs/src/admesh/portable_endian.h | 123 ++++++++++++++++++++++++++++++++ xs/src/admesh/stlinit.c | 37 ++++++++-- 2 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 xs/src/admesh/portable_endian.h diff --git a/xs/src/admesh/portable_endian.h b/xs/src/admesh/portable_endian.h new file mode 100644 index 000000000..f980de82a --- /dev/null +++ b/xs/src/admesh/portable_endian.h @@ -0,0 +1,123 @@ +/* portable_endian.h + * from https://gist.github.com/panzi/6856583 + * "License": Public Domain + * I, Mathias Panzenböck, place this file hereby into the public domain. Use it + * at your own risk for whatever you like. In case there are jurisdictions + * that don't support putting things in the public domain you can also consider + * it to be "dual licensed" under the BSD, MIT and Apache licenses, if you want + * to. This code is trivial anyway. Consider it an example on how to get the + * endian conversion functions on different platforms. + */ + +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + +# include + +#elif defined(__APPLE__) + +# include + +# define htobe16(x) OSSwapHostToBigInt16(x) +# define htole16(x) OSSwapHostToLittleInt16(x) +# define be16toh(x) OSSwapBigToHostInt16(x) +# define le16toh(x) OSSwapLittleToHostInt16(x) + +# define htobe32(x) OSSwapHostToBigInt32(x) +# define htole32(x) OSSwapHostToLittleInt32(x) +# define be32toh(x) OSSwapBigToHostInt32(x) +# define le32toh(x) OSSwapLittleToHostInt32(x) + +# define htobe64(x) OSSwapHostToBigInt64(x) +# define htole64(x) OSSwapHostToLittleInt64(x) +# define be64toh(x) OSSwapBigToHostInt64(x) +# define le64toh(x) OSSwapLittleToHostInt64(x) + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +# include + +# define be16toh(x) betoh16(x) +# define le16toh(x) letoh16(x) + +# define be32toh(x) betoh32(x) +# define le32toh(x) letoh32(x) + +# define be64toh(x) betoh64(x) +# define le64toh(x) letoh64(x) + +#elif defined(__WINDOWS__) + +/* # include */ +# include + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16(x) htons(x) +# define htole16(x) (x) +# define be16toh(x) ntohs(x) +# define le16toh(x) (x) + +# define htobe32(x) htonl(x) +# define htole32(x) (x) +# define be32toh(x) ntohl(x) +# define le32toh(x) (x) + +# define htobe64(x) htonll(x) +# define htole64(x) (x) +# define be64toh(x) ntohll(x) +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#else + +# error platform not supported + +#endif + +#endif diff --git a/xs/src/admesh/stlinit.c b/xs/src/admesh/stlinit.c index 7ec56e795..c15ee073e 100644 --- a/xs/src/admesh/stlinit.c +++ b/xs/src/admesh/stlinit.c @@ -21,11 +21,13 @@ */ #include +#include #include #include #include #include +#include "portable_endian.h" #include "stl.h" #ifndef SEEK_SET @@ -68,7 +70,7 @@ stl_initialize(stl_file *stl) { void stl_count_facets(stl_file *stl, const ADMESH_CHAR *file) { long file_size; - int header_num_facets; + uint32_t header_num_facets; int num_facets; int i; size_t s; @@ -123,7 +125,7 @@ stl_count_facets(stl_file *stl, const ADMESH_CHAR *file) { } /* Read the int following the header. This should contain # of facets */ - if((!fread(&header_num_facets, sizeof(int), 1, stl->fp)) || (num_facets != header_num_facets)) { + if((!fread(&header_num_facets, sizeof(uint32_t), 1, stl->fp)) || (uint32_t)num_facets != le32toh(header_num_facets)) { fprintf(stderr, "Warning: File size doesn't match number of facets in the header\n"); @@ -260,7 +262,24 @@ stl_reallocate(stl_file *stl) { void stl_read(stl_file *stl, int first_facet, int first) { stl_facet facet; - int i; + int i, j; + const int facet_float_length = 12; + float *facet_floats[12]; + char facet_buffer[12 * sizeof(float)]; + uint32_t endianswap_buffer; /* for byteswapping operations */ + + facet_floats[0] = &facet.normal.x; + facet_floats[1] = &facet.normal.y; + facet_floats[2] = &facet.normal.z; + facet_floats[3] = &facet.vertex[0].x; + facet_floats[4] = &facet.vertex[0].y; + facet_floats[5] = &facet.vertex[0].z; + facet_floats[6] = &facet.vertex[1].x; + facet_floats[7] = &facet.vertex[1].y; + facet_floats[8] = &facet.vertex[1].z; + facet_floats[9] = &facet.vertex[2].x; + facet_floats[10] = &facet.vertex[2].y; + facet_floats[11] = &facet.vertex[2].z; if (stl->error) return; @@ -274,11 +293,19 @@ stl_read(stl_file *stl, int first_facet, int first) { if(stl->stats.type == binary) /* Read a single facet from a binary .STL file */ { - /* we assume little-endian architecture! */ - if (fread(&facet, 1, SIZEOF_STL_FACET, stl->fp) != SIZEOF_STL_FACET) { + if(fread(facet_buffer, sizeof(facet_buffer), 1, stl->fp) + + fread(&facet.extra, sizeof(char), 2, stl->fp) != 3) { + perror("Cannot read facet"); stl->error = 1; return; } + + for(j = 0; j < facet_float_length; j++) { + /* convert LE float to host byte order */ + memcpy(&endianswap_buffer, facet_buffer + j * sizeof(float), 4); + endianswap_buffer = le32toh(endianswap_buffer); + memcpy(facet_floats[j], &endianswap_buffer, 4); + } } else /* Read a single facet from an ASCII .STL file */ {