From 2085a482c76d88bfbb7ed8b5c598ff9f7ed8788f Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 17 Nov 2016 16:57:58 +0100
Subject: [PATCH] admesh: Fixed a problem in loading an STL when compiled with
 Visual Studio 2013. Added multiple compile time checks for data sizes and
 alignment. The library STL import is not big endian safe, so added a test for
 endianity, modified STL export to a faster little endian only.

---
 xs/src/admesh/stl.h     | 17 +++++++++++
 xs/src/admesh/stl_io.c  | 65 ++---------------------------------------
 xs/src/admesh/stlinit.c | 14 +++------
 3 files changed, 24 insertions(+), 72 deletions(-)

diff --git a/xs/src/admesh/stl.h b/xs/src/admesh/stl.h
index e6e69c7f6..d97760eb0 100644
--- a/xs/src/admesh/stl.h
+++ b/xs/src/admesh/stl.h
@@ -25,6 +25,12 @@
 
 #include <stdio.h>
 #include <stdint.h>
+#include <stddef.h>
+#include <boost/predef/detail/endian_compat.h>
+
+#ifndef BOOST_LITTLE_ENDIAN
+#error "admesh works correctly on little endian machines only!"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -51,12 +57,16 @@ typedef struct {
   float z;
 } stl_vertex;
 
+static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
+
 typedef struct {
   float x;
   float y;
   float z;
 } stl_normal;
 
+static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
+
 typedef char stl_extra[2];
 
 typedef struct {
@@ -66,6 +76,11 @@ typedef struct {
 } stl_facet;
 #define SIZEOF_STL_FACET       50
 
+static_assert(offsetof(stl_facet, normal) == 0, "stl_facet.normal has correct offset");
+static_assert(offsetof(stl_facet, vertex) == 12, "stl_facet.vertex has correct offset");
+static_assert(offsetof(stl_facet, extra ) == 48, "stl_facet.extra has correct offset");
+static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrect");
+
 typedef enum {binary, ascii, inmemory} stl_type;
 
 typedef struct {
@@ -85,6 +100,8 @@ typedef struct stl_hash_edge {
   struct stl_hash_edge  *next;
 } stl_hash_edge;
 
+static_assert(offsetof(stl_hash_edge, facet_number) == SIZEOF_EDGE_SORT, "size of stl_hash_edge.key incorrect");
+
 typedef struct {
   // Index of a neighbor facet.
   int   neighbor[3];
diff --git a/xs/src/admesh/stl_io.c b/xs/src/admesh/stl_io.c
index e015cee99..7d8e4eab8 100644
--- a/xs/src/admesh/stl_io.c
+++ b/xs/src/admesh/stl_io.c
@@ -203,63 +203,6 @@ stl_print_neighbors(stl_file *stl, char *file) {
   fclose(fp);
 }
 
-void
-stl_put_little_int(FILE *fp, int value_in) {
-  int new_value;
-  union {
-    int  int_value;
-    char char_value[4];
-  } value;
-
-  value.int_value = value_in;
-
-  new_value  = value.char_value[0] & 0xFF;
-  new_value |= (value.char_value[1] & 0xFF) << 0x08;
-  new_value |= (value.char_value[2] & 0xFF) << 0x10;
-  new_value |= (value.char_value[3] & 0xFF) << 0x18;
-  fwrite(&new_value, sizeof(int), 1, fp);
-}
-
-void
-stl_put_little_float(FILE *fp, float value_in) {
-  int new_value;
-  union {
-    float float_value;
-    char  char_value[4];
-  } value;
-
-  value.float_value = value_in;
-
-  new_value  = value.char_value[0] & 0xFF;
-  new_value |= (value.char_value[1] & 0xFF) << 0x08;
-  new_value |= (value.char_value[2] & 0xFF) << 0x10;
-  new_value |= (value.char_value[3] & 0xFF) << 0x18;
-  fwrite(&new_value, sizeof(int), 1, fp);
-}
-
-void
-stl_write_binary_block(stl_file *stl, FILE *fp)
-{
-  int i;
-  for(i = 0; i < stl->stats.number_of_facets; i++)
-    {
-      stl_put_little_float(fp, stl->facet_start[i].normal.x);
-      stl_put_little_float(fp, stl->facet_start[i].normal.y);
-      stl_put_little_float(fp, stl->facet_start[i].normal.z);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[0].x);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[0].y);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[0].z);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[1].x);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[1].y);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[1].z);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[2].x);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[2].y);
-      stl_put_little_float(fp, stl->facet_start[i].vertex[2].z);
-      fputc(stl->facet_start[i].extra[0], fp);
-      fputc(stl->facet_start[i].extra[1], fp);
-    }
-}
-
 void
 stl_write_binary(stl_file *stl, const char *file, const char *label) {
   FILE      *fp;
@@ -285,11 +228,9 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) {
   for(i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp);
 
   fseek(fp, LABEL_SIZE, SEEK_SET);
-
-  stl_put_little_int(fp, stl->stats.number_of_facets);
-
-  stl_write_binary_block(stl, fp);
-
+  fwrite(&stl->stats.number_of_facets, 4, 1, fp);
+  for(i = 0; i < stl->stats.number_of_facets; i++)
+    fwrite(stl->facet_start + i, SIZEOF_STL_FACET, 1, fp);
   fclose(fp);
 }
 
diff --git a/xs/src/admesh/stlinit.c b/xs/src/admesh/stlinit.c
index 4e48ef48e..de1760bd5 100644
--- a/xs/src/admesh/stlinit.c
+++ b/xs/src/admesh/stlinit.c
@@ -27,10 +27,8 @@
 
 #include "stl.h"
 
-#if !defined(SEEK_SET)
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
+#ifndef SEEK_SET
+#error "SEEK_SET not defined"
 #endif
 
 void
@@ -277,10 +275,7 @@ stl_read(stl_file *stl, int first_facet, int first) {
       /* Read a single facet from a binary .STL file */
     {
       /* we assume little-endian architecture! */
-      if (fread(&facet.normal, sizeof(stl_normal), 1, stl->fp) \
-          + fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp) \
-          + fread(&facet.extra, sizeof(char), 2, stl->fp) != 6) {
-        perror("Cannot read facet");
+      if (fread(&facet, 1, SIZEOF_STL_FACET, stl->fp) != SIZEOF_STL_FACET) {
         stl->error = 1;
         return;
       }
@@ -343,8 +338,7 @@ stl_read(stl_file *stl, int first_facet, int first) {
     }
 #endif
     /* Write the facet into memory. */
-    stl->facet_start[i] = facet;
-
+    memcpy(stl->facet_start+i, &facet, SIZEOF_STL_FACET);
     stl_facet_stats(stl, facet, first);
     first = 0;
   }