libstl-c

C STL file-format library
git clone https://git.sinitax.com/sinitax/libstl-c
Log | Files | Refs | LICENSE | sfeed.txt

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}