77 {
78 char *inputFile = NULL, *outputFile = NULL;
80 SCANNED_ARG *scanned;
81 long iArg;
82 long ascii = 0;
83 unsigned long pipeFlags = 0;
84
85 int i, n = 0, solid = 0;
86 char init[7];
87 short attribute = 0;
88 int32_t face_num = 0, iface;
89 int32_t bigEndianMachine = 0;
90 int64_t bytes_num = 0, text_num = 0;
91 float *normalVector[3];
92 float *vertex1[3];
93 float *vertex2[3];
94 float *vertex3[3];
95 FILE *fd;
96 char input[LINE_MAX_LEN];
97 char *next;
98 char token[LINE_MAX_LEN];
99 int width;
100
102 argc =
scanargs(&scanned, argc, argv);
103 if (argc < 2) {
104 fprintf(stderr, "%s", USAGE);
105 return EXIT_FAILURE;
106 }
107
108 for (iArg = 1; iArg < argc; iArg++) {
109 if (scanned[iArg].arg_type == OPTION) {
110 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
111 case SET_ASCII:
112 ascii = 1;
113 break;
114 case SET_BINARY:
115 ascii = 0;
116 break;
117 case SET_PIPE:
118 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags)) {
119 fprintf(stderr, "Error: Invalid -pipe syntax.\n");
120 fprintf(stderr, "%s", USAGE);
121 return EXIT_FAILURE;
122 }
123 break;
124 default:
125 fprintf(stderr, "Error: Invalid option detected.\n%s", USAGE);
126 return EXIT_FAILURE;
127 }
128 } else {
129 if (!inputFile)
131 else if (!outputFile)
133 else {
134 fprintf(stderr, "Error: Too many filenames provided.\n%s", USAGE);
135 return EXIT_FAILURE;
136 }
137 }
138 }
139
141
142 if (inputFile) {
144 fprintf(stderr, "Error: Input file '%s' not found.\n", inputFile);
145 return EXIT_FAILURE;
146 }
147 if (!(fd = fopen(inputFile, "rb"))) {
148 fprintf(stderr, "Error: Unable to open input file '%s'.\n", inputFile);
149 return EXIT_FAILURE;
150 }
151 } else {
152#if defined(_WIN32)
153 if (_setmode(_fileno(stdin), _O_BINARY) == -1) {
154 fprintf(stderr, "Error: Unable to set stdin to binary mode.\n");
155 return EXIT_FAILURE;
156 }
157#endif
158 fd = stdin;
159 }
160
162
163
164 bytes_num += fread(&init, 1, 6, fd);
165 init[6] = '\0';
166 int stlascii = (strcasecmp("solid ", init) == 0) ? TRUE : FALSE;
167
168 if (!stlascii) {
169
170 for (i = 0; i < 74; i++) {
171 if (fgetc(fd) == EOF)
172 break;
173 bytes_num++;
174 }
175
176
177 bytes_num += fread(&face_num, 1, sizeof(int32_t), fd);
178 if (bigEndianMachine) {
180 }
181
182 for (i = 0; i < 3; i++) {
183 normalVector[i] = malloc(sizeof(*(normalVector[i])) * face_num);
184 vertex1[i] = malloc(sizeof(*(vertex1[i])) * face_num);
185 vertex2[i] = malloc(sizeof(*(vertex2[i])) * face_num);
186 vertex3[i] = malloc(sizeof(*(vertex3[i])) * face_num);
187 if (!normalVector[i] || !vertex1[i] || !vertex2[i] || !vertex3[i]) {
188 fprintf(stderr, "Error: Memory allocation failed.\n");
189 return EXIT_FAILURE;
190 }
191 }
192
193
194 for (iface = 0; iface < face_num; iface++) {
195 for (i = 0; i < 3; i++) {
196 if (fread(&(normalVector[i][iface]), 1, sizeof(float), fd) != sizeof(float)) {
197 fprintf(stderr, "Error: Unexpected end of file while reading normals.\n");
198 return EXIT_FAILURE;
199 }
200 bytes_num += sizeof(float);
201 if (bigEndianMachine) {
202 normalVector[i][iface] = float_reverse_bytes(normalVector[i][iface]);
203 }
204 }
205 for (i = 0; i < 3; i++) {
206 if (fread(&(vertex1[i][iface]), 1, sizeof(float), fd) != sizeof(float)) {
207 fprintf(stderr, "Error: Unexpected end of file while reading vertex1.\n");
208 return EXIT_FAILURE;
209 }
210 bytes_num += sizeof(float);
211 if (bigEndianMachine) {
212 vertex1[i][iface] = float_reverse_bytes(vertex1[i][iface]);
213 }
214 }
215 for (i = 0; i < 3; i++) {
216 if (fread(&(vertex2[i][iface]), 1, sizeof(float), fd) != sizeof(float)) {
217 fprintf(stderr, "Error: Unexpected end of file while reading vertex2.\n");
218 return EXIT_FAILURE;
219 }
220 bytes_num += sizeof(float);
221 if (bigEndianMachine) {
222 vertex2[i][iface] = float_reverse_bytes(vertex2[i][iface]);
223 }
224 }
225 for (i = 0; i < 3; i++) {
226 if (fread(&(vertex3[i][iface]), 1, sizeof(float), fd) != sizeof(float)) {
227 fprintf(stderr, "Error: Unexpected end of file while reading vertex3.\n");
228 return EXIT_FAILURE;
229 }
230 bytes_num += sizeof(float);
231 if (bigEndianMachine) {
232 vertex3[i][iface] = float_reverse_bytes(vertex3[i][iface]);
233 }
234 }
235 if (fread(&(attribute), 1, sizeof(short int), fd) != sizeof(short int)) {
236 fprintf(stderr, "Error: Unexpected end of file while reading attribute.\n");
237 return EXIT_FAILURE;
238 }
239 bytes_num += sizeof(short int);
240 }
241 } else {
242 for (i = 0; i < 3; i++) {
243 normalVector[i] = NULL;
244 vertex1[i] = NULL;
245 vertex2[i] = NULL;
246 vertex3[i] = NULL;
247 }
248 fseek(fd, 0, SEEK_SET);
249 while (fgets(input, LINE_MAX_LEN, fd) != NULL) {
250 text_num++;
251 for (next = input; *next != '\0' && isspace((unsigned char)*next); next++) {
252 }
253 if (*next == '\0' || *next == '#' || *next == '!' || *next == '$') {
254 continue;
255 }
256 sscanf(next, "%s%n", token, &width);
257 next += width;
258
259 if (leqi(token, "facet")) {
260 if (n == 0) {
261 n++;
262 for (i = 0; i < 3; i++) {
263 normalVector[i] = malloc(sizeof(*(normalVector[i])) * n);
264 vertex1[i] = malloc(sizeof(*(vertex1[i])) * n);
265 vertex2[i] = malloc(sizeof(*(vertex2[i])) * n);
266 vertex3[i] = malloc(sizeof(*(vertex3[i])) * n);
267 if (!normalVector[i] || !vertex1[i] || !vertex2[i] || !vertex3[i]) {
268 fprintf(stderr, "Error: Memory allocation failed.\n");
269 return EXIT_FAILURE;
270 }
271 }
272 } else {
273 n++;
274 for (i = 0; i < 3; i++) {
275 normalVector[i] = realloc(normalVector[i], sizeof(*(normalVector[i])) * n);
276 vertex1[i] = realloc(vertex1[i], sizeof(*(vertex1[i])) * n);
277 vertex2[i] = realloc(vertex2[i], sizeof(*(vertex2[i])) * n);
278 vertex3[i] = realloc(vertex3[i], sizeof(*(vertex3[i])) * n);
279 if (!normalVector[i] || !vertex1[i] || !vertex2[i] || !vertex3[i]) {
280 fprintf(stderr, "Error: Memory allocation failed.\n");
281 return EXIT_FAILURE;
282 }
283 }
284 }
285
286
287 sscanf(next, "%*s %e %e %e",
288 &(normalVector[0][n - 1]),
289 &(normalVector[1][n - 1]),
290 &(normalVector[2][n - 1]));
291
292
293 if (!fgets(input, LINE_MAX_LEN, fd) || !fgets(input, LINE_MAX_LEN, fd)) {
294 fprintf(stderr, "Error: Unexpected end of file while reading outer loop.\n");
295 return EXIT_FAILURE;
296 }
297 text_num += 2;
298
299
300 sscanf(next, "%*s %e %e %e",
301 &(vertex1[0][n - 1]),
302 &(vertex1[1][n - 1]),
303 &(vertex1[2][n - 1]));
304
305
306 if (!fgets(input, LINE_MAX_LEN, fd)) {
307 fprintf(stderr, "Error: Unexpected end of file while reading vertex2.\n");
308 return EXIT_FAILURE;
309 }
310 text_num++;
311
312
313 sscanf(next, "%*s %e %e %e",
314 &(vertex2[0][n - 1]),
315 &(vertex2[1][n - 1]),
316 &(vertex2[2][n - 1]));
317
318
319 if (!fgets(input, LINE_MAX_LEN, fd)) {
320 fprintf(stderr, "Error: Unexpected end of file while reading vertex3.\n");
321 return EXIT_FAILURE;
322 }
323 text_num++;
324
325
326 sscanf(next, "%*s %e %e %e",
327 &(vertex3[0][n - 1]),
328 &(vertex3[1][n - 1]),
329 &(vertex3[2][n - 1]));
330
331
332 if (!fgets(input, LINE_MAX_LEN, fd) || !fgets(input, LINE_MAX_LEN, fd)) {
333 fprintf(stderr, "Error: Unexpected end of file while reading endloop/endfacet.\n");
334 return EXIT_FAILURE;
335 }
336 text_num += 2;
337 } else if (leqi(token, "color")) {
338 fprintf(stderr, "Warning: Color field seen in STL file ignored.\n");
339 } else if (leqi(token, "solid")) {
340 solid++;
341 if (solid > 1) {
342 fprintf(stderr, "Error: More than one solid field seen in STL file.\n");
343 return EXIT_FAILURE;
344 }
345 } else if (leqi(token, "endsolid")) {
346
347 } else {
348 fprintf(stderr, "Error: Unrecognized keyword '%s' in STL file.\n", token);
349 return EXIT_FAILURE;
350 }
351 }
352 face_num = n;
353 }
354
355
358 return EXIT_FAILURE;
359 }
360
361 if (!ascii) {
362 SDDSout.layout.data_mode.column_major = 1;
363 }
364
365
366 const char *columns[] = {
367 "NormalVectorX", "NormalVectorY", "NormalVectorZ",
368 "Vertex1X", "Vertex1Y", "Vertex1Z",
369 "Vertex2X", "Vertex2Y", "Vertex2Z",
370 "Vertex3X", "Vertex3Y", "Vertex3Z"};
371 for (i = 0; i < 12; i++) {
374 return EXIT_FAILURE;
375 }
376 }
377
378
381 return EXIT_FAILURE;
382 }
383
384
385 if (!SDDS_StartTable(&SDDSout, face_num)) {
387 return EXIT_FAILURE;
388 }
389
390
391 const char *column_names[] = {
392 "NormalVectorX", "NormalVectorY", "NormalVectorZ",
393 "Vertex1X", "Vertex1Y", "Vertex1Z",
394 "Vertex2X", "Vertex2Y", "Vertex2Z",
395 "Vertex3X", "Vertex3Y", "Vertex3Z"};
396 float *data_columns[12] = {
397 normalVector[0], normalVector[1], normalVector[2],
398 vertex1[0], vertex1[1], vertex1[2],
399 vertex2[0], vertex2[1], vertex2[2],
400 vertex3[0], vertex3[1], vertex3[2]};
401
402 for (i = 0; i < 12; i++) {
405 return EXIT_FAILURE;
406 }
407 }
408
409
410 if (!SDDS_WriteTable(&SDDSout)) {
413 return EXIT_FAILURE;
414 }
415
416
419 return EXIT_FAILURE;
420 }
421
422
424 for (i = 0; i < 3; i++) {
425 free(normalVector[i]);
426 free(vertex1[i]);
427 free(vertex2[i]);
428 free(vertex3[i]);
429 }
430
431 return EXIT_SUCCESS;
432}
void SDDS_SwapLong(int32_t *data)
Swaps the endianness of a 32-bit integer.
int32_t SDDS_SetColumnFromFloats(SDDS_DATASET *SDDS_dataset, int32_t mode, float *data, int64_t rows,...)
Sets the values for a single data column using single-precision floating-point numbers.
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
#define SDDS_FLOAT
Identifier for the float data type.
long fexists(const char *filename)
Checks if a file exists.
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
void free_scanargs(SCANNED_ARG **scanned, int argc)