1 /*
2
3 The interface routines for reading and writing PLY polygon files.
4
5 Greg Turk, February 1994
6
7 ---------------------------------------------------------------
8
9 A PLY file contains a single polygonal _object_.
10
11 An object is composed of lists of _elements_. Typical elements are
12 vertices, faces, edges and materials.
13
14 Each type of element for a given object has one or more _properties_
15 associated with the element type. For instance, a vertex element may
16 have as properties the floating-point values x,y,z and the three unsigned
17 chars representing red, green and blue.
18
19 ---------------------------------------------------------------
20
21 Copyright (c) 1994 The Board of Trustees of The Leland Stanford
22 Junior University. All rights reserved.
23
24 Permission to use, copy, modify and distribute this software and its
25 documentation for any purpose is hereby granted without fee, provided
26 that the above copyright notice and this permission notice appear in
27 all copies of this software and that you do not sell the software.
28
29 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
31 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
32
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <math.h>
38 #include <string.h>
39 #include "Ply.h"
40
41 const char *type_names[] = {
42 "invalid",
43 "char",
44 "short",
45 "int",
46 "uchar",
47 "ushort",
48 "uint",
49 "float",
50 "double",
51
52 "int8", // character 1
53 "uint8", // unsigned character 1
54 "int16", // short integer 2
55 "uint16", // unsigned short integer 2
56 "int32", // integer 4
57 "uint32", // unsigned integer 4
58 "float32", // single-precision float 4
59 "float64", // double-precision float 8
60
61 };
62
63 int ply_type_size[] = {
64 0,
65 1,
66 2,
67 4,
68 1,
69 2,
70 4,
71 4,
72 8,
73 1,
74 1,
75 2,
76 2,
77 4,
78 4,
79 4,
80 8
81 };
82
83 typedef union
84 {
85 int int_value;
86 char byte_values[sizeof(int)];
87 } endian_test_type;
88
89
90 static int native_binary_type = -1;
91 static int types_checked = 0;
92
93 #define NO_OTHER_PROPS -1
94
95 #define DONT_STORE_PROP 0
96 #define STORE_PROP 1
97
98 #define OTHER_PROP 0
99 #define NAMED_PROP 1
100
101
102 /* returns 1 if strings are equal, 0 if not */
103 int equal_strings(const char *, const char *);
104
105 /* find an element in a plyfile's list */
106 PlyElement *find_element(PlyFile *, const char *);
107
108 /* find a property in an element's list */
109 PlyProperty *find_property(PlyElement *, const char *, int *);
110
111 /* write to a file the word describing a PLY file data type */
112 void write_scalar_type (FILE *, int);
113
114 /* read a line from a file and break it up into separate words */
115 char **get_words(FILE *, int *, char **);
116 char **old_get_words(FILE *, int *);
117
118 /* write an item to a file */
119 void write_binary_item(FILE *, int, int, unsigned int, double, int);
120 void write_ascii_item(FILE *, int, unsigned int, double, int);
121 double old_write_ascii_item(FILE *, char *, int);
122
123 /* add information to a PLY file descriptor */
124 void add_element(PlyFile *, char **);
125 void add_property(PlyFile *, char **);
126 void add_comment(PlyFile *, char *);
127 void add_obj_info(PlyFile *, char *);
128
129 /* copy a property */
130 void copy_property(PlyProperty *, PlyProperty *);
131
132 /* store a value into where a pointer and a type specify */
133 void store_item(char *, int, int, unsigned int, double);
134
135 /* return the value of a stored item */
136 void get_stored_item( void *, int, int *, unsigned int *, double *);
137
138 /* return the value stored in an item, given ptr to it and its type */
139 double get_item_value(char *, int);
140
141 /* get binary or ascii item and store it according to ptr and type */
142 void get_ascii_item(char *, int, int *, unsigned int *, double *);
143 void get_binary_item(FILE *, int, int, int *, unsigned int *, double *);
144
145 /* get a bunch of elements from a file */
146 void ascii_get_element(PlyFile *, char *);
147 void binary_get_element(PlyFile *, char *);
148
149 /* memory allocation */
150 char *my_alloc(int, int, const char *);
151
152 /* byte ordering */
153 void get_native_binary_type();
154 void swap_bytes(char *, int);
155
156 void check_types();
157
158 /*************/
159 /* Writing */
160 /*************/
161
162
163 /******************************************************************************
164 Given a file pointer, get ready to write PLY data to the file.
165
166 Entry:
167 fp - the given file pointer
168 nelems - number of elements in object
169 elem_names - list of element names
170 file_type - file type, either ascii or binary
171
172 Exit:
173 returns a pointer to a PlyFile, used to refer to this file, or NULL if error
174 ******************************************************************************/
175
ply_write(FILE * fp,int nelems,const char ** elem_names,int file_type)176 PlyFile *ply_write(
177 FILE *fp,
178 int nelems,
179 const char **elem_names,
180 int file_type
181 )
182 {
183 int i;
184 PlyFile *plyfile;
185 PlyElement *elem;
186
187 /* check for NULL file pointer */
188 if (fp == NULL)
189 return (NULL);
190
191 if (native_binary_type == -1)
192 get_native_binary_type();
193 if (!types_checked)
194 check_types();
195
196 /* create a record for this object */
197
198 plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
199 if (file_type == PLY_BINARY_NATIVE)
200 plyfile->file_type = native_binary_type;
201 else
202 plyfile->file_type = file_type;
203 plyfile->num_comments = 0;
204 plyfile->num_obj_info = 0;
205 plyfile->nelems = nelems;
206 plyfile->version = 1.0;
207 plyfile->fp = fp;
208 plyfile->other_elems = NULL;
209
210 /* tuck aside the names of the elements */
211
212 plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems);
213 for (i = 0; i < nelems; i++) {
214 elem = (PlyElement *) myalloc (sizeof (PlyElement));
215 plyfile->elems[i] = elem;
216 elem->name = _strdup (elem_names[i]);
217 elem->num = 0;
218 elem->nprops = 0;
219 }
220
221 /* return pointer to the file descriptor */
222 return (plyfile);
223 }
224
225
226 /******************************************************************************
227 Open a polygon file for writing.
228
229 Entry:
230 filename - name of file to read from
231 nelems - number of elements in object
232 elem_names - list of element names
233 file_type - file type, either ascii or binary
234
235 Exit:
236 version - version number of PLY file
237 returns a file identifier, used to refer to this file, or NULL if error
238 ******************************************************************************/
239
ply_open_for_writing(char * filename,int nelems,const char ** elem_names,int file_type,float * version)240 PlyFile *ply_open_for_writing(
241 char *filename,
242 int nelems,
243 const char **elem_names,
244 int file_type,
245 float *version
246 )
247 {
248 PlyFile *plyfile;
249 char *name;
250 FILE *fp;
251
252 /* tack on the extension .ply, if necessary */
253
254 name = (char *) myalloc (int(sizeof (char) * (strlen (filename)) + 5));
255 strcpy (name, filename);
256 if (strlen (name) < 4 ||
257 strcmp (name + strlen (name) - 4, ".ply") != 0)
258 strcat (name, ".ply");
259
260 /* open the file for writing */
261
262 fp = fopen (name, "wb");
263 free(name);
264 if (fp == NULL) {
265 return (NULL);
266 }
267
268 /* create the actual PlyFile structure */
269
270 plyfile = ply_write (fp, nelems, elem_names, file_type);
271 if (plyfile == NULL)
272 return (NULL);
273
274 /* say what PLY file version number we're writing */
275 *version = plyfile->version;
276
277 /* return pointer to the file descriptor */
278 return (plyfile);
279 }
280
281
282 /******************************************************************************
283 Describe an element, including its properties and how many will be written
284 to the file.
285
286 Entry:
287 plyfile - file identifier
288 elem_name - name of element that information is being specified about
289 nelems - number of elements of this type to be written
290 nprops - number of properties contained in the element
291 prop_list - list of properties
292 ******************************************************************************/
293
ply_describe_element(PlyFile * plyfile,char * elem_name,int nelems,int nprops,PlyProperty * prop_list)294 void ply_describe_element(
295 PlyFile *plyfile,
296 char *elem_name,
297 int nelems,
298 int nprops,
299 PlyProperty *prop_list
300 )
301 {
302 int i;
303 PlyElement *elem;
304 PlyProperty *prop;
305
306 /* look for appropriate element */
307 elem = find_element (plyfile, elem_name);
308 if (elem == NULL) {
309 fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name);
310 exit (-1);
311 }
312
313 elem->num = nelems;
314
315 /* copy the list of properties */
316
317 elem->nprops = nprops;
318 elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops);
319 elem->store_prop = (char *) myalloc (sizeof (char) * nprops);
320
321 for (i = 0; i < nprops; i++) {
322 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
323 elem->props[i] = prop;
324 elem->store_prop[i] = NAMED_PROP;
325 copy_property (prop, &prop_list[i]);
326 }
327 }
328
329
330 /******************************************************************************
331 Describe a property of an element.
332
333 Entry:
334 plyfile - file identifier
335 elem_name - name of element that information is being specified about
336 prop - the new property
337 ******************************************************************************/
338
ply_describe_property(PlyFile * plyfile,const char * elem_name,PlyProperty * prop)339 void ply_describe_property(
340 PlyFile *plyfile,
341 const char *elem_name,
342 PlyProperty *prop
343 )
344 {
345 PlyElement *elem;
346 PlyProperty *elem_prop;
347
348 /* look for appropriate element */
349 elem = find_element (plyfile, elem_name);
350 if (elem == NULL) {
351 fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
352 elem_name);
353 return;
354 }
355
356 /* create room for new property */
357
358 if (elem->nprops == 0) {
359 elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
360 elem->store_prop = (char *) myalloc (sizeof (char));
361 elem->nprops = 1;
362 }
363 else {
364 elem->nprops++;
365 elem->props = (PlyProperty **)
366 realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
367 elem->store_prop = (char *)
368 realloc (elem->store_prop, sizeof (char) * elem->nprops);
369 }
370
371 /* copy the new property */
372
373 elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
374 elem->props[elem->nprops - 1] = elem_prop;
375 elem->store_prop[elem->nprops - 1] = NAMED_PROP;
376 copy_property (elem_prop, prop);
377 }
378
379
380 /******************************************************************************
381 Describe what the "other" properties are that are to be stored, and where
382 they are in an element.
383 ******************************************************************************/
384
ply_describe_other_properties(PlyFile * plyfile,PlyOtherProp * other,int offset)385 void ply_describe_other_properties(
386 PlyFile *plyfile,
387 PlyOtherProp *other,
388 int offset
389 )
390 {
391 int i;
392 PlyElement *elem;
393 PlyProperty *prop;
394
395 /* look for appropriate element */
396 elem = find_element (plyfile, other->name);
397 if (elem == NULL) {
398 fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n",
399 other->name);
400 return;
401 }
402
403 /* create room for other properties */
404
405 if (elem->nprops == 0) {
406 elem->props = (PlyProperty **)
407 myalloc (sizeof (PlyProperty *) * other->nprops);
408 elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops);
409 elem->nprops = 0;
410 }
411 else {
412 int newsize;
413 newsize = elem->nprops + other->nprops;
414 elem->props = (PlyProperty **)
415 realloc (elem->props, sizeof (PlyProperty *) * newsize);
416 elem->store_prop = (char *)
417 realloc (elem->store_prop, sizeof (char) * newsize);
418 }
419
420 /* copy the other properties */
421
422 for (i = 0; i < other->nprops; i++) {
423 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
424 copy_property (prop, other->props[i]);
425 elem->props[elem->nprops] = prop;
426 elem->store_prop[elem->nprops] = OTHER_PROP;
427 elem->nprops++;
428 }
429
430 /* save other info about other properties */
431 elem->other_size = other->size;
432 elem->other_offset = offset;
433 }
434
435
436 /******************************************************************************
437 State how many of a given element will be written.
438
439 Entry:
440 plyfile - file identifier
441 elem_name - name of element that information is being specified about
442 nelems - number of elements of this type to be written
443 ******************************************************************************/
444
ply_element_count(PlyFile * plyfile,const char * elem_name,int nelems)445 void ply_element_count(
446 PlyFile *plyfile,
447 const char *elem_name,
448 int nelems
449 )
450 {
451 PlyElement *elem;
452
453 /* look for appropriate element */
454 elem = find_element (plyfile, elem_name);
455 if (elem == NULL) {
456 fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name);
457 exit (-1);
458 }
459
460 elem->num = nelems;
461 }
462
463
464 /******************************************************************************
465 Signal that we've described everything a PLY file's header and that the
466 header should be written to the file.
467
468 Entry:
469 plyfile - file identifier
470 ******************************************************************************/
471
ply_header_complete(PlyFile * plyfile)472 void ply_header_complete(PlyFile *plyfile)
473 {
474 int i,j;
475 FILE *fp = plyfile->fp;
476 PlyElement *elem;
477 PlyProperty *prop;
478
479 fprintf (fp, "ply\n");
480
481 switch (plyfile->file_type) {
482 case PLY_ASCII:
483 fprintf (fp, "format ascii 1.0\n");
484 break;
485 case PLY_BINARY_BE:
486 fprintf (fp, "format binary_big_endian 1.0\n");
487 break;
488 case PLY_BINARY_LE:
489 fprintf (fp, "format binary_little_endian 1.0\n");
490 break;
491 default:
492 fprintf (stderr, "ply_header_complete: bad file type = %d\n",
493 plyfile->file_type);
494 exit (-1);
495 }
496
497 /* write out the comments */
498
499 for (i = 0; i < plyfile->num_comments; i++)
500 fprintf (fp, "comment %s\n", plyfile->comments[i]);
501
502 /* write out object information */
503
504 for (i = 0; i < plyfile->num_obj_info; i++)
505 fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]);
506
507 /* write out information about each element */
508
509 for (i = 0; i < plyfile->nelems; i++) {
510
511 elem = plyfile->elems[i];
512 fprintf (fp, "element %s %d\n", elem->name, elem->num);
513
514 /* write out each property */
515 for (j = 0; j < elem->nprops; j++) {
516 prop = elem->props[j];
517 if (prop->is_list) {
518 fprintf (fp, "property list ");
519 write_scalar_type (fp, prop->count_external);
520 fprintf (fp, " ");
521 write_scalar_type (fp, prop->external_type);
522 fprintf (fp, " %s\n", prop->name);
523 }
524 else {
525 fprintf (fp, "property ");
526 write_scalar_type (fp, prop->external_type);
527 fprintf (fp, " %s\n", prop->name);
528 }
529 }
530 }
531
532 fprintf (fp, "end_header\n");
533 }
534
535
536 /******************************************************************************
537 Specify which elements are going to be written. This should be called
538 before a call to the routine ply_put_element().
539
540 Entry:
541 plyfile - file identifier
542 elem_name - name of element we're talking about
543 ******************************************************************************/
544
ply_put_element_setup(PlyFile * plyfile,const char * elem_name)545 void ply_put_element_setup(PlyFile *plyfile, const char *elem_name)
546 {
547 PlyElement *elem;
548
549 elem = find_element (plyfile, elem_name);
550 if (elem == NULL) {
551 fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name);
552 exit (-1);
553 }
554
555 plyfile->which_elem = elem;
556 }
557
558
559 /******************************************************************************
560 Write an element to the file. This routine assumes that we're
561 writing the type of element specified in the last call to the routine
562 ply_put_element_setup().
563
564 Entry:
565 plyfile - file identifier
566 elem_ptr - pointer to the element
567 ******************************************************************************/
568
ply_put_element(PlyFile * plyfile,void * elem_ptr)569 void ply_put_element(PlyFile *plyfile, void *elem_ptr)
570 {
571 int j,k;
572 FILE *fp = plyfile->fp;
573 PlyElement *elem;
574 PlyProperty *prop;
575 char *elem_data,*item;
576 char **item_ptr;
577 int list_count;
578 int item_size;
579 int int_val;
580 unsigned int uint_val;
581 double double_val;
582 char **other_ptr;
583
584 elem = plyfile->which_elem;
585 elem_data = (char *)elem_ptr;
586 other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
587
588 /* write out either to an ascii or binary file */
589
590 if (plyfile->file_type == PLY_ASCII) {
591
592 /* write an ascii file */
593
594 /* write out each property of the element */
595 for (j = 0; j < elem->nprops; j++) {
596 prop = elem->props[j];
597 if (elem->store_prop[j] == OTHER_PROP)
598 elem_data = *other_ptr;
599 else
600 elem_data = (char *)elem_ptr;
601 if (prop->is_list) {
602 item = elem_data + prop->count_offset;
603 get_stored_item ((void *) item, prop->count_internal,
604 &int_val, &uint_val, &double_val);
605 write_ascii_item (fp, int_val, uint_val, double_val,
606 prop->count_external);
607 list_count = uint_val;
608 item_ptr = (char **) (elem_data + prop->offset);
609 item = item_ptr[0];
610 item_size = ply_type_size[prop->internal_type];
611 for (k = 0; k < list_count; k++) {
612 get_stored_item ((void *) item, prop->internal_type,
613 &int_val, &uint_val, &double_val);
614 write_ascii_item (fp, int_val, uint_val, double_val,
615 prop->external_type);
616 item += item_size;
617 }
618 }
619 else {
620 item = elem_data + prop->offset;
621 get_stored_item ((void *) item, prop->internal_type,
622 &int_val, &uint_val, &double_val);
623 write_ascii_item (fp, int_val, uint_val, double_val,
624 prop->external_type);
625 }
626 }
627
628 fprintf (fp, "\n");
629 }
630 else {
631
632 /* write a binary file */
633
634 /* write out each property of the element */
635 for (j = 0; j < elem->nprops; j++) {
636 prop = elem->props[j];
637 if (elem->store_prop[j] == OTHER_PROP)
638 elem_data = *other_ptr;
639 else
640 elem_data = (char *)elem_ptr;
641 if (prop->is_list) {
642 item = elem_data + prop->count_offset;
643 item_size = ply_type_size[prop->count_internal];
644 get_stored_item ((void *) item, prop->count_internal,
645 &int_val, &uint_val, &double_val);
646 write_binary_item (fp, plyfile->file_type, int_val, uint_val,
647 double_val, prop->count_external);
648 list_count = uint_val;
649 item_ptr = (char **) (elem_data + prop->offset);
650 item = item_ptr[0];
651 item_size = ply_type_size[prop->internal_type];
652 for (k = 0; k < list_count; k++) {
653 get_stored_item ((void *) item, prop->internal_type,
654 &int_val, &uint_val, &double_val);
655 write_binary_item (fp, plyfile->file_type, int_val, uint_val,
656 double_val, prop->external_type);
657 item += item_size;
658 }
659 }
660 else {
661 item = elem_data + prop->offset;
662 item_size = ply_type_size[prop->internal_type];
663 get_stored_item ((void *) item, prop->internal_type,
664 &int_val, &uint_val, &double_val);
665 write_binary_item (fp, plyfile->file_type, int_val, uint_val,
666 double_val, prop->external_type);
667 }
668 }
669
670 }
671 }
672
673
674 /******************************************************************************
675 Specify a comment that will be written in the header.
676
677 Entry:
678 plyfile - file identifier
679 comment - the comment to be written
680 ******************************************************************************/
681
ply_put_comment(PlyFile * plyfile,char * comment)682 void ply_put_comment(PlyFile *plyfile, char *comment)
683 {
684 /* (re)allocate space for new comment */
685 if (plyfile->num_comments == 0)
686 plyfile->comments = (char **) myalloc (sizeof (char *));
687 else
688 plyfile->comments = (char **) realloc (plyfile->comments,
689 sizeof (char *) * (plyfile->num_comments + 1));
690
691 /* add comment to list */
692 plyfile->comments[plyfile->num_comments] = _strdup (comment);
693 plyfile->num_comments++;
694 }
695
696
697 /******************************************************************************
698 Specify a piece of object information (arbitrary text) that will be written
699 in the header.
700
701 Entry:
702 plyfile - file identifier
703 obj_info - the text information to be written
704 ******************************************************************************/
705
ply_put_obj_info(PlyFile * plyfile,char * obj_info)706 void ply_put_obj_info(PlyFile *plyfile, char *obj_info)
707 {
708 /* (re)allocate space for new info */
709 if (plyfile->num_obj_info == 0)
710 plyfile->obj_info = (char **) myalloc (sizeof (char *));
711 else
712 plyfile->obj_info = (char **) realloc (plyfile->obj_info,
713 sizeof (char *) * (plyfile->num_obj_info + 1));
714
715 /* add info to list */
716 plyfile->obj_info[plyfile->num_obj_info] = _strdup (obj_info);
717 plyfile->num_obj_info++;
718 }
719
720
721
722
723
724
725
726 /*************/
727 /* Reading */
728 /*************/
729
730
731
732 /******************************************************************************
733 Given a file pointer, get ready to read PLY data from the file.
734
735 Entry:
736 fp - the given file pointer
737
738 Exit:
739 nelems - number of elements in object
740 elem_names - list of element names
741 returns a pointer to a PlyFile, used to refer to this file, or NULL if error
742 ******************************************************************************/
743
ply_read(FILE * fp,int * nelems,char *** elem_names)744 PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
745 {
746 int i,j;
747 PlyFile *plyfile;
748 int nwords;
749 char **words;
750 char **elist;
751 PlyElement *elem;
752 char *orig_line;
753 /* check for NULL file pointer */
754 if (fp == NULL)
755 return (NULL);
756
757 if (native_binary_type == -1)
758 get_native_binary_type();
759 if (!types_checked)
760 check_types();
761 /* create record for this object */
762
763 plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
764 plyfile->nelems = 0;
765 plyfile->comments = NULL;
766 plyfile->num_comments = 0;
767 plyfile->obj_info = NULL;
768 plyfile->num_obj_info = 0;
769 plyfile->fp = fp;
770 plyfile->other_elems = NULL;
771
772 /* read and parse the file's header */
773
774 words = get_words (plyfile->fp, &nwords, &orig_line);
775 if (!words || !equal_strings (words[0], "ply"))
776 {
777 if (words)
778 free(words);
779 return (NULL);
780 }
781 while (words) {
782 /* parse words */
783
784 if (equal_strings (words[0], "format")) {
785 if (nwords != 3) {
786 free(words);
787 return (NULL);
788 }
789 if (equal_strings (words[1], "ascii"))
790 plyfile->file_type = PLY_ASCII;
791 else if (equal_strings (words[1], "binary_big_endian"))
792 plyfile->file_type = PLY_BINARY_BE;
793 else if (equal_strings (words[1], "binary_little_endian"))
794 plyfile->file_type = PLY_BINARY_LE;
795 else {
796 free(words);
797 return (NULL);
798 }
799 plyfile->version = (float)atof (words[2]);
800 }
801 else if (equal_strings (words[0], "element"))
802 add_element (plyfile, words);
803 else if (equal_strings (words[0], "property"))
804 add_property (plyfile, words);
805 else if (equal_strings (words[0], "comment"))
806 add_comment (plyfile, orig_line);
807 else if (equal_strings (words[0], "obj_info"))
808 add_obj_info (plyfile, orig_line);
809 else if (equal_strings (words[0], "end_header")) {
810 free(words);
811 break;
812 }
813
814 /* free up words space */
815 free (words);
816
817 words = get_words (plyfile->fp, &nwords, &orig_line);
818 }
819
820 /* create tags for each property of each element, to be used */
821 /* later to say whether or not to store each property for the user */
822
823 for (i = 0; i < plyfile->nelems; i++) {
824 elem = plyfile->elems[i];
825 elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
826 for (j = 0; j < elem->nprops; j++)
827 elem->store_prop[j] = DONT_STORE_PROP;
828 elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
829 }
830
831 /* set return values about the elements */
832
833 elist = (char **) myalloc (sizeof (char *) * plyfile->nelems);
834 for (i = 0; i < plyfile->nelems; i++)
835 elist[i] = _strdup (plyfile->elems[i]->name);
836
837 *elem_names = elist;
838 *nelems = plyfile->nelems;
839
840 /* return a pointer to the file's information */
841
842 return (plyfile);
843 }
844
845
846 /******************************************************************************
847 Open a polygon file for reading.
848
849 Entry:
850 filename - name of file to read from
851
852 Exit:
853 nelems - number of elements in object
854 elem_names - list of element names
855 file_type - file type, either ascii or binary
856 version - version number of PLY file
857 returns a file identifier, used to refer to this file, or NULL if error
858 ******************************************************************************/
859
ply_open_for_reading(char * filename,int * nelems,char *** elem_names,int * file_type,float * version)860 PlyFile *ply_open_for_reading(
861 char *filename,
862 int *nelems,
863 char ***elem_names,
864 int *file_type,
865 float *version
866 )
867 {
868 FILE *fp;
869 PlyFile *plyfile;
870 char *name;
871
872 /* tack on the extension .ply, if necessary */
873
874 name = (char *) myalloc (int(sizeof (char) * (strlen (filename) + 5)));
875 strcpy (name, filename);
876 if (strlen (name) < 4 ||
877 strcmp (name + strlen (name) - 4, ".ply") != 0)
878 strcat (name, ".ply");
879
880 /* open the file for reading */
881
882 fp = fopen (name, "rb");
883 free(name);
884 if (fp == NULL)
885 return (NULL);
886
887 /* create the PlyFile data structure */
888
889 plyfile = ply_read (fp, nelems, elem_names);
890
891 /* determine the file type and version */
892
893 *file_type = plyfile->file_type;
894 *version = plyfile->version;
895
896 /* return a pointer to the file's information */
897
898 return (plyfile);
899 }
900
901
902 /******************************************************************************
903 Get information about a particular element.
904
905 Entry:
906 plyfile - file identifier
907 elem_name - name of element to get information about
908
909 Exit:
910 nelems - number of elements of this type in the file
911 nprops - number of properties
912 returns a list of properties, or NULL if the file doesn't contain that elem
913 ******************************************************************************/
914
ply_get_element_description(PlyFile * plyfile,char * elem_name,int * nelems,int * nprops)915 PlyProperty **ply_get_element_description(
916 PlyFile *plyfile,
917 char *elem_name,
918 int *nelems,
919 int *nprops
920 )
921 {
922 int i;
923 PlyElement *elem;
924 PlyProperty *prop;
925 PlyProperty **prop_list;
926
927 /* find information about the element */
928 elem = find_element (plyfile, elem_name);
929 if (elem == NULL)
930 return (NULL);
931
932 *nelems = elem->num;
933 *nprops = elem->nprops;
934
935 /* make a copy of the element's property list */
936 prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
937 for (i = 0; i < elem->nprops; i++) {
938 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
939 copy_property (prop, elem->props[i]);
940 prop_list[i] = prop;
941 }
942
943 /* return this duplicate property list */
944 return (prop_list);
945 }
946
947
948 /******************************************************************************
949 Specify which properties of an element are to be returned. This should be
950 called before a call to the routine ply_get_element().
951
952 Entry:
953 plyfile - file identifier
954 elem_name - which element we're talking about
955 nprops - number of properties
956 prop_list - list of properties
957 ******************************************************************************/
958
ply_get_element_setup(PlyFile * plyfile,char * elem_name,int nprops,PlyProperty * prop_list)959 void ply_get_element_setup(
960 PlyFile *plyfile,
961 char *elem_name,
962 int nprops,
963 PlyProperty *prop_list
964 )
965 {
966 int i;
967 PlyElement *elem;
968 PlyProperty *prop;
969 int index;
970
971 /* find information about the element */
972 elem = find_element (plyfile, elem_name);
973 plyfile->which_elem = elem;
974
975 /* deposit the property information into the element's description */
976 for (i = 0; i < nprops; i++) {
977
978 /* look for actual property */
979 prop = find_property (elem, prop_list[i].name, &index);
980 if (prop == NULL) {
981 fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
982 prop_list[i].name, elem_name);
983 continue;
984 }
985
986 /* store its description */
987 prop->internal_type = prop_list[i].internal_type;
988 prop->offset = prop_list[i].offset;
989 prop->count_internal = prop_list[i].count_internal;
990 prop->count_offset = prop_list[i].count_offset;
991
992 /* specify that the user wants this property */
993 elem->store_prop[index] = STORE_PROP;
994 }
995 }
996
997
998 /******************************************************************************
999 Specify a property of an element that is to be returned. This should be
1000 called (usually multiple times) before a call to the routine ply_get_element().
1001 This routine should be used in preference to the less flexible old routine
1002 called ply_get_element_setup().
1003
1004 Entry:
1005 plyfile - file identifier
1006 elem_name - which element we're talking about
1007 prop - property to add to those that will be returned
1008 ******************************************************************************/
1009
ply_get_property(PlyFile * plyfile,char * elem_name,PlyProperty * prop)1010 int ply_get_property(
1011 PlyFile *plyfile,
1012 char *elem_name,
1013 PlyProperty *prop
1014 )
1015 {
1016 PlyElement *elem;
1017 PlyProperty *prop_ptr;
1018 int index;
1019
1020 /* find information about the element */
1021 elem = find_element (plyfile, elem_name);
1022 plyfile->which_elem = elem;
1023
1024 /* deposit the property information into the element's description */
1025
1026 prop_ptr = find_property (elem, prop->name, &index);
1027 if (prop_ptr == NULL) {
1028 // fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
1029 // prop->name, elem_name);
1030 // return;
1031 return 0;
1032 }
1033 prop_ptr->internal_type = prop->internal_type;
1034 prop_ptr->offset = prop->offset;
1035 prop_ptr->count_internal = prop->count_internal;
1036 prop_ptr->count_offset = prop->count_offset;
1037
1038 /* specify that the user wants this property */
1039 elem->store_prop[index] = STORE_PROP;
1040 return 1;
1041 }
1042
1043
1044 /******************************************************************************
1045 Read one element from the file. This routine assumes that we're reading
1046 the type of element specified in the last call to the routine
1047 ply_get_element_setup().
1048
1049 Entry:
1050 plyfile - file identifier
1051 elem_ptr - pointer to location where the element information should be put
1052 ******************************************************************************/
1053
ply_get_element(PlyFile * plyfile,void * elem_ptr)1054 void ply_get_element(PlyFile *plyfile, void *elem_ptr)
1055 {
1056 if (plyfile->file_type == PLY_ASCII)
1057 ascii_get_element (plyfile, (char *) elem_ptr);
1058 else
1059 binary_get_element (plyfile, (char *) elem_ptr);
1060 }
1061
1062
1063 /******************************************************************************
1064 Extract the comments from the header information of a PLY file.
1065
1066 Entry:
1067 plyfile - file identifier
1068
1069 Exit:
1070 num_comments - number of comments returned
1071 returns a pointer to a list of comments
1072 ******************************************************************************/
1073
ply_get_comments(PlyFile * plyfile,int * num_comments)1074 char **ply_get_comments(PlyFile *plyfile, int *num_comments)
1075 {
1076 *num_comments = plyfile->num_comments;
1077 return (plyfile->comments);
1078 }
1079
1080
1081 /******************************************************************************
1082 Extract the object information (arbitrary text) from the header information
1083 of a PLY file.
1084
1085 Entry:
1086 plyfile - file identifier
1087
1088 Exit:
1089 num_obj_info - number of lines of text information returned
1090 returns a pointer to a list of object info lines
1091 ******************************************************************************/
1092
ply_get_obj_info(PlyFile * plyfile,int * num_obj_info)1093 char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info)
1094 {
1095 *num_obj_info = plyfile->num_obj_info;
1096 return (plyfile->obj_info);
1097 }
1098
1099
1100 /******************************************************************************
1101 Make ready for "other" properties of an element-- those properties that
1102 the user has not explicitly asked for, but that are to be stashed away
1103 in a special structure to be carried along with the element's other
1104 information.
1105
1106 Entry:
1107 plyfile - file identifier
1108 elem - element for which we want to save away other properties
1109 ******************************************************************************/
1110
setup_other_props(PlyElement * elem)1111 void setup_other_props(PlyElement *elem)
1112 {
1113 int i;
1114 PlyProperty *prop;
1115 int size = 0;
1116 int type_size;
1117
1118 /* Examine each property in decreasing order of size. */
1119 /* We do this so that all data types will be aligned by */
1120 /* word, half-word, or whatever within the structure. */
1121
1122 for (type_size = 8; type_size > 0; type_size /= 2) {
1123
1124 /* add up the space taken by each property, and save this information */
1125 /* away in the property descriptor */
1126
1127 for (i = 0; i < elem->nprops; i++) {
1128
1129 /* don't bother with properties we've been asked to store explicitly */
1130 if (elem->store_prop[i])
1131 continue;
1132
1133 prop = elem->props[i];
1134
1135 /* internal types will be same as external */
1136 prop->internal_type = prop->external_type;
1137 prop->count_internal = prop->count_external;
1138
1139 /* check list case */
1140 if (prop->is_list) {
1141
1142 /* pointer to list */
1143 if (type_size == sizeof (void *)) {
1144 prop->offset = size;
1145 size += sizeof (void *); /* always use size of a pointer here */
1146 }
1147
1148 /* count of number of list elements */
1149 if (type_size == ply_type_size[prop->count_external]) {
1150 prop->count_offset = size;
1151 size += ply_type_size[prop->count_external];
1152 }
1153 }
1154 /* not list */
1155 else if (type_size == ply_type_size[prop->external_type]) {
1156 prop->offset = size;
1157 size += ply_type_size[prop->external_type];
1158 }
1159 }
1160
1161 }
1162
1163 /* save the size for the other_props structure */
1164 elem->other_size = size;
1165 }
1166
1167
1168 /******************************************************************************
1169 Specify that we want the "other" properties of an element to be tucked
1170 away within the user's structure. The user needn't be concerned for how
1171 these properties are stored.
1172
1173 Entry:
1174 plyfile - file identifier
1175 elem_name - name of element that we want to store other_props in
1176 offset - offset to where other_props will be stored inside user's structure
1177
1178 Exit:
1179 returns pointer to structure containing description of other_props
1180 ******************************************************************************/
1181
ply_get_other_properties(PlyFile * plyfile,char * elem_name,int offset)1182 PlyOtherProp *ply_get_other_properties(
1183 PlyFile *plyfile,
1184 char *elem_name,
1185 int offset
1186 )
1187 {
1188 int i;
1189 PlyElement *elem;
1190 PlyOtherProp *other;
1191 PlyProperty *prop;
1192 int nprops;
1193
1194 /* find information about the element */
1195 elem = find_element (plyfile, elem_name);
1196 if (elem == NULL) {
1197 fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
1198 elem_name);
1199 return (NULL);
1200 }
1201
1202 /* remember that this is the "current" element */
1203 plyfile->which_elem = elem;
1204
1205 /* save the offset to where to store the other_props */
1206 elem->other_offset = offset;
1207
1208 /* place the appropriate pointers, etc. in the element's property list */
1209 setup_other_props (elem);
1210
1211 /* create structure for describing other_props */
1212 other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
1213 other->name = _strdup (elem_name);
1214 other->size = elem->other_size;
1215 other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops);
1216
1217 /* save descriptions of each "other" property */
1218 nprops = 0;
1219 for (i = 0; i < elem->nprops; i++) {
1220 if (elem->store_prop[i])
1221 continue;
1222 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
1223 copy_property (prop, elem->props[i]);
1224 other->props[nprops] = prop;
1225 nprops++;
1226 }
1227 other->nprops = nprops;
1228
1229 /* set other_offset pointer appropriately if there are NO other properties */
1230 if (other->nprops == 0) {
1231 elem->other_offset = NO_OTHER_PROPS;
1232 }
1233
1234 /* return structure */
1235 return (other);
1236 }
1237
1238
1239
1240
1241 /*************************/
1242 /* Other Element Stuff */
1243 /*************************/
1244
1245
1246
1247
1248 /******************************************************************************
1249 Grab all the data for an element that a user does not want to explicitly
1250 read in.
1251
1252 Entry:
1253 plyfile - pointer to file
1254 elem_name - name of element whose data is to be read in
1255 elem_count - number of instances of this element stored in the file
1256
1257 Exit:
1258 returns pointer to ALL the "other" element data for this PLY file
1259 ******************************************************************************/
1260
ply_get_other_element(PlyFile * plyfile,char * elem_name,int elem_count)1261 PlyOtherElems *ply_get_other_element (
1262 PlyFile *plyfile,
1263 char *elem_name,
1264 int elem_count
1265 )
1266 {
1267 int i;
1268 PlyElement *elem;
1269 PlyOtherElems *other_elems;
1270 OtherElem *other;
1271
1272 /* look for appropriate element */
1273 elem = find_element (plyfile, elem_name);
1274 if (elem == NULL) {
1275 fprintf (stderr,
1276 "ply_get_other_element: can't find element '%s'\n", elem_name);
1277 exit (-1);
1278 }
1279
1280 /* create room for the new "other" element, initializing the */
1281 /* other data structure if necessary */
1282
1283 if (plyfile->other_elems == NULL) {
1284 plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
1285 other_elems = plyfile->other_elems;
1286 other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
1287 other = &(other_elems->other_list[0]);
1288 other_elems->num_elems = 1;
1289 }
1290 else {
1291 other_elems = plyfile->other_elems;
1292 other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
1293 sizeof (OtherElem) * other_elems->num_elems + 1);
1294 other = &(other_elems->other_list[other_elems->num_elems]);
1295 other_elems->num_elems++;
1296 }
1297
1298 /* count of element instances in file */
1299 other->elem_count = elem_count;
1300
1301 /* save name of element */
1302 other->elem_name = _strdup (elem_name);
1303
1304 /* create a list to hold all the current elements */
1305 other->other_data = (OtherData **)
1306 malloc (sizeof (OtherData *) * other->elem_count);
1307
1308 /* set up for getting elements */
1309 other->other_props = ply_get_other_properties (plyfile, elem_name,
1310 offsetof(OtherData,other_props));
1311
1312 /* grab all these elements */
1313 for (i = 0; i < other->elem_count; i++) {
1314 /* grab and element from the file */
1315 other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
1316 ply_get_element (plyfile, (void *) other->other_data[i]);
1317 }
1318
1319 /* return pointer to the other elements data */
1320 return (other_elems);
1321 }
1322
1323
1324 /******************************************************************************
1325 Pass along a pointer to "other" elements that we want to save in a given
1326 PLY file. These other elements were presumably read from another PLY file.
1327
1328 Entry:
1329 plyfile - file pointer in which to store this other element info
1330 other_elems - info about other elements that we want to store
1331 ******************************************************************************/
1332
ply_describe_other_elements(PlyFile * plyfile,PlyOtherElems * other_elems)1333 void ply_describe_other_elements (
1334 PlyFile *plyfile,
1335 PlyOtherElems *other_elems
1336 )
1337 {
1338 int i;
1339 OtherElem *other;
1340 PlyElement *elem;
1341
1342 /* ignore this call if there is no other element */
1343 if (other_elems == NULL)
1344 return;
1345
1346 /* save pointer to this information */
1347 plyfile->other_elems = other_elems;
1348
1349 /* describe the other properties of this element */
1350 /* store them in the main element list as elements with
1351 only other properties */
1352
1353 REALLOCN(plyfile->elems, PlyElement *,
1354 plyfile->nelems, plyfile->nelems + other_elems->num_elems);
1355 for (i = 0; i < other_elems->num_elems; i++) {
1356 other = &(other_elems->other_list[i]);
1357 elem = (PlyElement *) myalloc (sizeof (PlyElement));
1358 plyfile->elems[plyfile->nelems++] = elem;
1359 elem->name = _strdup (other->elem_name);
1360 elem->num = other->elem_count;
1361 elem->nprops = 0;
1362 ply_describe_other_properties (plyfile, other->other_props,
1363 offsetof(OtherData,other_props));
1364 }
1365 }
1366
1367
1368 /******************************************************************************
1369 Write out the "other" elements specified for this PLY file.
1370
1371 Entry:
1372 plyfile - pointer to PLY file to write out other elements for
1373 ******************************************************************************/
1374
ply_put_other_elements(PlyFile * plyfile)1375 void ply_put_other_elements (PlyFile *plyfile)
1376 {
1377 int i,j;
1378 OtherElem *other;
1379
1380 /* make sure we have other elements to write */
1381 if (plyfile->other_elems == NULL)
1382 return;
1383
1384 /* write out the data for each "other" element */
1385
1386 for (i = 0; i < plyfile->other_elems->num_elems; i++) {
1387
1388 other = &(plyfile->other_elems->other_list[i]);
1389 ply_put_element_setup (plyfile, other->elem_name);
1390
1391 /* write out each instance of the current element */
1392 for (j = 0; j < other->elem_count; j++)
1393 ply_put_element (plyfile, (void *) other->other_data[j]);
1394 }
1395 }
1396
1397
1398 /******************************************************************************
1399 Free up storage used by an "other" elements data structure.
1400
1401 Entry:
1402 other_elems - data structure to free up
1403 ******************************************************************************/
1404
ply_free_other_elements(PlyOtherElems * other_elems)1405 void ply_free_other_elements (PlyOtherElems *other_elems)
1406 {
1407 other_elems = other_elems;
1408 }
1409
1410
1411
1412 /*******************/
1413 /* Miscellaneous */
1414 /*******************/
1415
1416
1417
1418 /******************************************************************************
1419 Close a PLY file.
1420
1421 Entry:
1422 plyfile - identifier of file to close
1423 ******************************************************************************/
1424
ply_close(PlyFile * plyfile)1425 void ply_close(PlyFile *plyfile)
1426 {
1427 fclose (plyfile->fp);
1428
1429 /* free up memory associated with the PLY file */
1430 free (plyfile);
1431 }
1432
1433
1434 /******************************************************************************
1435 Get version number and file type of a PlyFile.
1436
1437 Entry:
1438 ply - pointer to PLY file
1439
1440 Exit:
1441 version - version of the file
1442 file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
1443 ******************************************************************************/
1444
ply_get_info(PlyFile * ply,float * version,int * file_type)1445 void ply_get_info(PlyFile *ply, float *version, int *file_type)
1446 {
1447 if (ply == NULL)
1448 return;
1449
1450 *version = ply->version;
1451 *file_type = ply->file_type;
1452 }
1453
1454
1455 /******************************************************************************
1456 Compare two strings. Returns 1 if they are the same, 0 if not.
1457 ******************************************************************************/
1458
equal_strings(const char * s1,const char * s2)1459 int equal_strings(const char *s1, const char *s2)
1460 {
1461
1462 while (*s1 && *s2)
1463 if (*s1++ != *s2++)
1464 return (0);
1465
1466 if (*s1 != *s2)
1467 return (0);
1468 else
1469 return (1);
1470 }
1471
1472
1473 /******************************************************************************
1474 Find an element from the element list of a given PLY object.
1475
1476 Entry:
1477 plyfile - file id for PLY file
1478 element - name of element we're looking for
1479
1480 Exit:
1481 returns the element, or NULL if not found
1482 ******************************************************************************/
1483
find_element(PlyFile * plyfile,const char * element)1484 PlyElement *find_element(PlyFile *plyfile, const char *element)
1485 {
1486 int i;
1487
1488 for (i = 0; i < plyfile->nelems; i++)
1489 if (equal_strings (element, plyfile->elems[i]->name))
1490 return (plyfile->elems[i]);
1491
1492 return (NULL);
1493 }
1494
1495
1496 /******************************************************************************
1497 Find a property in the list of properties of a given element.
1498
1499 Entry:
1500 elem - pointer to element in which we want to find the property
1501 prop_name - name of property to find
1502
1503 Exit:
1504 index - index to position in list
1505 returns a pointer to the property, or NULL if not found
1506 ******************************************************************************/
1507
find_property(PlyElement * elem,const char * prop_name,int * index)1508 PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index)
1509 {
1510 int i;
1511
1512 for (i = 0; i < elem->nprops; i++)
1513 if (equal_strings (prop_name, elem->props[i]->name)) {
1514 *index = i;
1515 return (elem->props[i]);
1516 }
1517
1518 *index = -1;
1519 return (NULL);
1520 }
1521
1522
1523 /******************************************************************************
1524 Read an element from an ascii file.
1525
1526 Entry:
1527 plyfile - file identifier
1528 elem_ptr - pointer to element
1529 ******************************************************************************/
1530
ascii_get_element(PlyFile * plyfile,char * elem_ptr)1531 void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
1532 {
1533 int j,k;
1534 PlyElement *elem;
1535 PlyProperty *prop;
1536 char **words;
1537 int nwords;
1538 int which_word;
1539 char *elem_data,*item=NULL;
1540 char *item_ptr;
1541 int item_size;
1542 int int_val;
1543 unsigned int uint_val;
1544 double double_val;
1545 int list_count;
1546 int store_it;
1547 char **store_array;
1548 char *orig_line;
1549 char *other_data=NULL;
1550 int other_flag;
1551
1552 /* the kind of element we're reading currently */
1553 elem = plyfile->which_elem;
1554
1555 /* do we need to setup for other_props? */
1556
1557 if (elem->other_offset != NO_OTHER_PROPS) {
1558 char **ptr;
1559 other_flag = 1;
1560 /* make room for other_props */
1561 other_data = (char *) myalloc (elem->other_size);
1562 /* store pointer in user's structure to the other_props */
1563 ptr = (char **) (elem_ptr + elem->other_offset);
1564 *ptr = other_data;
1565 }
1566 else
1567 other_flag = 0;
1568
1569 /* read in the element */
1570
1571 words = get_words (plyfile->fp, &nwords, &orig_line);
1572 if (words == NULL) {
1573 fprintf (stderr, "ply_get_element: unexpected end of file\n");
1574 exit (-1);
1575 }
1576
1577 which_word = 0;
1578
1579 for (j = 0; j < elem->nprops; j++) {
1580
1581 prop = elem->props[j];
1582 store_it = (elem->store_prop[j] | other_flag);
1583
1584 /* store either in the user's structure or in other_props */
1585 if (elem->store_prop[j])
1586 elem_data = elem_ptr;
1587 else
1588 elem_data = other_data;
1589
1590 if (prop->is_list) { /* a list */
1591
1592 /* get and store the number of items in the list */
1593 get_ascii_item (words[which_word++], prop->count_external,
1594 &int_val, &uint_val, &double_val);
1595 if (store_it) {
1596 item = elem_data + prop->count_offset;
1597 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1598 }
1599
1600 /* allocate space for an array of items and store a ptr to the array */
1601 list_count = int_val;
1602 item_size = ply_type_size[prop->internal_type];
1603 store_array = (char **) (elem_data + prop->offset);
1604
1605 if (list_count == 0) {
1606 if (store_it)
1607 *store_array = NULL;
1608 }
1609 else {
1610 if (store_it) {
1611 item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1612 item = item_ptr;
1613 *store_array = item_ptr;
1614 }
1615
1616 /* read items and store them into the array */
1617 for (k = 0; k < list_count; k++) {
1618 get_ascii_item (words[which_word++], prop->external_type,
1619 &int_val, &uint_val, &double_val);
1620 if (store_it) {
1621 store_item (item, prop->internal_type,
1622 int_val, uint_val, double_val);
1623 item += item_size;
1624 }
1625 }
1626 }
1627
1628 }
1629 else { /* not a list */
1630 get_ascii_item (words[which_word++], prop->external_type,
1631 &int_val, &uint_val, &double_val);
1632 if (store_it) {
1633 item = elem_data + prop->offset;
1634 store_item (item, prop->internal_type, int_val, uint_val, double_val);
1635 }
1636 }
1637
1638 }
1639
1640 free (words);
1641 }
1642
1643
1644 /******************************************************************************
1645 Read an element from a binary file.
1646
1647 Entry:
1648 plyfile - file identifier
1649 elem_ptr - pointer to an element
1650 ******************************************************************************/
1651
binary_get_element(PlyFile * plyfile,char * elem_ptr)1652 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
1653 {
1654 int j,k;
1655 PlyElement *elem;
1656 PlyProperty *prop;
1657 FILE *fp = plyfile->fp;
1658 char *elem_data,*item=NULL;
1659 char *item_ptr;
1660 int item_size;
1661 int int_val;
1662 unsigned int uint_val;
1663 double double_val;
1664 int list_count;
1665 int store_it;
1666 char **store_array;
1667 char *other_data=NULL;
1668 int other_flag;
1669
1670 /* the kind of element we're reading currently */
1671 elem = plyfile->which_elem;
1672
1673 /* do we need to setup for other_props? */
1674
1675 if (elem->other_offset != NO_OTHER_PROPS) {
1676 char **ptr;
1677 other_flag = 1;
1678 /* make room for other_props */
1679 other_data = (char *) myalloc (elem->other_size);
1680 /* store pointer in user's structure to the other_props */
1681 ptr = (char **) (elem_ptr + elem->other_offset);
1682 *ptr = other_data;
1683 }
1684 else
1685 other_flag = 0;
1686
1687 /* read in a number of elements */
1688
1689 for (j = 0; j < elem->nprops; j++) {
1690
1691 prop = elem->props[j];
1692 store_it = (elem->store_prop[j] | other_flag);
1693
1694 /* store either in the user's structure or in other_props */
1695 if (elem->store_prop[j])
1696 elem_data = elem_ptr;
1697 else
1698 elem_data = other_data;
1699
1700 if (prop->is_list) { /* a list */
1701
1702 /* get and store the number of items in the list */
1703 get_binary_item (fp, plyfile->file_type, prop->count_external,
1704 &int_val, &uint_val, &double_val);
1705 if (store_it) {
1706 item = elem_data + prop->count_offset;
1707 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1708 }
1709
1710 /* allocate space for an array of items and store a ptr to the array */
1711 list_count = int_val;
1712 item_size = ply_type_size[prop->internal_type];
1713 store_array = (char **) (elem_data + prop->offset);
1714 if (list_count == 0) {
1715 if (store_it)
1716 *store_array = NULL;
1717 }
1718 else {
1719 if (store_it) {
1720 item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1721 item = item_ptr;
1722 *store_array = item_ptr;
1723 }
1724
1725 /* read items and store them into the array */
1726 for (k = 0; k < list_count; k++) {
1727 get_binary_item (fp, plyfile->file_type, prop->external_type,
1728 &int_val, &uint_val, &double_val);
1729 if (store_it) {
1730 store_item (item, prop->internal_type,
1731 int_val, uint_val, double_val);
1732 item += item_size;
1733 }
1734 }
1735 }
1736
1737 }
1738 else { /* not a list */
1739 get_binary_item (fp, plyfile->file_type, prop->external_type,
1740 &int_val, &uint_val, &double_val);
1741 if (store_it) {
1742 item = elem_data + prop->offset;
1743 store_item (item, prop->internal_type, int_val, uint_val, double_val);
1744 }
1745 }
1746
1747 }
1748 }
1749
1750
1751 /******************************************************************************
1752 Write to a file the word that represents a PLY data type.
1753
1754 Entry:
1755 fp - file pointer
1756 code - code for type
1757 ******************************************************************************/
1758
write_scalar_type(FILE * fp,int code)1759 void write_scalar_type (FILE *fp, int code)
1760 {
1761 /* make sure this is a valid code */
1762
1763 if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
1764 fprintf (stderr, "write_scalar_type: bad data code = %d\n", code);
1765 exit (-1);
1766 }
1767
1768 /* write the code to a file */
1769
1770 fprintf (fp, "%s", type_names[code]);
1771 }
1772
1773 /******************************************************************************
1774 Reverse the order in an array of bytes. This is the conversion from big
1775 endian to little endian and vice versa
1776
1777 Entry:
1778 bytes - array of bytes to reverse (in place)
1779 num_bytes - number of bytes in array
1780 ******************************************************************************/
1781
swap_bytes(char * bytes,int num_bytes)1782 void swap_bytes(char *bytes, int num_bytes)
1783 {
1784 int i;
1785 char temp;
1786
1787 for (i=0; i < num_bytes/2; i++)
1788 {
1789 temp = bytes[i];
1790 bytes[i] = bytes[(num_bytes-1)-i];
1791 bytes[(num_bytes-1)-i] = temp;
1792 }
1793 }
1794
1795 /******************************************************************************
1796 Find out if this machine is big endian or little endian
1797
1798 Exit:
1799 set global variable, native_binary_type =
1800 either PLY_BINARY_BE or PLY_BINARY_LE
1801
1802 ******************************************************************************/
1803
get_native_binary_type()1804 void get_native_binary_type()
1805 {
1806 endian_test_type test;
1807
1808 test.int_value = 0;
1809 test.int_value = 1;
1810 if (test.byte_values[0] == 1)
1811 native_binary_type = PLY_BINARY_LE;
1812 else if (test.byte_values[sizeof(int)-1] == 1)
1813 native_binary_type = PLY_BINARY_BE;
1814 else
1815 {
1816 fprintf(stderr, "ply: Couldn't determine machine endianness.\n");
1817 fprintf(stderr, "ply: Exiting...\n");
1818 exit(1);
1819 }
1820 }
1821
1822 /******************************************************************************
1823 Verify that all the native types are the sizes we need
1824
1825
1826 ******************************************************************************/
1827
check_types()1828 void check_types()
1829 {
1830 if ((ply_type_size[PLY_CHAR] != sizeof(char)) ||
1831 (ply_type_size[PLY_SHORT] != sizeof(short)) ||
1832 (ply_type_size[PLY_INT] != sizeof(int)) ||
1833 (ply_type_size[PLY_UCHAR] != sizeof(unsigned char)) ||
1834 (ply_type_size[PLY_USHORT] != sizeof(unsigned short)) ||
1835 (ply_type_size[PLY_UINT] != sizeof(unsigned int)) ||
1836 (ply_type_size[PLY_FLOAT] != sizeof(float)) ||
1837 (ply_type_size[PLY_DOUBLE] != sizeof(double)))
1838 {
1839 fprintf(stderr, "ply: Type sizes do not match built-in types\n");
1840 fprintf(stderr, "ply: Exiting...\n");
1841 exit(1);
1842 }
1843
1844 types_checked = 1;
1845 }
1846
1847 /******************************************************************************
1848 Get a text line from a file and break it up into words.
1849
1850 IMPORTANT: The calling routine call "free" on the returned pointer once
1851 finished with it.
1852
1853 Entry:
1854 fp - file to read from
1855
1856 Exit:
1857 nwords - number of words returned
1858 orig_line - the original line of characters
1859 returns a list of words from the line, or NULL if end-of-file
1860 ******************************************************************************/
1861
get_words(FILE * fp,int * nwords,char ** orig_line)1862 char **get_words(FILE *fp, int *nwords, char **orig_line)
1863 {
1864 #define BIG_STRING 4096
1865 static char str[BIG_STRING];
1866 static char str_copy[BIG_STRING];
1867 char **words;
1868 int max_words = 10;
1869 int num_words = 0;
1870 char *ptr,*ptr2;
1871 char *result;
1872
1873 words = (char **) myalloc (sizeof (char *) * max_words);
1874
1875 /* read in a line */
1876 result = fgets (str, BIG_STRING, fp);
1877 if (result == NULL) {
1878 free(words);
1879 *nwords = 0;
1880 *orig_line = NULL;
1881 return (NULL);
1882 }
1883 /* convert line-feed and tabs into spaces */
1884 /* (this guarentees that there will be a space before the */
1885 /* null character at the end of the string) */
1886
1887 str[BIG_STRING-2] = ' ';
1888 str[BIG_STRING-1] = '\0';
1889
1890 for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
1891 *ptr2 = *ptr;
1892 // Added line here to manage carriage returns
1893 if (*ptr == '\t' || *ptr == '\r') {
1894 *ptr = ' ';
1895 *ptr2 = ' ';
1896 }
1897 else if (*ptr == '\n') {
1898 *ptr = ' ';
1899 *ptr2 = '\0';
1900 break;
1901 }
1902 }
1903
1904 /* find the words in the line */
1905
1906 ptr = str;
1907 while (*ptr != '\0') {
1908
1909 /* jump over leading spaces */
1910 while (*ptr == ' ')
1911 ptr++;
1912
1913 /* break if we reach the end */
1914 if (*ptr == '\0')
1915 break;
1916
1917 /* save pointer to beginning of word */
1918 if (num_words >= max_words) {
1919 max_words += 10;
1920 words = (char **) realloc (words, sizeof (char *) * max_words);
1921 }
1922 words[num_words++] = ptr;
1923
1924 /* jump over non-spaces */
1925 while (*ptr != ' ')
1926 ptr++;
1927
1928 /* place a null character here to mark the end of the word */
1929 *ptr++ = '\0';
1930 }
1931
1932 /* return the list of words */
1933 *nwords = num_words;
1934 *orig_line = str_copy;
1935 return (words);
1936 }
1937
1938
1939 /******************************************************************************
1940 Return the value of an item, given a pointer to it and its type.
1941
1942 Entry:
1943 item - pointer to item
1944 type - data type that "item" points to
1945
1946 Exit:
1947 returns a double-precision float that contains the value of the item
1948 ******************************************************************************/
1949
get_item_value(char * item,int type)1950 double get_item_value(char *item, int type)
1951 {
1952 unsigned char *puchar;
1953 char *pchar;
1954 short int *pshort;
1955 unsigned short int *pushort;
1956 int *pint;
1957 unsigned int *puint;
1958 float *pfloat;
1959 double *pdouble;
1960 int int_value;
1961 unsigned int uint_value;
1962 double double_value;
1963
1964 switch (type) {
1965 case PLY_CHAR:
1966 case PLY_INT_8:
1967 pchar = (char *) item;
1968 int_value = *pchar;
1969 return ((double) int_value);
1970 case PLY_UCHAR:
1971 case PLY_UINT_8:
1972 puchar = (unsigned char *) item;
1973 int_value = *puchar;
1974 return ((double) int_value);
1975 case PLY_SHORT:
1976 case PLY_INT_16:
1977 pshort = (short int *) item;
1978 int_value = *pshort;
1979 return ((double) int_value);
1980 case PLY_USHORT:
1981 case PLY_UINT_16:
1982 pushort = (unsigned short int *) item;
1983 int_value = *pushort;
1984 return ((double) int_value);
1985 case PLY_INT:
1986 case PLY_INT_32:
1987 pint = (int *) item;
1988 int_value = *pint;
1989 return ((double) int_value);
1990 case PLY_UINT:
1991 case PLY_UINT_32:
1992 puint = (unsigned int *) item;
1993 uint_value = *puint;
1994 return ((double) uint_value);
1995 case PLY_FLOAT:
1996 case PLY_FLOAT_32:
1997 pfloat = (float *) item;
1998 double_value = *pfloat;
1999 return (double_value);
2000 case PLY_DOUBLE:
2001 case PLY_FLOAT_64:
2002 pdouble = (double *) item;
2003 double_value = *pdouble;
2004 return (double_value);
2005 default:
2006 fprintf (stderr, "get_item_value: bad type = %d\n", type);
2007 exit (-1);
2008 }
2009 }
2010
2011
2012 /******************************************************************************
2013 Write out an item to a file as raw binary bytes.
2014
2015 Entry:
2016 fp - file to write to
2017 int_val - integer version of item
2018 uint_val - unsigned integer version of item
2019 double_val - double-precision float version of item
2020 type - data type to write out
2021 ******************************************************************************/
2022
write_binary_item(FILE * fp,int file_type,int int_val,unsigned int uint_val,double double_val,int type)2023 void write_binary_item(
2024 FILE *fp,
2025 int file_type,
2026 int int_val,
2027 unsigned int uint_val,
2028 double double_val,
2029 int type
2030 )
2031 {
2032 unsigned char uchar_val;
2033 char char_val;
2034 unsigned short ushort_val;
2035 short short_val;
2036 float float_val;
2037 void *value;
2038
2039 switch (type) {
2040 case PLY_CHAR:
2041 case PLY_INT_8:
2042 char_val = char(int_val);
2043 value = &char_val;
2044 break;
2045 case PLY_SHORT:
2046 case PLY_INT_16:
2047 short_val = short(int_val);
2048 value = &short_val;
2049 break;
2050 case PLY_INT:
2051 case PLY_INT_32:
2052 value = &int_val;
2053 break;
2054 case PLY_UCHAR:
2055 case PLY_UINT_8:
2056 uchar_val = (unsigned char)(uint_val);
2057 value = &uchar_val;
2058 break;
2059 case PLY_USHORT:
2060 case PLY_UINT_16:
2061 ushort_val = (unsigned short)(uint_val);
2062 value = &ushort_val;
2063 break;
2064 case PLY_UINT:
2065 case PLY_UINT_32:
2066 value = &uint_val;
2067 break;
2068 case PLY_FLOAT:
2069 case PLY_FLOAT_32:
2070 float_val = (float)double_val;
2071 value = &float_val;
2072 break;
2073 case PLY_DOUBLE:
2074 case PLY_FLOAT_64:
2075 value = &double_val;
2076 break;
2077 default:
2078 fprintf (stderr, "write_binary_item: bad type = %d\n", type);
2079 exit (-1);
2080 }
2081
2082
2083 if ((file_type != native_binary_type) && (ply_type_size[type] > 1))
2084 swap_bytes((char *)value, ply_type_size[type]);
2085
2086 if (fwrite (value, ply_type_size[type], 1, fp) != 1)
2087 {
2088 fprintf(stderr, "PLY ERROR: fwrite() failed -- aborting.\n");
2089 exit(1);
2090 }
2091 }
2092
2093
2094 /******************************************************************************
2095 Write out an item to a file as ascii characters.
2096
2097 Entry:
2098 fp - file to write to
2099 int_val - integer version of item
2100 uint_val - unsigned integer version of item
2101 double_val - double-precision float version of item
2102 type - data type to write out
2103 ******************************************************************************/
2104
write_ascii_item(FILE * fp,int int_val,unsigned int uint_val,double double_val,int type)2105 void write_ascii_item(
2106 FILE *fp,
2107 int int_val,
2108 unsigned int uint_val,
2109 double double_val,
2110 int type
2111 )
2112 {
2113 switch (type) {
2114 case PLY_CHAR:
2115 case PLY_INT_8:
2116 case PLY_SHORT:
2117 case PLY_INT_16:
2118 case PLY_INT:
2119 case PLY_INT_32:
2120 if (fprintf (fp, "%d ", int_val) <= 0)
2121 {
2122 fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
2123 exit(1);
2124 }
2125 break;
2126 case PLY_UCHAR:
2127 case PLY_UINT_8:
2128 case PLY_USHORT:
2129 case PLY_UINT_16:
2130 case PLY_UINT:
2131 case PLY_UINT_32:
2132
2133 if (fprintf (fp, "%u ", uint_val) <= 0)
2134 {
2135 fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
2136 exit(1);
2137 }
2138 break;
2139 case PLY_FLOAT:
2140 case PLY_FLOAT_32:
2141 case PLY_DOUBLE:
2142 case PLY_FLOAT_64:
2143 if (fprintf (fp, "%g ", double_val) <= 0)
2144 {
2145 fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
2146 exit(1);
2147 }
2148 break;
2149 default:
2150 fprintf (stderr, "write_ascii_item: bad type = %d\n", type);
2151 exit (-1);
2152 }
2153 }
2154
2155
2156 /******************************************************************************
2157 Write out an item to a file as ascii characters.
2158
2159 Entry:
2160 fp - file to write to
2161 item - pointer to item to write
2162 type - data type that "item" points to
2163
2164 Exit:
2165 returns a double-precision float that contains the value of the written item
2166 ******************************************************************************/
2167
old_write_ascii_item(FILE * fp,char * item,int type)2168 double old_write_ascii_item(FILE *fp, char *item, int type)
2169 {
2170 unsigned char *puchar;
2171 char *pchar;
2172 short int *pshort;
2173 unsigned short int *pushort;
2174 int *pint;
2175 unsigned int *puint;
2176 float *pfloat;
2177 double *pdouble;
2178 int int_value;
2179 unsigned int uint_value;
2180 double double_value;
2181
2182 switch (type) {
2183 case PLY_CHAR:
2184 case PLY_INT_8:
2185 pchar = (char *) item;
2186 int_value = *pchar;
2187 fprintf (fp, "%d ", int_value);
2188 return ((double) int_value);
2189 case PLY_UCHAR:
2190 case PLY_UINT_8:
2191 puchar = (unsigned char *) item;
2192 int_value = *puchar;
2193 fprintf (fp, "%d ", int_value);
2194 return ((double) int_value);
2195 case PLY_SHORT:
2196 case PLY_INT_16:
2197 pshort = (short int *) item;
2198 int_value = *pshort;
2199 fprintf (fp, "%d ", int_value);
2200 return ((double) int_value);
2201 case PLY_USHORT:
2202 case PLY_UINT_16:
2203 pushort = (unsigned short int *) item;
2204 int_value = *pushort;
2205 fprintf (fp, "%d ", int_value);
2206 return ((double) int_value);
2207 case PLY_INT:
2208 case PLY_INT_32:
2209 pint = (int *) item;
2210 int_value = *pint;
2211 fprintf (fp, "%d ", int_value);
2212 return ((double) int_value);
2213 case PLY_UINT:
2214 case PLY_UINT_32:
2215 puint = (unsigned int *) item;
2216 uint_value = *puint;
2217 fprintf (fp, "%u ", uint_value);
2218 return ((double) uint_value);
2219 case PLY_FLOAT:
2220 case PLY_FLOAT_32:
2221 pfloat = (float *) item;
2222 double_value = *pfloat;
2223 fprintf (fp, "%g ", double_value);
2224 return (double_value);
2225 case PLY_DOUBLE:
2226 case PLY_FLOAT_64:
2227 pdouble = (double *) item;
2228 double_value = *pdouble;
2229 fprintf (fp, "%g ", double_value);
2230 return (double_value);
2231 default:
2232 fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type);
2233 exit (-1);
2234 }
2235 }
2236
2237
2238 /******************************************************************************
2239 Get the value of an item that is in memory, and place the result
2240 into an integer, an unsigned integer and a double.
2241
2242 Entry:
2243 ptr - pointer to the item
2244 type - data type supposedly in the item
2245
2246 Exit:
2247 int_val - integer value
2248 uint_val - unsigned integer value
2249 double_val - double-precision floating point value
2250 ******************************************************************************/
2251
get_stored_item(void * ptr,int type,int * int_val,unsigned int * uint_val,double * double_val)2252 void get_stored_item(
2253 void *ptr,
2254 int type,
2255 int *int_val,
2256 unsigned int *uint_val,
2257 double *double_val
2258 )
2259 {
2260 switch (type) {
2261 case PLY_CHAR:
2262 case PLY_INT_8:
2263 *int_val = *((char *) ptr);
2264 *uint_val = *int_val;
2265 *double_val = *int_val;
2266 break;
2267 case PLY_UCHAR:
2268 case PLY_UINT_8:
2269 *uint_val = *((unsigned char *) ptr);
2270 *int_val = *uint_val;
2271 *double_val = *uint_val;
2272 break;
2273 case PLY_SHORT:
2274 case PLY_INT_16:
2275 *int_val = *((short int *) ptr);
2276 *uint_val = *int_val;
2277 *double_val = *int_val;
2278 break;
2279 case PLY_USHORT:
2280 case PLY_UINT_16:
2281 *uint_val = *((unsigned short int *) ptr);
2282 *int_val = *uint_val;
2283 *double_val = *uint_val;
2284 break;
2285 case PLY_INT:
2286 case PLY_INT_32:
2287 *int_val = *((int *) ptr);
2288 *uint_val = *int_val;
2289 *double_val = *int_val;
2290 break;
2291 case PLY_UINT:
2292 case PLY_UINT_32:
2293 *uint_val = *((unsigned int *) ptr);
2294 *int_val = *uint_val;
2295 *double_val = *uint_val;
2296 break;
2297 case PLY_FLOAT:
2298 case PLY_FLOAT_32:
2299 *double_val = *((float *) ptr);
2300 *int_val = (int) *double_val;
2301 *uint_val = (unsigned int) *double_val;
2302 break;
2303 case PLY_DOUBLE:
2304 case PLY_FLOAT_64:
2305 *double_val = *((double *) ptr);
2306 *int_val = (int) *double_val;
2307 *uint_val = (unsigned int) *double_val;
2308 break;
2309 default:
2310 fprintf (stderr, "get_stored_item: bad type = %d\n", type);
2311 exit (-1);
2312 }
2313 }
2314
2315
2316 /******************************************************************************
2317 Get the value of an item from a binary file, and place the result
2318 into an integer, an unsigned integer and a double.
2319
2320 Entry:
2321 fp - file to get item from
2322 type - data type supposedly in the word
2323
2324 Exit:
2325 int_val - integer value
2326 uint_val - unsigned integer value
2327 double_val - double-precision floating point value
2328 ******************************************************************************/
2329
get_binary_item(FILE * fp,int file_type,int type,int * int_val,unsigned int * uint_val,double * double_val)2330 void get_binary_item(
2331 FILE *fp,
2332 int file_type,
2333 int type,
2334 int *int_val,
2335 unsigned int *uint_val,
2336 double *double_val
2337 )
2338 {
2339 char c[8];
2340 void *ptr;
2341
2342 ptr = (void *) c;
2343
2344 if (fread (ptr, ply_type_size[type], 1, fp) != 1)
2345 {
2346 fprintf(stderr, "PLY ERROR: fread() failed -- aborting.\n");
2347 exit(1);
2348 }
2349
2350
2351 if ((file_type != native_binary_type) && (ply_type_size[type] > 1))
2352 swap_bytes((char *)ptr, ply_type_size[type]);
2353
2354 switch (type) {
2355 case PLY_CHAR:
2356 case PLY_INT_8:
2357 *int_val = *((char *) ptr);
2358 *uint_val = *int_val;
2359 *double_val = *int_val;
2360 break;
2361 case PLY_UCHAR:
2362 case PLY_UINT_8:
2363 *uint_val = *((unsigned char *) ptr);
2364 *int_val = *uint_val;
2365 *double_val = *uint_val;
2366 break;
2367 case PLY_SHORT:
2368 case PLY_INT_16:
2369 *int_val = *((short int *) ptr);
2370 *uint_val = *int_val;
2371 *double_val = *int_val;
2372 break;
2373 case PLY_USHORT:
2374 case PLY_UINT_16:
2375 *uint_val = *((unsigned short int *) ptr);
2376 *int_val = *uint_val;
2377 *double_val = *uint_val;
2378 break;
2379 case PLY_INT:
2380 case PLY_INT_32:
2381 *int_val = *((int *) ptr);
2382 *uint_val = *int_val;
2383 *double_val = *int_val;
2384 break;
2385 case PLY_UINT:
2386 case PLY_UINT_32:
2387 *uint_val = *((unsigned int *) ptr);
2388 *int_val = *uint_val;
2389 *double_val = *uint_val;
2390 break;
2391 case PLY_FLOAT:
2392 case PLY_FLOAT_32:
2393 *double_val = *((float *) ptr);
2394 *int_val = (int) *double_val;
2395 *uint_val = (unsigned int) *double_val;
2396 break;
2397 case PLY_DOUBLE:
2398 case PLY_FLOAT_64:
2399 *double_val = *((double *) ptr);
2400 *int_val = (int) *double_val;
2401 *uint_val = (unsigned int) *double_val;
2402 break;
2403 default:
2404 fprintf (stderr, "get_binary_item: bad type = %d\n", type);
2405 exit (-1);
2406 }
2407 }
2408
2409
2410 /******************************************************************************
2411 Extract the value of an item from an ascii word, and place the result
2412 into an integer, an unsigned integer and a double.
2413
2414 Entry:
2415 word - word to extract value from
2416 type - data type supposedly in the word
2417
2418 Exit:
2419 int_val - integer value
2420 uint_val - unsigned integer value
2421 double_val - double-precision floating point value
2422 ******************************************************************************/
2423
get_ascii_item(char * word,int type,int * int_val,unsigned int * uint_val,double * double_val)2424 void get_ascii_item(
2425 char *word,
2426 int type,
2427 int *int_val,
2428 unsigned int *uint_val,
2429 double *double_val
2430 )
2431 {
2432 switch (type) {
2433 case PLY_CHAR:
2434 case PLY_INT_8:
2435 case PLY_UCHAR:
2436 case PLY_UINT_8:
2437 case PLY_SHORT:
2438 case PLY_INT_16:
2439 case PLY_USHORT:
2440 case PLY_UINT_16:
2441 case PLY_INT:
2442 case PLY_INT_32:
2443 *int_val = atoi (word);
2444 *uint_val = (unsigned int) *int_val;
2445 *double_val = (double) *int_val;
2446 break;
2447
2448 case PLY_UINT:
2449 case PLY_UINT_32:
2450 *uint_val = strtol (word, (char **) NULL, 10);
2451 *int_val = (int) *uint_val;
2452 *double_val = (double) *uint_val;
2453 break;
2454
2455 case PLY_FLOAT:
2456 case PLY_FLOAT_32:
2457 case PLY_DOUBLE:
2458 case PLY_FLOAT_64:
2459 *double_val = atof (word);
2460 *int_val = (int) *double_val;
2461 *uint_val = (unsigned int) *double_val;
2462 break;
2463
2464 default:
2465 fprintf (stderr, "get_ascii_item: bad type = %d\n", type);
2466 exit (-1);
2467 }
2468 }
2469
2470
2471 /******************************************************************************
2472 Store a value into a place being pointed to, guided by a data type.
2473
2474 Entry:
2475 item - place to store value
2476 type - data type
2477 int_val - integer version of value
2478 uint_val - unsigned integer version of value
2479 double_val - double version of value
2480
2481 Exit:
2482 item - pointer to stored value
2483 ******************************************************************************/
2484
store_item(char * item,int type,int int_val,unsigned int uint_val,double double_val)2485 void store_item (
2486 char *item,
2487 int type,
2488 int int_val,
2489 unsigned int uint_val,
2490 double double_val
2491 )
2492 {
2493 unsigned char *puchar;
2494 short int *pshort;
2495 unsigned short int *pushort;
2496 int *pint;
2497 unsigned int *puint;
2498 float *pfloat;
2499 double *pdouble;
2500
2501
2502 switch (type) {
2503 case PLY_CHAR:
2504 case PLY_INT_8:
2505 *item = char(int_val);
2506 break;
2507 case PLY_UCHAR:
2508 case PLY_UINT_8:
2509 puchar = (unsigned char *) item;
2510 *puchar = (unsigned char)(uint_val);
2511 break;
2512 case PLY_SHORT:
2513 case PLY_INT_16:
2514 pshort = (short *) item;
2515 *pshort = short(int_val);
2516 break;
2517 case PLY_USHORT:
2518 case PLY_UINT_16:
2519 pushort = (unsigned short *) item;
2520 *pushort = (unsigned short)(uint_val);
2521 break;
2522 case PLY_INT:
2523 case PLY_INT_32:
2524 pint = (int *) item;
2525 *pint = int_val;
2526 break;
2527 case PLY_UINT:
2528 case PLY_UINT_32:
2529 puint = (unsigned int *) item;
2530 *puint = uint_val;
2531 break;
2532 case PLY_FLOAT:
2533 case PLY_FLOAT_32:
2534 pfloat = (float *) item;
2535 *pfloat = (float)double_val;
2536 break;
2537 case PLY_DOUBLE:
2538 case PLY_FLOAT_64:
2539 pdouble = (double *) item;
2540 *pdouble = double_val;
2541 break;
2542 default:
2543 fprintf (stderr, "store_item: bad type = %d\n", type);
2544 exit (-1);
2545 }
2546 }
2547
2548
2549 /******************************************************************************
2550 Add an element to a PLY file descriptor.
2551
2552 Entry:
2553 plyfile - PLY file descriptor
2554 words - list of words describing the element
2555 nwords - number of words in the list
2556 ******************************************************************************/
2557
add_element(PlyFile * plyfile,char ** words)2558 void add_element (PlyFile *plyfile, char **words)
2559 {
2560 PlyElement *elem;
2561
2562 /* create the new element */
2563 elem = (PlyElement *) myalloc (sizeof (PlyElement));
2564 elem->name = _strdup (words[1]);
2565 elem->num = atoi (words[2]);
2566 elem->nprops = 0;
2567
2568 /* make room for new element in the object's list of elements */
2569 if (plyfile->nelems == 0)
2570 plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
2571 else
2572 plyfile->elems = (PlyElement **) realloc (plyfile->elems,
2573 sizeof (PlyElement *) * (plyfile->nelems + 1));
2574
2575 /* add the new element to the object's list */
2576 plyfile->elems[plyfile->nelems] = elem;
2577 plyfile->nelems++;
2578 }
2579
2580
2581 /******************************************************************************
2582 Return the type of a property, given the name of the property.
2583
2584 Entry:
2585 name - name of property type
2586
2587 Exit:
2588 returns integer code for property, or 0 if not found
2589 ******************************************************************************/
2590
get_prop_type(char * type_name)2591 int get_prop_type(char *type_name)
2592 {
2593 int i;
2594
2595 for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
2596 if (equal_strings (type_name, type_names[i]))
2597 return (i);
2598
2599 /* if we get here, we didn't find the type */
2600 return (0);
2601 }
2602
2603
2604 /******************************************************************************
2605 Add a property to a PLY file descriptor.
2606
2607 Entry:
2608 plyfile - PLY file descriptor
2609 words - list of words describing the property
2610 nwords - number of words in the list
2611 ******************************************************************************/
2612
add_property(PlyFile * plyfile,char ** words)2613 void add_property (PlyFile *plyfile, char **words)
2614 {
2615 PlyProperty *prop;
2616 PlyElement *elem;
2617
2618 /* create the new property */
2619
2620 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
2621
2622 if (equal_strings (words[1], "list")) { /* is a list */
2623 prop->count_external = get_prop_type (words[2]);
2624 prop->external_type = get_prop_type (words[3]);
2625 prop->name = _strdup (words[4]);
2626 prop->is_list = 1;
2627 }
2628 else { /* not a list */
2629 prop->external_type = get_prop_type (words[1]);
2630 prop->name = _strdup (words[2]);
2631 prop->is_list = 0;
2632 }
2633
2634 /* add this property to the list of properties of the current element */
2635
2636 elem = plyfile->elems[plyfile->nelems - 1];
2637
2638 if (elem->nprops == 0)
2639 elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
2640 else
2641 elem->props = (PlyProperty **) realloc (elem->props,
2642 sizeof (PlyProperty *) * (elem->nprops + 1));
2643
2644 elem->props[elem->nprops] = prop;
2645 elem->nprops++;
2646 }
2647
2648
2649 /******************************************************************************
2650 Add a comment to a PLY file descriptor.
2651
2652 Entry:
2653 plyfile - PLY file descriptor
2654 line - line containing comment
2655 ******************************************************************************/
2656
add_comment(PlyFile * plyfile,char * line)2657 void add_comment (PlyFile *plyfile, char *line)
2658 {
2659 int i;
2660
2661 /* skip over "comment" and leading spaces and tabs */
2662 i = 7;
2663 while (line[i] == ' ' || line[i] == '\t')
2664 i++;
2665
2666 ply_put_comment (plyfile, &line[i]);
2667 }
2668
2669
2670 /******************************************************************************
2671 Add a some object information to a PLY file descriptor.
2672
2673 Entry:
2674 plyfile - PLY file descriptor
2675 line - line containing text info
2676 ******************************************************************************/
2677
add_obj_info(PlyFile * plyfile,char * line)2678 void add_obj_info (PlyFile *plyfile, char *line)
2679 {
2680 int i;
2681
2682 /* skip over "obj_info" and leading spaces and tabs */
2683 i = 8;
2684 while (line[i] == ' ' || line[i] == '\t')
2685 i++;
2686
2687 ply_put_obj_info (plyfile, &line[i]);
2688 }
2689
2690
2691 /******************************************************************************
2692 Copy a property.
2693 ******************************************************************************/
2694
copy_property(PlyProperty * dest,PlyProperty * src)2695 void copy_property(PlyProperty *dest, PlyProperty *src)
2696 {
2697 dest->name = _strdup (src->name);
2698 dest->external_type = src->external_type;
2699 dest->internal_type = src->internal_type;
2700 dest->offset = src->offset;
2701
2702 dest->is_list = src->is_list;
2703 dest->count_external = src->count_external;
2704 dest->count_internal = src->count_internal;
2705 dest->count_offset = src->count_offset;
2706 }
2707
2708
2709 /******************************************************************************
2710 Allocate some memory.
2711
2712 Entry:
2713 size - amount of memory requested (in bytes)
2714 lnum - line number from which memory was requested
2715 fname - file name from which memory was requested
2716 ******************************************************************************/
2717
my_alloc(int size,int lnum,const char * fname)2718 char *my_alloc(int size, int lnum, const char *fname)
2719 {
2720 char *ptr;
2721
2722 ptr = (char *) malloc (size);
2723
2724 if (ptr == 0) {
2725 fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname);
2726 }
2727
2728 return (ptr);
2729 }
2730
2731