2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
31 The interface routines for reading and writing PLY polygon files.
33 Greg Turk, February 1994
35 ---------------------------------------------------------------
37 A PLY file contains a single polygonal _object_.
39 An object is composed of lists of _elements_. Typical elements are
40 vertices, faces, edges and materials.
42 Each type of element for a given object has one or more _properties_
43 associated with the element type. For instance, a vertex element may
44 have as properties the floating-point values x,y,z and the three unsigned
45 chars representing red, green and blue.
47 ---------------------------------------------------------------
49 Copyright (c) 1994 The Board of Trustees of The Leland Stanford
50 Junior University. All rights reserved.
52 Permission to use, copy, modify and distribute this software and its
53 documentation for any purpose is hereby granted without fee, provided
54 that the above copyright notice and this permission notice appear in
55 all copies of this software and that you do not sell the software.
57 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
58 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
59 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
69 char *type_names[] = {
71 "char", "short", "int",
72 "uchar", "ushort", "uint",
76 int ply_type_size[] = {
77 0, 1, 2, 4, 1, 2, 4, 4, 8
80 #define NO_OTHER_PROPS -1
82 #define DONT_STORE_PROP 0
89 /* returns 1 if strings are equal, 0 if not */
90 int equal_strings(char *, char *);
92 /* find an element in a plyfile's list */
93 PlyElement *find_element(PlyFile *, char *);
95 /* find a property in an element's list */
96 PlyProperty *find_property(PlyElement *, char *, int *);
98 /* write to a file the word describing a PLY file data type */
99 void write_scalar_type(FILE *, int);
101 /* read a line from a file and break it up into separate words */
102 char **get_words(FILE *, int *, char **);
103 char **old_get_words(FILE *, int *);
105 /* write an item to a file */
106 void write_binary_item(FILE *, int, unsigned int, double, int);
107 void write_ascii_item(FILE *, int, unsigned int, double, int);
108 double old_write_ascii_item(FILE *, char *, int);
110 /* add information to a PLY file descriptor */
111 void add_element(PlyFile *, char **);
112 void add_property(PlyFile *, char **);
113 void add_comment(PlyFile *, char *);
114 void add_obj_info(PlyFile *, char *);
116 /* copy a property */
117 void copy_property(PlyProperty *, PlyProperty *);
119 /* store a value into where a pointer and a type specify */
120 void store_item(char *, int, int, unsigned int, double);
122 /* return the value of a stored item */
123 void get_stored_item(void *, int, int *, unsigned int *, double *);
125 /* return the value stored in an item, given ptr to it and its type */
126 double get_item_value(char *, int);
128 /* get binary or ascii item and store it according to ptr and type */
129 void get_ascii_item(char *, int, int *, unsigned int *, double *);
130 void get_binary_item(FILE *, int, int *, unsigned int *, double *);
132 /* get a bunch of elements from a file */
133 void ascii_get_element(PlyFile *, char *);
134 void binary_get_element(PlyFile *, char *);
136 /* memory allocation */
137 char *my_alloc(int, int, char *);
145 /******************************************************************************
146 Given a file pointer, get ready to write PLY data to the file.
149 fp - the given file pointer
150 nelems - number of elements in object
151 elem_names - list of element names
152 file_type - file type, either ascii or binary
155 returns a pointer to a PlyFile, used to refer to this file, or NULL if error
156 ******************************************************************************/
169 /* check for NULL file pointer */
173 /* create a record for this object */
175 plyfile = (PlyFile *) myalloc(sizeof(PlyFile));
176 plyfile->file_type = file_type;
177 plyfile->num_comments = 0;
178 plyfile->num_obj_info = 0;
179 plyfile->nelems = nelems;
180 plyfile->version = 1.0;
182 plyfile->other_elems = NULL;
184 /* tuck aside the names of the elements */
186 plyfile->elems = (PlyElement **) myalloc(sizeof(PlyElement *) * nelems);
187 for (i = 0; i < nelems; i++) {
188 elem = (PlyElement *) myalloc(sizeof(PlyElement));
189 plyfile->elems[i] = elem;
190 elem->name = strdup(elem_names[i]);
195 /* return pointer to the file descriptor */
200 /******************************************************************************
201 Open a polygon file for writing.
204 filename - name of file to read from
205 nelems - number of elements in object
206 elem_names - list of element names
207 file_type - file type, either ascii or binary
210 version - version number of PLY file
211 returns a file identifier, used to refer to this file, or NULL if error
212 ******************************************************************************/
214 PlyFile *ply_open_for_writing(
226 /* tack on the extension .ply, if necessary */
228 name = (char *) myalloc(sizeof(char) * (strlen(filename) + 5));
229 strcpy(name, filename);
230 if (strlen(name) < 4 ||
231 strcmp(name + strlen(name) - 4, ".ply") != 0)
232 strcat(name, ".ply");
234 /* open the file for writing */
236 fp = fopen(name, "w");
241 /* create the actual PlyFile structure */
243 plyfile = ply_write(fp, nelems, elem_names, file_type);
247 /* say what PLY file version number we're writing */
248 *version = plyfile->version;
250 /* return pointer to the file descriptor */
255 /******************************************************************************
256 Describe an element, including its properties and how many will be written
260 plyfile - file identifier
261 elem_name - name of element that information is being specified about
262 nelems - number of elements of this type to be written
263 nprops - number of properties contained in the element
264 prop_list - list of properties
265 ******************************************************************************/
267 void ply_describe_element(
272 PlyProperty *prop_list
279 /* look for appropriate element */
280 elem = find_element(plyfile, elem_name);
282 fprintf(stderr, "ply_describe_element: can't find element '%s'\n", elem_name);
288 /* copy the list of properties */
290 elem->nprops = nprops;
291 elem->props = (PlyProperty **) myalloc(sizeof(PlyProperty *) * nprops);
292 elem->store_prop = (char *) myalloc(sizeof(char) * nprops);
294 for (i = 0; i < nprops; i++) {
295 prop = (PlyProperty *) myalloc(sizeof(PlyProperty));
296 elem->props[i] = prop;
297 elem->store_prop[i] = NAMED_PROP;
298 copy_property(prop, &prop_list[i]);
303 /******************************************************************************
304 Describe a property of an element.
307 plyfile - file identifier
308 elem_name - name of element that information is being specified about
309 prop - the new property
310 ******************************************************************************/
312 void ply_describe_property(
319 PlyProperty *elem_prop;
321 /* look for appropriate element */
322 elem = find_element(plyfile, elem_name);
324 fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
329 /* create room for new property */
331 if (elem->nprops == 0) {
332 elem->props = (PlyProperty **) myalloc(sizeof(PlyProperty *));
333 elem->store_prop = (char *) myalloc(sizeof(char));
338 elem->props = (PlyProperty **)
339 realloc(elem->props, sizeof(PlyProperty *) * elem->nprops);
340 elem->store_prop = (char *)
341 realloc(elem->store_prop, sizeof(char) * elem->nprops);
344 /* copy the new property */
346 elem_prop = (PlyProperty *) myalloc(sizeof(PlyProperty));
347 elem->props[elem->nprops - 1] = elem_prop;
348 elem->store_prop[elem->nprops - 1] = NAMED_PROP;
349 copy_property(elem_prop, prop);
353 /******************************************************************************
354 Describe what the "other" properties are that are to be stored, and where
355 they are in an element.
356 ******************************************************************************/
358 void ply_describe_other_properties(
368 /* look for appropriate element */
369 elem = find_element(plyfile, other->name);
371 fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n",
376 /* create room for other properties */
378 if (elem->nprops == 0) {
379 elem->props = (PlyProperty **)
380 myalloc(sizeof(PlyProperty *) * other->nprops);
381 elem->store_prop = (char *) myalloc(sizeof(char) * other->nprops);
386 newsize = elem->nprops + other->nprops;
387 elem->props = (PlyProperty **)
388 realloc(elem->props, sizeof(PlyProperty *) * newsize);
389 elem->store_prop = (char *)
390 realloc(elem->store_prop, sizeof(char) * newsize);
393 /* copy the other properties */
395 for (i = 0; i < other->nprops; i++) {
396 prop = (PlyProperty *) myalloc(sizeof(PlyProperty));
397 copy_property(prop, other->props[i]);
398 elem->props[elem->nprops] = prop;
399 elem->store_prop[elem->nprops] = OTHER_PROP;
403 /* save other info about other properties */
404 elem->other_size = other->size;
405 elem->other_offset = offset;
409 /******************************************************************************
410 State how many of a given element will be written.
413 plyfile - file identifier
414 elem_name - name of element that information is being specified about
415 nelems - number of elements of this type to be written
416 ******************************************************************************/
418 void ply_element_count(
426 /* look for appropriate element */
427 elem = find_element(plyfile, elem_name);
429 fprintf(stderr, "ply_element_count: can't find element '%s'\n", elem_name);
437 /******************************************************************************
438 Signal that we've described everything a PLY file's header and that the
439 header should be written to the file.
442 plyfile - file identifier
443 ******************************************************************************/
445 void ply_header_complete(PlyFile *plyfile)
448 FILE *fp = plyfile->fp;
452 fprintf(fp, "ply\n");
454 switch (plyfile->file_type) {
456 fprintf(fp, "format ascii 1.0\n");
459 fprintf(fp, "format binary_big_endian 1.0\n");
462 fprintf(fp, "format binary_little_endian 1.0\n");
465 fprintf(stderr, "ply_header_complete: bad file type = %d\n",
470 /* write out the comments */
472 for (i = 0; i < plyfile->num_comments; i++)
473 fprintf(fp, "comment %s\n", plyfile->comments[i]);
475 /* write out object information */
477 for (i = 0; i < plyfile->num_obj_info; i++)
478 fprintf(fp, "obj_info %s\n", plyfile->obj_info[i]);
480 /* write out information about each element */
482 for (i = 0; i < plyfile->nelems; i++) {
484 elem = plyfile->elems[i];
485 fprintf(fp, "element %s %d\n", elem->name, elem->num);
487 /* write out each property */
488 for (j = 0; j < elem->nprops; j++) {
489 prop = elem->props[j];
491 fprintf(fp, "property list ");
492 write_scalar_type(fp, prop->count_external);
494 write_scalar_type(fp, prop->external_type);
495 fprintf(fp, " %s\n", prop->name);
498 fprintf(fp, "property ");
499 write_scalar_type(fp, prop->external_type);
500 fprintf(fp, " %s\n", prop->name);
505 fprintf(fp, "end_header\n");
509 /******************************************************************************
510 Specify which elements are going to be written. This should be called
511 before a call to the routine ply_put_element().
514 plyfile - file identifier
515 elem_name - name of element we're talking about
516 ******************************************************************************/
518 void ply_put_element_setup(PlyFile *plyfile, char *elem_name)
522 elem = find_element(plyfile, elem_name);
524 fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name);
528 plyfile->which_elem = elem;
532 /******************************************************************************
533 Write an element to the file. This routine assumes that we're
534 writing the type of element specified in the last call to the routine
535 ply_put_element_setup().
538 plyfile - file identifier
539 elem_ptr - pointer to the element
540 ******************************************************************************/
542 void ply_put_element(PlyFile *plyfile, void *elem_ptr)
545 FILE *fp = plyfile->fp;
548 char *elem_data, *item;
553 unsigned int uint_val;
557 elem = plyfile->which_elem;
558 elem_data = elem_ptr;
559 other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
561 /* write out either to an ascii or binary file */
563 if (plyfile->file_type == PLY_ASCII) {
565 /* write an ascii file */
567 /* write out each property of the element */
568 for (j = 0; j < elem->nprops; j++) {
569 prop = elem->props[j];
570 if (elem->store_prop[j] == OTHER_PROP)
571 elem_data = *other_ptr;
573 elem_data = elem_ptr;
575 item = elem_data + prop->count_offset;
576 get_stored_item((void *) item, prop->count_internal,
577 &int_val, &uint_val, &double_val);
578 write_ascii_item(fp, int_val, uint_val, double_val,
579 prop->count_external);
580 list_count = uint_val;
581 item_ptr = (char **) (elem_data + prop->offset);
583 item_size = ply_type_size[prop->internal_type];
584 for (k = 0; k < list_count; k++) {
585 get_stored_item((void *) item, prop->internal_type,
586 &int_val, &uint_val, &double_val);
587 write_ascii_item(fp, int_val, uint_val, double_val,
588 prop->external_type);
593 item = elem_data + prop->offset;
594 get_stored_item((void *) item, prop->internal_type,
595 &int_val, &uint_val, &double_val);
596 write_ascii_item(fp, int_val, uint_val, double_val,
597 prop->external_type);
605 /* write a binary file */
607 /* write out each property of the element */
608 for (j = 0; j < elem->nprops; j++) {
609 prop = elem->props[j];
610 if (elem->store_prop[j] == OTHER_PROP)
611 elem_data = *other_ptr;
613 elem_data = elem_ptr;
615 item = elem_data + prop->count_offset;
616 item_size = ply_type_size[prop->count_internal];
617 get_stored_item((void *) item, prop->count_internal,
618 &int_val, &uint_val, &double_val);
619 write_binary_item(fp, int_val, uint_val, double_val,
620 prop->count_external);
621 list_count = uint_val;
622 item_ptr = (char **) (elem_data + prop->offset);
624 item_size = ply_type_size[prop->internal_type];
625 for (k = 0; k < list_count; k++) {
626 get_stored_item((void *) item, prop->internal_type,
627 &int_val, &uint_val, &double_val);
628 write_binary_item(fp, int_val, uint_val, double_val,
629 prop->external_type);
634 item = elem_data + prop->offset;
635 item_size = ply_type_size[prop->internal_type];
636 get_stored_item((void *) item, prop->internal_type,
637 &int_val, &uint_val, &double_val);
638 write_binary_item(fp, int_val, uint_val, double_val,
639 prop->external_type);
647 /******************************************************************************
648 Specify a comment that will be written in the header.
651 plyfile - file identifier
652 comment - the comment to be written
653 ******************************************************************************/
655 void ply_put_comment(PlyFile *plyfile, char *comment)
657 /* (re)allocate space for new comment */
658 if (plyfile->num_comments == 0)
659 plyfile->comments = (char **) myalloc(sizeof(char *));
661 plyfile->comments = (char **) realloc(plyfile->comments,
662 sizeof(char *) * (plyfile->num_comments + 1));
664 /* add comment to list */
665 plyfile->comments[plyfile->num_comments] = strdup(comment);
666 plyfile->num_comments++;
670 /******************************************************************************
671 Specify a piece of object information (arbitrary text) that will be written
675 plyfile - file identifier
676 obj_info - the text information to be written
677 ******************************************************************************/
679 void ply_put_obj_info(PlyFile *plyfile, char *obj_info)
681 /* (re)allocate space for new info */
682 if (plyfile->num_obj_info == 0)
683 plyfile->obj_info = (char **) myalloc(sizeof(char *));
685 plyfile->obj_info = (char **) realloc(plyfile->obj_info,
686 sizeof(char *) * (plyfile->num_obj_info + 1));
688 /* add info to list */
689 plyfile->obj_info[plyfile->num_obj_info] = strdup(obj_info);
690 plyfile->num_obj_info++;
705 /******************************************************************************
706 Given a file pointer, get ready to read PLY data from the file.
709 fp - the given file pointer
712 nelems - number of elements in object
713 elem_names - list of element names
714 returns a pointer to a PlyFile, used to refer to this file, or NULL if error
715 ******************************************************************************/
717 PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
723 int found_format = 0;
728 /* check for NULL file pointer */
732 /* create record for this object */
734 plyfile = (PlyFile *) myalloc(sizeof(PlyFile));
736 plyfile->comments = NULL;
737 plyfile->num_comments = 0;
738 plyfile->obj_info = NULL;
739 plyfile->num_obj_info = 0;
741 plyfile->other_elems = NULL;
743 /* read and parse the file's header */
745 words = get_words(plyfile->fp, &nwords, &orig_line);
746 if (!words || !equal_strings(words[0], "ply"))
753 if (equal_strings(words[0], "format")) {
756 if (equal_strings(words[1], "ascii"))
757 plyfile->file_type = PLY_ASCII;
758 else if (equal_strings(words[1], "binary_big_endian"))
759 plyfile->file_type = PLY_BINARY_BE;
760 else if (equal_strings(words[1], "binary_little_endian"))
761 plyfile->file_type = PLY_BINARY_LE;
764 plyfile->version = (float)atof(words[2]);
767 else if (equal_strings(words[0], "element"))
768 add_element(plyfile, words);
769 else if (equal_strings(words[0], "property"))
770 add_property(plyfile, words);
771 else if (equal_strings(words[0], "comment"))
772 add_comment(plyfile, orig_line);
773 else if (equal_strings(words[0], "obj_info"))
774 add_obj_info(plyfile, orig_line);
775 else if (equal_strings(words[0], "end_header"))
778 /* free up words space */
781 words = get_words(plyfile->fp, &nwords, &orig_line);
784 /* create tags for each property of each element, to be used */
785 /* later to say whether or not to store each property for the user */
787 for (i = 0; i < plyfile->nelems; i++) {
788 elem = plyfile->elems[i];
789 elem->store_prop = (char *) myalloc(sizeof(char) * elem->nprops);
790 for (j = 0; j < elem->nprops; j++)
791 elem->store_prop[j] = DONT_STORE_PROP;
792 elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
795 /* set return values about the elements */
797 elist = (char **) myalloc(sizeof(char *) * plyfile->nelems);
798 for (i = 0; i < plyfile->nelems; i++)
799 elist[i] = strdup(plyfile->elems[i]->name);
802 *nelems = plyfile->nelems;
804 /* return a pointer to the file's information */
810 /******************************************************************************
811 Open a polygon file for reading.
814 filename - name of file to read from
817 nelems - number of elements in object
818 elem_names - list of element names
819 file_type - file type, either ascii or binary
820 version - version number of PLY file
821 returns a file identifier, used to refer to this file, or NULL if error
822 ******************************************************************************/
824 PlyFile *ply_open_for_reading(
836 /* tack on the extension .ply, if necessary */
838 name = (char *) myalloc(sizeof(char) * (strlen(filename) + 5));
839 strcpy(name, filename);
840 if (strlen(name) < 4 ||
841 strcmp(name + strlen(name) - 4, ".ply") != 0)
842 strcat(name, ".ply");
844 /* open the file for reading */
846 fp = fopen(name, "r");
850 /* create the PlyFile data structure */
852 plyfile = ply_read(fp, nelems, elem_names);
854 /* determine the file type and version */
856 *file_type = plyfile->file_type;
857 *version = plyfile->version;
859 /* return a pointer to the file's information */
865 /******************************************************************************
866 Get information about a particular element.
869 plyfile - file identifier
870 elem_name - name of element to get information about
873 nelems - number of elements of this type in the file
874 nprops - number of properties
875 returns a list of properties, or NULL if the file doesn't contain that elem
876 ******************************************************************************/
878 PlyProperty **ply_get_element_description(
888 PlyProperty **prop_list;
890 /* find information about the element */
891 elem = find_element(plyfile, elem_name);
896 *nprops = elem->nprops;
898 /* make a copy of the element's property list */
899 prop_list = (PlyProperty **) myalloc(sizeof(PlyProperty *) * elem->nprops);
900 for (i = 0; i < elem->nprops; i++) {
901 prop = (PlyProperty *) myalloc(sizeof(PlyProperty));
902 copy_property(prop, elem->props[i]);
906 /* return this duplicate property list */
911 /******************************************************************************
912 Specify which properties of an element are to be returned. This should be
913 called before a call to the routine ply_get_element().
916 plyfile - file identifier
917 elem_name - which element we're talking about
918 nprops - number of properties
919 prop_list - list of properties
920 ******************************************************************************/
922 void ply_get_element_setup(
926 PlyProperty *prop_list
934 /* find information about the element */
935 elem = find_element(plyfile, elem_name);
936 plyfile->which_elem = elem;
938 /* deposit the property information into the element's description */
939 for (i = 0; i < nprops; i++) {
941 /* look for actual property */
942 prop = find_property(elem, prop_list[i].name, &index);
944 fprintf(stderr, "Warning: Can't find property '%s' in element '%s'\n",
945 prop_list[i].name, elem_name);
949 /* store its description */
950 prop->internal_type = prop_list[i].internal_type;
951 prop->offset = prop_list[i].offset;
952 prop->count_internal = prop_list[i].count_internal;
953 prop->count_offset = prop_list[i].count_offset;
955 /* specify that the user wants this property */
956 elem->store_prop[index] = STORE_PROP;
961 /******************************************************************************
962 Specify a property of an element that is to be returned. This should be
963 called (usually multiple times) before a call to the routine ply_get_element().
964 This routine should be used in preference to the less flexible old routine
965 called ply_get_element_setup().
968 plyfile - file identifier
969 elem_name - which element we're talking about
970 prop - property to add to those that will be returned
971 ******************************************************************************/
973 void ply_get_property(
980 PlyProperty *prop_ptr;
983 /* find information about the element */
984 elem = find_element(plyfile, elem_name);
985 plyfile->which_elem = elem;
987 /* deposit the property information into the element's description */
989 prop_ptr = find_property(elem, prop->name, &index);
990 if (prop_ptr == NULL) {
991 fprintf(stderr, "Warning: Can't find property '%s' in element '%s'\n",
992 prop->name, elem_name);
995 prop_ptr->internal_type = prop->internal_type;
996 prop_ptr->offset = prop->offset;
997 prop_ptr->count_internal = prop->count_internal;
998 prop_ptr->count_offset = prop->count_offset;
1000 /* specify that the user wants this property */
1001 elem->store_prop[index] = STORE_PROP;
1005 /******************************************************************************
1006 Read one element from the file. This routine assumes that we're reading
1007 the type of element specified in the last call to the routine
1008 ply_get_element_setup().
1011 plyfile - file identifier
1012 elem_ptr - pointer to location where the element information should be put
1013 ******************************************************************************/
1015 void ply_get_element(PlyFile *plyfile, void *elem_ptr)
1017 if (plyfile->file_type == PLY_ASCII)
1018 ascii_get_element(plyfile, (char *) elem_ptr);
1020 binary_get_element(plyfile, (char *) elem_ptr);
1024 /******************************************************************************
1025 Extract the comments from the header information of a PLY file.
1028 plyfile - file identifier
1031 num_comments - number of comments returned
1032 returns a pointer to a list of comments
1033 ******************************************************************************/
1035 char **ply_get_comments(PlyFile *plyfile, int *num_comments)
1037 *num_comments = plyfile->num_comments;
1038 return (plyfile->comments);
1042 /******************************************************************************
1043 Extract the object information (arbitrary text) from the header information
1047 plyfile - file identifier
1050 num_obj_info - number of lines of text information returned
1051 returns a pointer to a list of object info lines
1052 ******************************************************************************/
1054 char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info)
1056 *num_obj_info = plyfile->num_obj_info;
1057 return (plyfile->obj_info);
1061 /******************************************************************************
1062 Make ready for "other" properties of an element-- those properties that
1063 the user has not explicitly asked for, but that are to be stashed away
1064 in a special structure to be carried along with the element's other
1068 plyfile - file identifier
1069 elem - element for which we want to save away other properties
1070 ******************************************************************************/
1072 void setup_other_props(PlyElement *elem)
1079 /* Examine each property in decreasing order of size. */
1080 /* We do this so that all data types will be aligned by */
1081 /* word, half-word, or whatever within the structure. */
1083 for (type_size = 8; type_size > 0; type_size /= 2) {
1085 /* add up the space taken by each property, and save this information */
1086 /* away in the property descriptor */
1088 for (i = 0; i < elem->nprops; i++) {
1090 /* don't bother with properties we've been asked to store explicitly */
1091 if (elem->store_prop[i])
1094 prop = elem->props[i];
1096 /* internal types will be same as external */
1097 prop->internal_type = prop->external_type;
1098 prop->count_internal = prop->count_external;
1100 /* check list case */
1101 if (prop->is_list) {
1103 /* pointer to list */
1104 if (type_size == sizeof(void *)) {
1105 prop->offset = size;
1106 size += sizeof(void *); /* always use size of a pointer here */
1109 /* count of number of list elements */
1110 if (type_size == ply_type_size[prop->count_external]) {
1111 prop->count_offset = size;
1112 size += ply_type_size[prop->count_external];
1116 else if (type_size == ply_type_size[prop->external_type]) {
1117 prop->offset = size;
1118 size += ply_type_size[prop->external_type];
1124 /* save the size for the other_props structure */
1125 elem->other_size = size;
1129 /******************************************************************************
1130 Specify that we want the "other" properties of an element to be tucked
1131 away within the user's structure. The user needn't be concerned for how
1132 these properties are stored.
1135 plyfile - file identifier
1136 elem_name - name of element that we want to store other_props in
1137 offset - offset to where other_props will be stored inside user's structure
1140 returns pointer to structure containing description of other_props
1141 ******************************************************************************/
1143 PlyOtherProp *ply_get_other_properties(
1151 PlyOtherProp *other;
1155 /* find information about the element */
1156 elem = find_element(plyfile, elem_name);
1158 fprintf(stderr, "ply_get_other_properties: Can't find element '%s'\n",
1163 /* remember that this is the "current" element */
1164 plyfile->which_elem = elem;
1166 /* save the offset to where to store the other_props */
1167 elem->other_offset = offset;
1169 /* place the appropriate pointers, etc. in the element's property list */
1170 setup_other_props(elem);
1172 /* create structure for describing other_props */
1173 other = (PlyOtherProp *) myalloc(sizeof(PlyOtherProp));
1174 other->name = strdup(elem_name);
1176 if (elem->other_offset == NO_OTHER_PROPS) {
1178 other->props = NULL;
1183 other->size = elem->other_size;
1184 other->props = (PlyProperty **) myalloc(sizeof(PlyProperty) * elem->nprops);
1186 /* save descriptions of each "other" property */
1188 for (i = 0; i < elem->nprops; i++) {
1189 if (elem->store_prop[i])
1191 prop = (PlyProperty *) myalloc(sizeof(PlyProperty));
1192 copy_property(prop, elem->props[i]);
1193 other->props[nprops] = prop;
1196 other->nprops = nprops;
1199 /* set other_offset pointer appropriately if there are NO other properties */
1200 if (other->nprops == 0) {
1201 elem->other_offset = NO_OTHER_PROPS;
1205 /* return structure */
1212 /*************************/
1213 /* Other Element Stuff */
1214 /*************************/
1219 /******************************************************************************
1220 Grab all the data for an element that a user does not want to explicitly
1224 plyfile - pointer to file
1225 elem_name - name of element whose data is to be read in
1226 elem_count - number of instances of this element stored in the file
1229 returns pointer to ALL the "other" element data for this PLY file
1230 ******************************************************************************/
1232 PlyOtherElems *ply_get_other_element(
1240 PlyOtherElems *other_elems;
1243 /* look for appropriate element */
1244 elem = find_element(plyfile, elem_name);
1247 "ply_get_other_element: can't find element '%s'\n", elem_name);
1251 /* create room for the new "other" element, initializing the */
1252 /* other data structure if necessary */
1254 if (plyfile->other_elems == NULL) {
1255 plyfile->other_elems = (PlyOtherElems *) myalloc(sizeof(PlyOtherElems));
1256 other_elems = plyfile->other_elems;
1257 other_elems->other_list = (OtherElem *) myalloc(sizeof(OtherElem));
1258 other = &(other_elems->other_list[0]);
1259 other_elems->num_elems = 1;
1262 other_elems = plyfile->other_elems;
1263 other_elems->other_list = (OtherElem *) realloc(other_elems->other_list,
1264 sizeof(OtherElem) * other_elems->num_elems + 1);
1265 other = &(other_elems->other_list[other_elems->num_elems]);
1266 other_elems->num_elems++;
1269 /* count of element instances in file */
1270 other->elem_count = elem_count;
1272 /* save name of element */
1273 other->elem_name = strdup(elem_name);
1275 /* create a list to hold all the current elements */
1276 other->other_data = (OtherData **)
1277 malloc(sizeof(OtherData *) * other->elem_count);
1279 /* set up for getting elements */
1280 other->other_props = ply_get_other_properties(plyfile, elem_name,
1281 offsetof(OtherData, other_props));
1283 /* grab all these elements */
1284 for (i = 0; i < other->elem_count; i++) {
1285 /* grab and element from the file */
1286 other->other_data[i] = (OtherData *) malloc(sizeof(OtherData));
1287 ply_get_element(plyfile, (void *) other->other_data[i]);
1290 /* return pointer to the other elements data */
1291 return (other_elems);
1295 /******************************************************************************
1296 Pass along a pointer to "other" elements that we want to save in a given
1297 PLY file. These other elements were presumably read from another PLY file.
1300 plyfile - file pointer in which to store this other element info
1301 other_elems - info about other elements that we want to store
1302 ******************************************************************************/
1304 void ply_describe_other_elements(
1306 PlyOtherElems *other_elems
1312 /* ignore this call if there is no other element */
1313 if (other_elems == NULL)
1316 /* save pointer to this information */
1317 plyfile->other_elems = other_elems;
1319 /* describe the other properties of this element */
1321 for (i = 0; i < other_elems->num_elems; i++) {
1322 other = &(other_elems->other_list[i]);
1323 ply_element_count(plyfile, other->elem_name, other->elem_count);
1324 ply_describe_other_properties(plyfile, other->other_props,
1325 offsetof(OtherData, other_props));
1330 /******************************************************************************
1331 Write out the "other" elements specified for this PLY file.
1334 plyfile - pointer to PLY file to write out other elements for
1335 ******************************************************************************/
1337 void ply_put_other_elements(PlyFile *plyfile)
1342 /* make sure we have other elements to write */
1343 if (plyfile->other_elems == NULL)
1346 /* write out the data for each "other" element */
1348 for (i = 0; i < plyfile->other_elems->num_elems; i++) {
1350 other = &(plyfile->other_elems->other_list[i]);
1351 ply_put_element_setup(plyfile, other->elem_name);
1353 /* write out each instance of the current element */
1354 for (j = 0; j < other->elem_count; j++)
1355 ply_put_element(plyfile, (void *) other->other_data[j]);
1360 /******************************************************************************
1361 Free up storage used by an "other" elements data structure.
1364 other_elems - data structure to free up
1365 ******************************************************************************/
1370 /*******************/
1372 /*******************/
1376 /******************************************************************************
1380 plyfile - identifier of file to close
1381 ******************************************************************************/
1383 void ply_close(PlyFile *plyfile)
1385 fclose(plyfile->fp);
1387 /* free up memory associated with the PLY file */
1392 /******************************************************************************
1393 Get version number and file type of a PlyFile.
1396 ply - pointer to PLY file
1399 version - version of the file
1400 file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
1401 ******************************************************************************/
1403 void ply_get_info(PlyFile *ply, float *version, int *file_type)
1408 *version = ply->version;
1409 *file_type = ply->file_type;
1413 /******************************************************************************
1414 Compare two strings. Returns 1 if they are the same, 0 if not.
1415 ******************************************************************************/
1417 int equal_strings(char *s1, char *s2)
1431 /******************************************************************************
1432 Find an element from the element list of a given PLY object.
1435 plyfile - file id for PLY file
1436 element - name of element we're looking for
1439 returns the element, or NULL if not found
1440 ******************************************************************************/
1442 PlyElement *find_element(PlyFile *plyfile, char *element)
1446 for (i = 0; i < plyfile->nelems; i++)
1447 if (equal_strings(element, plyfile->elems[i]->name))
1448 return (plyfile->elems[i]);
1454 /******************************************************************************
1455 Find a property in the list of properties of a given element.
1458 elem - pointer to element in which we want to find the property
1459 prop_name - name of property to find
1462 index - index to position in list
1463 returns a pointer to the property, or NULL if not found
1464 ******************************************************************************/
1466 PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index)
1470 for (i = 0; i < elem->nprops; i++)
1471 if (equal_strings(prop_name, elem->props[i]->name)) {
1473 return (elem->props[i]);
1481 /******************************************************************************
1482 Read an element from an ascii file.
1485 plyfile - file identifier
1486 elem_ptr - pointer to element
1487 ******************************************************************************/
1489 void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
1497 char *elem_data, *item;
1501 unsigned int uint_val;
1515 /* the kind of element we're reading currently */
1516 elem = plyfile->which_elem;
1518 /* do we need to setup for other_props? */
1520 if (elem->other_offset != NO_OTHER_PROPS) {
1523 /* make room for other_props */
1524 other_data = (char *) myalloc(elem->other_size);
1525 /* store pointer in user's structure to the other_props */
1526 ptr = (char **) (elem_ptr + elem->other_offset);
1536 /* read in the element */
1538 words = get_words(plyfile->fp, &nwords, &orig_line);
1539 if (words == NULL) {
1540 fprintf(stderr, "ply_get_element: unexpected end of file\n");
1546 for (j = 0; j < elem->nprops; j++) {
1548 prop = elem->props[j];
1549 store_it = (elem->store_prop[j] | other_flag);
1551 /* store either in the user's structure or in other_props */
1552 if (elem->store_prop[j])
1553 elem_data = elem_ptr;
1555 elem_data = other_data;
1557 if (prop->is_list) { /* a list */
1559 /* get and store the number of items in the list */
1560 get_ascii_item(words[which_word++], prop->count_external,
1561 &int_val, &uint_val, &double_val);
1563 item = elem_data + prop->count_offset;
1564 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1567 /* allocate space for an array of items and store a ptr to the array */
1568 list_count = int_val;
1569 item_size = ply_type_size[prop->internal_type];
1570 store_array = (char **) (elem_data + prop->offset);
1572 if (list_count == 0) {
1574 *store_array = NULL;
1578 item_ptr = (char *) myalloc(sizeof(char) * item_size * list_count);
1580 *store_array = item_ptr;
1583 /* read items and store them into the array */
1584 for (k = 0; k < list_count; k++) {
1585 get_ascii_item(words[which_word++], prop->external_type,
1586 &int_val, &uint_val, &double_val);
1588 store_item(item, prop->internal_type,
1589 int_val, uint_val, double_val);
1596 else { /* not a list */
1597 get_ascii_item(words[which_word++], prop->external_type,
1598 &int_val, &uint_val, &double_val);
1600 item = elem_data + prop->offset;
1601 store_item(item, prop->internal_type, int_val, uint_val, double_val);
1611 /******************************************************************************
1612 Read an element from a binary file.
1615 plyfile - file identifier
1616 elem_ptr - pointer to an element
1617 ******************************************************************************/
1619 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
1624 FILE *fp = plyfile->fp;
1625 char *elem_data, *item;
1629 unsigned int uint_val;
1643 /* the kind of element we're reading currently */
1644 elem = plyfile->which_elem;
1646 /* do we need to setup for other_props? */
1648 if (elem->other_offset != NO_OTHER_PROPS) {
1651 /* make room for other_props */
1652 other_data = (char *) myalloc(elem->other_size);
1653 /* store pointer in user's structure to the other_props */
1654 ptr = (char **) (elem_ptr + elem->other_offset);
1663 /* read in a number of elements */
1665 for (j = 0; j < elem->nprops; j++) {
1667 prop = elem->props[j];
1668 store_it = (elem->store_prop[j] | other_flag);
1670 /* store either in the user's structure or in other_props */
1671 if (elem->store_prop[j])
1672 elem_data = elem_ptr;
1674 elem_data = other_data;
1676 if (prop->is_list) { /* a list */
1678 /* get and store the number of items in the list */
1679 get_binary_item(fp, prop->count_external,
1680 &int_val, &uint_val, &double_val);
1682 item = elem_data + prop->count_offset;
1683 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1686 /* allocate space for an array of items and store a ptr to the array */
1687 list_count = int_val;
1688 /* The "if" was added by Afra Zomorodian 8/22/95
1689 * so that zipper won't crash reading plies that have additional
1693 item_size = ply_type_size[prop->internal_type];
1695 store_array = (char **) (elem_data + prop->offset);
1696 if (list_count == 0) {
1698 *store_array = NULL;
1702 item_ptr = (char *) myalloc(sizeof(char) * item_size * list_count);
1704 *store_array = item_ptr;
1707 /* read items and store them into the array */
1708 for (k = 0; k < list_count; k++) {
1709 get_binary_item(fp, prop->external_type,
1710 &int_val, &uint_val, &double_val);
1712 store_item(item, prop->internal_type,
1713 int_val, uint_val, double_val);
1720 else { /* not a list */
1721 get_binary_item(fp, prop->external_type,
1722 &int_val, &uint_val, &double_val);
1724 item = elem_data + prop->offset;
1725 store_item(item, prop->internal_type, int_val, uint_val, double_val);
1733 /******************************************************************************
1734 Write to a file the word that represents a PLY data type.
1738 code - code for type
1739 ******************************************************************************/
1741 void write_scalar_type(FILE *fp, int code)
1743 /* make sure this is a valid code */
1745 if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
1746 fprintf(stderr, "write_scalar_type: bad data code = %d\n", code);
1750 /* write the code to a file */
1752 fprintf(fp, "%s", type_names[code]);
1756 /******************************************************************************
1757 Get a text line from a file and break it up into words.
1759 IMPORTANT: The calling routine call "free" on the returned pointer once
1763 fp - file to read from
1766 nwords - number of words returned
1767 orig_line - the original line of characters
1768 returns a list of words from the line, or NULL if end-of-file
1769 ******************************************************************************/
1771 char **get_words(FILE *fp, int *nwords, char **orig_line)
1773 #define BIG_STRING 4096
1774 static char str[BIG_STRING];
1775 static char str_copy[BIG_STRING];
1782 words = (char **) myalloc(sizeof(char *) * max_words);
1784 /* read in a line */
1785 result = fgets(str, BIG_STRING, fp);
1786 if (result == NULL) {
1792 /* convert line-feed and tabs into spaces */
1793 /* (this guarentees that there will be a space before the */
1794 /* null character at the end of the string) */
1796 str[BIG_STRING - 2] = ' ';
1797 str[BIG_STRING - 1] = '\0';
1799 for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
1805 else if (*ptr == '\n') {
1812 /* find the words in the line */
1815 while (*ptr != '\0') {
1817 /* jump over leading spaces */
1821 /* break if we reach the end */
1825 /* save pointer to beginning of word */
1826 if (num_words >= max_words) {
1828 words = (char **) realloc(words, sizeof(char *) * max_words);
1830 words[num_words++] = ptr;
1832 /* jump over non-spaces */
1836 /* place a null character here to mark the end of the word */
1840 /* return the list of words */
1841 *nwords = num_words;
1842 *orig_line = str_copy;
1847 /******************************************************************************
1848 Return the value of an item, given a pointer to it and its type.
1851 item - pointer to item
1852 type - data type that "item" points to
1855 returns a double-precision float that contains the value of the item
1856 ******************************************************************************/
1858 double get_item_value(char *item, int type)
1860 unsigned char *puchar;
1863 unsigned short int *pushort;
1865 unsigned int *puint;
1869 unsigned int uint_value;
1870 double double_value;
1874 pchar = (char *) item;
1876 return ((double) int_value);
1878 puchar = (unsigned char *) item;
1879 int_value = *puchar;
1880 return ((double) int_value);
1882 pshort = (short int *) item;
1883 int_value = *pshort;
1884 return ((double) int_value);
1886 pushort = (unsigned short int *) item;
1887 int_value = *pushort;
1888 return ((double) int_value);
1890 pint = (int *) item;
1892 return ((double) int_value);
1894 puint = (unsigned int *) item;
1895 uint_value = *puint;
1896 return ((double) uint_value);
1898 pfloat = (float *) item;
1899 double_value = *pfloat;
1900 return (double_value);
1902 pdouble = (double *) item;
1903 double_value = *pdouble;
1904 return (double_value);
1906 fprintf(stderr, "get_item_value: bad type = %d\n", type);
1912 /******************************************************************************
1913 Write out an item to a file as raw binary bytes.
1916 fp - file to write to
1917 int_val - integer version of item
1918 uint_val - unsigned integer version of item
1919 double_val - double-precision float version of item
1920 type - data type to write out
1921 ******************************************************************************/
1923 void write_binary_item(
1926 unsigned int uint_val,
1931 unsigned char uchar_val;
1933 unsigned short ushort_val;
1939 char_val = (char)int_val;
1940 fwrite(&char_val, 1, 1, fp);
1943 short_val = (short)int_val;
1944 fwrite(&short_val, 2, 1, fp);
1947 fwrite(&int_val, 4, 1, fp);
1950 uchar_val = (unsigned char) uint_val;
1951 fwrite(&uchar_val, 1, 1, fp);
1954 ushort_val = (unsigned short)uint_val;
1955 fwrite(&ushort_val, 2, 1, fp);
1958 fwrite(&uint_val, 4, 1, fp);
1961 float_val = (float) double_val;
1962 fwrite(&float_val, 4, 1, fp);
1965 fwrite(&double_val, 8, 1, fp);
1968 fprintf(stderr, "write_binary_item: bad type = %d\n", type);
1974 /******************************************************************************
1975 Write out an item to a file as ascii characters.
1978 fp - file to write to
1979 int_val - integer version of item
1980 uint_val - unsigned integer version of item
1981 double_val - double-precision float version of item
1982 type - data type to write out
1983 ******************************************************************************/
1985 void write_ascii_item(
1988 unsigned int uint_val,
1997 fprintf(fp, "%d ", int_val);
2002 fprintf(fp, "%u ", uint_val);
2006 fprintf(fp, "%g ", double_val);
2009 fprintf(stderr, "write_ascii_item: bad type = %d\n", type);
2015 /******************************************************************************
2016 Write out an item to a file as ascii characters.
2019 fp - file to write to
2020 item - pointer to item to write
2021 type - data type that "item" points to
2024 returns a double-precision float that contains the value of the written item
2025 ******************************************************************************/
2027 double old_write_ascii_item(FILE *fp, char *item, int type)
2029 unsigned char *puchar;
2032 unsigned short int *pushort;
2034 unsigned int *puint;
2038 unsigned int uint_value;
2039 double double_value;
2043 pchar = (char *) item;
2045 fprintf(fp, "%d ", int_value);
2046 return ((double) int_value);
2048 puchar = (unsigned char *) item;
2049 int_value = *puchar;
2050 fprintf(fp, "%d ", int_value);
2051 return ((double) int_value);
2053 pshort = (short int *) item;
2054 int_value = *pshort;
2055 fprintf(fp, "%d ", int_value);
2056 return ((double) int_value);
2058 pushort = (unsigned short int *) item;
2059 int_value = *pushort;
2060 fprintf(fp, "%d ", int_value);
2061 return ((double) int_value);
2063 pint = (int *) item;
2065 fprintf(fp, "%d ", int_value);
2066 return ((double) int_value);
2068 puint = (unsigned int *) item;
2069 uint_value = *puint;
2070 fprintf(fp, "%u ", uint_value);
2071 return ((double) uint_value);
2073 pfloat = (float *) item;
2074 double_value = *pfloat;
2075 fprintf(fp, "%g ", double_value);
2076 return (double_value);
2078 pdouble = (double *) item;
2079 double_value = *pdouble;
2080 fprintf(fp, "%g ", double_value);
2081 return (double_value);
2083 fprintf(stderr, "old_write_ascii_item: bad type = %d\n", type);
2089 /******************************************************************************
2090 Get the value of an item that is in memory, and place the result
2091 into an integer, an unsigned integer and a double.
2094 ptr - pointer to the item
2095 type - data type supposedly in the item
2098 int_val - integer value
2099 uint_val - unsigned integer value
2100 double_val - double-precision floating point value
2101 ******************************************************************************/
2103 void get_stored_item(
2107 unsigned int *uint_val,
2113 *int_val = *((char *) ptr);
2114 *uint_val = *int_val;
2115 *double_val = *int_val;
2118 *uint_val = *((unsigned char *) ptr);
2119 *int_val = *uint_val;
2120 *double_val = *uint_val;
2123 *int_val = *((short int *) ptr);
2124 *uint_val = *int_val;
2125 *double_val = *int_val;
2128 *uint_val = *((unsigned short int *) ptr);
2129 *int_val = *uint_val;
2130 *double_val = *uint_val;
2133 *int_val = *((int *) ptr);
2134 *uint_val = *int_val;
2135 *double_val = *int_val;
2138 *uint_val = *((unsigned int *) ptr);
2139 *int_val = *uint_val;
2140 *double_val = *uint_val;
2143 *double_val = *((float *) ptr);
2144 *int_val = (int)*double_val;
2145 *uint_val = (unsigned int)*double_val;
2148 *double_val = *((double *) ptr);
2149 *int_val = (int)*double_val;
2150 *uint_val = (unsigned int) *double_val;
2153 fprintf(stderr, "get_stored_item: bad type = %d\n", type);
2159 /******************************************************************************
2160 Get the value of an item from a binary file, and place the result
2161 into an integer, an unsigned integer and a double.
2164 fp - file to get item from
2165 type - data type supposedly in the word
2168 int_val - integer value
2169 uint_val - unsigned integer value
2170 double_val - double-precision floating point value
2171 ******************************************************************************/
2173 void get_binary_item(
2177 unsigned int *uint_val,
2188 fread(ptr, 1, 1, fp);
2189 *int_val = *((char *) ptr);
2190 *uint_val = *int_val;
2191 *double_val = *int_val;
2194 fread(ptr, 1, 1, fp);
2195 *uint_val = *((unsigned char *) ptr);
2196 *int_val = *uint_val;
2197 *double_val = *uint_val;
2200 fread(ptr, 2, 1, fp);
2201 *int_val = *((short int *) ptr);
2202 *uint_val = *int_val;
2203 *double_val = *int_val;
2206 fread(ptr, 2, 1, fp);
2207 *uint_val = *((unsigned short int *) ptr);
2208 *int_val = *uint_val;
2209 *double_val = *uint_val;
2212 fread(ptr, 4, 1, fp);
2213 *int_val = *((int *) ptr);
2214 *uint_val = *int_val;
2215 *double_val = *int_val;
2218 fread(ptr, 4, 1, fp);
2219 *uint_val = *((unsigned int *) ptr);
2220 *int_val = *uint_val;
2221 *double_val = *uint_val;
2224 fread(ptr, 4, 1, fp);
2225 *double_val = *((float *) ptr);
2226 *int_val = (int)*double_val;
2227 *uint_val = (unsigned int) *double_val;
2230 fread(ptr, 8, 1, fp);
2231 *double_val = *((double *) ptr);
2232 *int_val = (int)*double_val;
2233 *uint_val = (unsigned int)*double_val;
2236 fprintf(stderr, "get_binary_item: bad type = %d\n", type);
2242 /******************************************************************************
2243 Extract the value of an item from an ascii word, and place the result
2244 into an integer, an unsigned integer and a double.
2247 word - word to extract value from
2248 type - data type supposedly in the word
2251 int_val - integer value
2252 uint_val - unsigned integer value
2253 double_val - double-precision floating point value
2254 ******************************************************************************/
2256 void get_ascii_item(
2260 unsigned int *uint_val,
2270 *int_val = atoi(word);
2271 *uint_val = *int_val;
2272 *double_val = *int_val;
2276 *uint_val = strtoul(word, (char **) NULL, 10);
2277 *int_val = *uint_val;
2278 *double_val = *uint_val;
2283 *double_val = atof(word);
2284 *int_val = (int) *double_val;
2285 *uint_val = (unsigned int) *double_val;
2289 fprintf(stderr, "get_ascii_item: bad type = %d\n", type);
2295 /******************************************************************************
2296 Store a value into a place being pointed to, guided by a data type.
2299 item - place to store value
2301 int_val - integer version of value
2302 uint_val - unsigned integer version of value
2303 double_val - double version of value
2306 item - pointer to stored value
2307 ******************************************************************************/
2313 unsigned int uint_val,
2317 unsigned char *puchar;
2319 unsigned short int *pushort;
2321 unsigned int *puint;
2327 *item = (char) int_val;
2330 puchar = (unsigned char *) item;
2331 *puchar = (unsigned char)uint_val;
2334 pshort = (short *) item;
2335 *pshort = (short)int_val;
2338 pushort = (unsigned short *) item;
2339 *pushort = (unsigned short)uint_val;
2342 pint = (int *) item;
2346 puint = (unsigned int *) item;
2350 pfloat = (float *) item;
2351 *pfloat = (float)double_val;
2354 pdouble = (double *) item;
2355 *pdouble = double_val;
2358 fprintf(stderr, "store_item: bad type = %d\n", type);
2364 /******************************************************************************
2365 Add an element to a PLY file descriptor.
2368 plyfile - PLY file descriptor
2369 words - list of words describing the element
2370 nwords - number of words in the list
2371 ******************************************************************************/
2373 void add_element(PlyFile *plyfile, char **words)
2377 /* create the new element */
2378 elem = (PlyElement *) myalloc(sizeof(PlyElement));
2379 elem->name = strdup(words[1]);
2380 elem->num = atoi(words[2]);
2383 /* make room for new element in the object's list of elements */
2384 if (plyfile->nelems == 0)
2385 plyfile->elems = (PlyElement **) myalloc(sizeof(PlyElement *));
2387 plyfile->elems = (PlyElement **) realloc(plyfile->elems,
2388 sizeof(PlyElement *) * (plyfile->nelems + 1));
2390 /* add the new element to the object's list */
2391 plyfile->elems[plyfile->nelems] = elem;
2396 /******************************************************************************
2397 Return the type of a property, given the name of the property.
2400 name - name of property type
2403 returns integer code for property, or 0 if not found
2404 ******************************************************************************/
2406 int get_prop_type(char *type_name)
2410 for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
2411 if (equal_strings(type_name, type_names[i]))
2414 /* if we get here, we didn't find the type */
2419 /******************************************************************************
2420 Add a property to a PLY file descriptor.
2423 plyfile - PLY file descriptor
2424 words - list of words describing the property
2425 nwords - number of words in the list
2426 ******************************************************************************/
2428 void add_property(PlyFile *plyfile, char **words)
2433 /* create the new property */
2435 prop = (PlyProperty *) myalloc(sizeof(PlyProperty));
2437 if (equal_strings(words[1], "list")) { /* is a list */
2438 prop->count_external = get_prop_type(words[2]);
2439 prop->external_type = get_prop_type(words[3]);
2440 prop->name = strdup(words[4]);
2443 else { /* not a list */
2444 prop->external_type = get_prop_type(words[1]);
2445 prop->name = strdup(words[2]);
2449 /* add this property to the list of properties of the current element */
2451 elem = plyfile->elems[plyfile->nelems - 1];
2453 if (elem->nprops == 0)
2454 elem->props = (PlyProperty **) myalloc(sizeof(PlyProperty *));
2456 elem->props = (PlyProperty **) realloc(elem->props,
2457 sizeof(PlyProperty *) * (elem->nprops + 1));
2459 elem->props[elem->nprops] = prop;
2464 /******************************************************************************
2465 Add a comment to a PLY file descriptor.
2468 plyfile - PLY file descriptor
2469 line - line containing comment
2470 ******************************************************************************/
2472 void add_comment(PlyFile *plyfile, char *line)
2476 /* skip over "comment" and leading spaces and tabs */
2478 while (line[i] == ' ' || line[i] == '\t')
2481 ply_put_comment(plyfile, &line[i]);
2485 /******************************************************************************
2486 Add a some object information to a PLY file descriptor.
2489 plyfile - PLY file descriptor
2490 line - line containing text info
2491 ******************************************************************************/
2493 void add_obj_info(PlyFile *plyfile, char *line)
2497 /* skip over "obj_info" and leading spaces and tabs */
2499 while (line[i] == ' ' || line[i] == '\t')
2502 ply_put_obj_info(plyfile, &line[i]);
2506 /******************************************************************************
2508 ******************************************************************************/
2510 void copy_property(PlyProperty *dest, PlyProperty *src)
2512 dest->name = strdup(src->name);
2513 dest->external_type = src->external_type;
2514 dest->internal_type = src->internal_type;
2515 dest->offset = src->offset;
2517 dest->is_list = src->is_list;
2518 dest->count_external = src->count_external;
2519 dest->count_internal = src->count_internal;
2520 dest->count_offset = src->count_offset;
2524 /******************************************************************************
2525 Allocate some memory.
2528 size - amount of memory requested (in bytes)
2529 lnum - line number from which memory was requested
2530 fname - file name from which memory was requested
2531 ******************************************************************************/
2533 static char *my_alloc(int size, int lnum, char *fname)
2537 ptr = (char *) malloc(size);
2540 fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname);