stl.c (8964B)
1#include "stl.h" 2 3#include <string.h> 4#include <stdint.h> 5#include <stdbool.h> 6#include <stdio.h> 7 8#define MAX(a, b) ((a) > (b) ? (a) : (b)) 9#define MIN(a, b) ((a) > (b) ? (b) : (a)) 10 11enum { 12 STL_ASCII_SOLID, 13 STL_ASCII_SOLID_NAME, 14 STL_ASCII_ENDSOLID_CHECK, 15 STL_ASCII_FACET_NORMAL, 16 STL_ASCII_FACET_NORMAL_I, 17 STL_ASCII_FACET_NORMAL_J, 18 STL_ASCII_FACET_NORMAL_K, 19 STL_ASCII_OUTER_LOOP, 20 STL_ASCII_VERTEX_1, 21 STL_ASCII_VERTEX_1_X, 22 STL_ASCII_VERTEX_1_Y, 23 STL_ASCII_VERTEX_1_Z, 24 STL_ASCII_VERTEX_2, 25 STL_ASCII_VERTEX_2_X, 26 STL_ASCII_VERTEX_2_Y, 27 STL_ASCII_VERTEX_2_Z, 28 STL_ASCII_VERTEX_3, 29 STL_ASCII_VERTEX_3_X, 30 STL_ASCII_VERTEX_3_Y, 31 STL_ASCII_VERTEX_3_Z, 32 STL_ASCII_ENDLOOP, 33 STL_ASCII_ENDFACET, 34 STL_ASCII_ENDSOLID 35}; 36 37enum { 38 STL_BIN_HEADER, 39 STL_BIN_TRIANGLE 40}; 41 42static const uint8_t ascii_fsm[] = { 43 [STL_ASCII_SOLID] = STL_ASCII_SOLID_NAME, 44 [STL_ASCII_SOLID_NAME] = STL_ASCII_ENDSOLID_CHECK, 45 [STL_ASCII_ENDSOLID_CHECK] = STL_ASCII_FACET_NORMAL, 46 [STL_ASCII_FACET_NORMAL] = STL_ASCII_FACET_NORMAL_I, 47 [STL_ASCII_FACET_NORMAL_I] = STL_ASCII_FACET_NORMAL_K, 48 [STL_ASCII_FACET_NORMAL_K] = STL_ASCII_FACET_NORMAL_J, 49 [STL_ASCII_FACET_NORMAL_J] = STL_ASCII_OUTER_LOOP, 50 [STL_ASCII_OUTER_LOOP] = STL_ASCII_VERTEX_1, 51 [STL_ASCII_VERTEX_1] = STL_ASCII_VERTEX_1_X, 52 [STL_ASCII_VERTEX_1_X] = STL_ASCII_VERTEX_1_Y, 53 [STL_ASCII_VERTEX_1_Y] = STL_ASCII_VERTEX_1_Z, 54 [STL_ASCII_VERTEX_1_Z] = STL_ASCII_VERTEX_2, 55 [STL_ASCII_VERTEX_2] = STL_ASCII_VERTEX_2_X, 56 [STL_ASCII_VERTEX_2_X] = STL_ASCII_VERTEX_2_Y, 57 [STL_ASCII_VERTEX_2_Y] = STL_ASCII_VERTEX_2_Z, 58 [STL_ASCII_VERTEX_2_Z] = STL_ASCII_VERTEX_3, 59 [STL_ASCII_VERTEX_3] = STL_ASCII_VERTEX_3_X, 60 [STL_ASCII_VERTEX_3_X] = STL_ASCII_VERTEX_3_Y, 61 [STL_ASCII_VERTEX_3_Y] = STL_ASCII_VERTEX_3_Z, 62 [STL_ASCII_VERTEX_3_Z] = STL_ASCII_ENDLOOP, 63 [STL_ASCII_ENDLOOP] = STL_ASCII_ENDFACET, 64 [STL_ASCII_ENDFACET] = STL_ASCII_ENDSOLID_CHECK, 65}; 66 67static void 68stl_skip_spn(struct stl *stl, const char *spn) 69{ 70 const char *c; 71 size_t i; 72 73 c = stl->pos; 74 for (i = 0; i < stl->nleft; i++, c++) { 75 if (!strchr(spn, *c)) 76 break; 77 } 78 stl->pos += i; 79 stl->nleft -= i; 80} 81 82static int 83stl_read_n(struct stl *stl, size_t n) 84{ 85 size_t cnt; 86 87 if (stl->buflen >= n) 88 return STL_OK; 89 90 cnt = MIN(n - stl->buflen, stl->nleft); 91 memcpy(stl->buf + stl->buflen, stl->pos, cnt); 92 stl->buflen += cnt; 93 stl->pos += cnt; 94 stl->nleft -= cnt; 95 96 if (stl->buflen < n) 97 return STL_INCOMPLETE; 98 99 return STL_OK; 100} 101 102static int 103stl_read_expect(struct stl *stl, const char *str, size_t n) 104{ 105 size_t i, cnt; 106 int rc; 107 108 rc = stl_read_n(stl, n); 109 if (rc) return rc; 110 111 if (strncmp(stl->buf, str, n)) 112 return STL_INVALID; 113 114 stl->buflen = 0; 115 116 return STL_OK; 117} 118 119static int 120stl_read_until(struct stl *stl, size_t *len, char *any, size_t max) 121{ 122 const char *c; 123 size_t i; 124 125 c = stl->pos; 126 for (i = 0; i < stl->nleft; i++, c++) { 127 if (strchr(any, *c)) { 128 *len = stl->buflen; 129 stl->buflen = 0; 130 return STL_OK; 131 } 132 if (stl->buflen >= max) 133 return STL_INVALID; 134 stl->buf[stl->buflen++] = *c; 135 stl->pos++; 136 stl->nleft--; 137 } 138 139 return STL_INCOMPLETE; 140} 141 142static int 143stl_feed_binary(struct stl *stl, struct stl_result *res, 144 const void *chunk, size_t size) 145{ 146 int rc; 147 148 if (stl->bin.index == stl->bin.count) 149 return STL_DONE; 150 151 while (stl->nleft > 0) { 152 switch (stl->bin.state) { 153 case STL_BIN_HEADER: 154 rc = stl_read_n(stl, 84); 155 if (rc) return rc; 156 stl->bin.count = le32toh(*(uint32_t *)(stl->buf + 80)); 157 stl->bin.state = STL_BIN_TRIANGLE; 158 res->type = STL_RES_HEADER; 159 res->header.str = stl->buf; 160 res->header.len = 80; 161 return STL_OK; 162 case STL_BIN_TRIANGLE: 163 rc = stl_read_n(stl, 50); 164 if (rc) return rc; 165 res->type = STL_RES_TRIANGLE; 166 res->tri.normal.x = le32toh(*(uint32_t *)(stl->buf + 0)); 167 res->tri.normal.y = le32toh(*(uint32_t *)(stl->buf + 4)); 168 res->tri.normal.z = le32toh(*(uint32_t *)(stl->buf + 8)); 169 res->tri.vtx[0].x = le32toh(*(uint32_t *)(stl->buf + 12)); 170 res->tri.vtx[0].y = le32toh(*(uint32_t *)(stl->buf + 16)); 171 res->tri.vtx[0].z = le32toh(*(uint32_t *)(stl->buf + 20)); 172 res->tri.vtx[1].x = le32toh(*(uint32_t *)(stl->buf + 24)); 173 res->tri.vtx[1].y = le32toh(*(uint32_t *)(stl->buf + 28)); 174 res->tri.vtx[1].z = le32toh(*(uint32_t *)(stl->buf + 32)); 175 res->tri.vtx[2].x = le32toh(*(uint32_t *)(stl->buf + 36)); 176 res->tri.vtx[2].y = le32toh(*(uint32_t *)(stl->buf + 40)); 177 res->tri.vtx[2].z = le32toh(*(uint32_t *)(stl->buf + 40)); 178 stl->bin.index++; 179 return STL_OK; 180 default: 181 return STL_INVALID_ARG; 182 } 183 } 184 185 return STL_INCOMPLETE; 186} 187 188static int 189stl_feed_ascii(struct stl *stl, struct stl_result *res, 190 const void *chunk, size_t size) 191{ 192 char *end; 193 float val; 194 size_t len; 195 int rc; 196 197 while (stl->nleft > 0) { 198 switch (stl->ascii.state) { 199 case STL_ASCII_SOLID: 200 rc = stl_read_expect(stl, "solid ", 6); 201 if (rc) return rc; 202 break; 203 case STL_ASCII_SOLID_NAME: 204 rc = stl_read_until(stl, &len, "\n", STL_BUFMAX - 1); 205 if (rc) return rc; 206 stl->buf[len] = '\0'; 207 res->type = STL_RES_SOLID_NAME; 208 res->solid_name.str = stl->buf; 209 res->solid_name.len = len; 210 stl->ascii.state = STL_ASCII_FACET_NORMAL; 211 return STL_OK; 212 case STL_ASCII_FACET_NORMAL: 213 if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); 214 rc = stl_read_expect(stl, "facet normal ", 13); 215 if (rc) return rc; 216 break; 217 case STL_ASCII_OUTER_LOOP: 218 if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); 219 rc = stl_read_expect(stl, "outer loop", 10); 220 if (rc) return rc; 221 break; 222 case STL_ASCII_FACET_NORMAL_I: 223 case STL_ASCII_FACET_NORMAL_J: 224 case STL_ASCII_FACET_NORMAL_K: 225 case STL_ASCII_VERTEX_1_X: 226 case STL_ASCII_VERTEX_1_Y: 227 case STL_ASCII_VERTEX_1_Z: 228 case STL_ASCII_VERTEX_2_X: 229 case STL_ASCII_VERTEX_2_Y: 230 case STL_ASCII_VERTEX_2_Z: 231 case STL_ASCII_VERTEX_3_X: 232 case STL_ASCII_VERTEX_3_Y: 233 case STL_ASCII_VERTEX_3_Z: 234 if (!stl->buflen) stl_skip_spn(stl, " \t"); 235 rc = stl_read_until(stl, &len, " \n", STL_BUFMAX - 1); 236 if (rc) return rc; 237 stl->buf[len] = '\0'; 238 val = strtof(stl->buf, &end); 239 if (end && *end) return STL_INVALID; 240 switch (stl->ascii.state) { 241 case STL_ASCII_FACET_NORMAL_I: 242 stl->tri.normal.x = val; 243 break; 244 case STL_ASCII_FACET_NORMAL_J: 245 stl->tri.normal.y = val; 246 break; 247 case STL_ASCII_FACET_NORMAL_K: 248 stl->tri.normal.z = val; 249 break; 250 case STL_ASCII_VERTEX_1_X: 251 stl->tri.vtx[0].x = val; 252 break; 253 case STL_ASCII_VERTEX_1_Y: 254 stl->tri.vtx[0].y = val; 255 break; 256 case STL_ASCII_VERTEX_1_Z: 257 stl->tri.vtx[0].z = val; 258 break; 259 case STL_ASCII_VERTEX_2_X: 260 stl->tri.vtx[1].x = val; 261 break; 262 case STL_ASCII_VERTEX_2_Y: 263 stl->tri.vtx[1].y = val; 264 break; 265 case STL_ASCII_VERTEX_2_Z: 266 stl->tri.vtx[1].z = val; 267 break; 268 case STL_ASCII_VERTEX_3_X: 269 stl->tri.vtx[2].x = val; 270 break; 271 case STL_ASCII_VERTEX_3_Y: 272 stl->tri.vtx[2].y = val; 273 break; 274 case STL_ASCII_VERTEX_3_Z: 275 stl->tri.vtx[2].z = val; 276 break; 277 } 278 break; 279 case STL_ASCII_VERTEX_1: 280 case STL_ASCII_VERTEX_2: 281 case STL_ASCII_VERTEX_3: 282 if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); 283 rc = stl_read_expect(stl, "vertex", 6); 284 if (rc) return rc; 285 break; 286 case STL_ASCII_ENDLOOP: 287 if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); 288 rc = stl_read_expect(stl, "endloop", 7); 289 if (rc) return rc; 290 break; 291 case STL_ASCII_ENDFACET: 292 if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); 293 rc = stl_read_expect(stl, "endfacet", 8); 294 if (rc) return rc; 295 res->type = STL_RES_TRIANGLE; 296 res->tri = stl->tri; 297 stl->ascii.state = STL_ASCII_ENDSOLID_CHECK; 298 return STL_OK; 299 case STL_ASCII_ENDSOLID_CHECK: 300 if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); 301 rc = stl_read_expect(stl, "endsolid", 8); 302 if (!rc) return STL_DONE; 303 break; 304 defualt: 305 return STL_INVALID_ARG; 306 }; 307 stl->ascii.state = ascii_fsm[stl->ascii.state]; 308 } 309 310 return STL_INCOMPLETE; 311} 312 313void 314stl_init(struct stl *stl, int type) 315{ 316 stl->type = type; 317 stl->buflen = 0; 318 stl->chunk = NULL; 319 stl->pos = NULL; 320 stl->nleft = 0; 321} 322 323int 324stl_feed(struct stl *stl, struct stl_result *res, 325 const void *chunk, size_t size) 326{ 327 size_t cnt; 328 int rc; 329 330 if (stl->chunk != chunk) { 331 if (stl->nleft > 0) 332 return STL_INVALID; 333 stl->chunk = chunk; 334 stl->pos = stl->chunk; 335 stl->nleft = size; 336 } 337 338 if (stl->type == STL_TYPE_DETECT) { 339 rc = stl_read_expect(stl, "solid ", 6); 340 if (rc == STL_INCOMPLETE) 341 return STL_INCOMPLETE; 342 if (rc == STL_OK) { 343 printf("ascii file\n"); 344 stl->type = STL_TYPE_ASCII; 345 stl->ascii.state = STL_ASCII_SOLID_NAME; 346 } else { 347 printf("binary file\n"); 348 stl->type = STL_TYPE_BINARY; 349 stl->bin.state = STL_BIN_HEADER; 350 stl->bin.index = 0; 351 stl->bin.count = SIZE_MAX; 352 } 353 res->type = STL_RES_FILETYPE; 354 res->filetype = stl->type; 355 return STL_OK; 356 } 357 358 switch (stl->type) { 359 case STL_TYPE_ASCII: 360 return stl_feed_ascii(stl, res, chunk, size); 361 case STL_TYPE_BINARY: 362 return stl_feed_binary(stl, res, chunk, size); 363 default: 364 return STL_INVALID_ARG; 365 } 366}