-
Notifications
You must be signed in to change notification settings - Fork 2
/
stlparser.c
154 lines (132 loc) · 4.14 KB
/
stlparser.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* To the extent possible under law, Nirav Patel has waived all copyright
* and related or neighboring rights to stlparser.
*/
#include "stlparser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <arpa/inet.h>
char *load_file(const char *filename, int *len)
{
char *buf = NULL;
FILE *fp;
if (!(fp = fopen(filename, "r"))) {
return NULL;
}
fseek(fp, 0, SEEK_END);
*len = ftell(fp);
fseek(fp, 0, SEEK_SET);
buf = (char *)malloc(*len);
*len = fread(buf, 1, *len, fp);
fclose(fp);
return buf;
}
// returns 1 if the data looks like a binary stl
static int stl_binary_check(const char *data, int data_length)
{
// STL ASCII files should start with "solid"
if (data_length >= 5 && (strncasecmp(data, "solid", 5) == 0)) {
return 0;
} else if (data_length >= 84) {
uint32_t facets = *(uint32_t *)(data+80);
// A check suggested from thingiview.js, since ASCII STLs can be
// malformed. Checks if the binary STL's triangle count matches
// the file length plus a little fuzz in case there is end padding
if (abs(data_length - (facets*50 + 84)) < 10) {
return 1;
}
}
return 0;
}
// Opens the file at filename and returns an allocated array of floats
float *load_stl(const char *filename, int *facets)
{
int data_length = 0;
char *data = load_file(filename, &data_length);
if (!data) {
fprintf(stderr, "Could not load file %s\n", filename);
return NULL;
}
return parse_stl(data, data_length, facets);
}
// Parses the data, determines if it is a binary or string, and returns floats
float *parse_stl(const char *data, int data_length, int *facets)
{
if (stl_binary_check(data, data_length)) {
return parse_stl_binary(data, data_length, facets);
} else {
return parse_stl_string((char *)data, data_length, facets);
}
}
// Parses an ASCII STL string and returns the array of floats
float *parse_stl_string(const char *data, int data_length, int *facets)
{
int faces = 0;
float *parsed = NULL;
char *loc = (char *)data;
// Find the number of faces first
if ((loc = strstr(loc, "endfacet"))) {
faces = 1;
while((loc = strstr(loc+sizeof("endfacet"), "endfacet"))) faces++;
} else {
return NULL;
}
parsed = (float *)malloc(faces*12*4);
if (!parsed) return NULL;
*facets = faces;
// Go past the name line
if (!(loc = strchr((char *)data, '\n'))) {
free(parsed);
return NULL;
}
float x, y, z;
float *ptr = parsed;
while (1) {
// Parse each face
if (!(loc = strstr(loc+sizeof("vertex"),"normal"))) break;
if (sscanf(loc, "normal %f %f %f", &x, &y, &z) != 3) break;
*ptr++ = x;
*ptr++ = y;
*ptr++ = z;
if (!(loc = strstr(loc+sizeof("normal"),"vertex"))) break;
if (sscanf(loc, "vertex %f %f %f", &x, &y, &z) != 3) break;
*ptr++ = x;
*ptr++ = y;
*ptr++ = z;
if (!(loc = strstr(loc+sizeof("normal"),"vertex"))) break;
if (sscanf(loc, "vertex %f %f %f", &x, &y, &z) != 3) break;
*ptr++ = x;
*ptr++ = y;
*ptr++ = z;
if (!(loc = strstr(loc+sizeof("normal"),"vertex"))) break;
if (sscanf(loc ,"vertex %f %f %f", &x, &y, &z) != 3) break;
*ptr++ = x;
*ptr++ = y;
*ptr++ = z;
}
return parsed;
}
// Parses an STL binary and returns the array of floats
float *parse_stl_binary(const char *data, int data_length, int *facets)
{
int faces = 0;
float *parsed = NULL;
if (!facets || data_length <= 84) return NULL;
data += 80;
faces = *(uint32_t *)(data);
data += 4;
// Make sure the data provided can actually contain the number of faces
if (faces*50+84 < data_length) return NULL;
parsed = (float *)malloc(faces*12*4);
if (!parsed) return NULL;
*facets = faces;
float *ptr = parsed;
while (faces > 0) {
memcpy(ptr, data, 12*4);
data += 50;
ptr += 12;
faces--;
}
return parsed;
}