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