b0134f065573a75f676c91ed5abade476353add8
[blender.git] / intern / bsp / test / BSP_GhostTest / plyfile.c
1 /**
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /*
29
30
31    The interface routines for reading and writing PLY polygon files.
32
33    Greg Turk, February 1994
34
35    ---------------------------------------------------------------
36
37    A PLY file contains a single polygonal _object_.
38
39    An object is composed of lists of _elements_.  Typical elements are
40    vertices, faces, edges and materials.
41
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.
46
47    ---------------------------------------------------------------
48
49    Copyright (c) 1994 The Board of Trustees of The Leland Stanford
50    Junior University.  All rights reserved.
51   
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.
56   
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.
60
61  */
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <math.h>
66 #include <string.h>
67 #include "ply.h"
68
69 char *type_names[] = {
70         "invalid",
71         "char", "short", "int",
72         "uchar", "ushort", "uint",
73         "float", "double",
74 };
75
76 int ply_type_size[] = {
77         0, 1, 2, 4, 1, 2, 4, 4, 8
78 };
79
80 #define NO_OTHER_PROPS  -1
81
82 #define DONT_STORE_PROP  0
83 #define STORE_PROP       1
84
85 #define OTHER_PROP       0
86 #define NAMED_PROP       1
87
88
89 /* returns 1 if strings are equal, 0 if not */
90 int equal_strings(char *, char *);
91
92 /* find an element in a plyfile's list */
93 PlyElement *find_element(PlyFile *, char *);
94
95 /* find a property in an element's list */
96 PlyProperty *find_property(PlyElement *, char *, int *);
97
98 /* write to a file the word describing a PLY file data type */
99 void write_scalar_type(FILE *, int);
100
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 *);
104
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);
109
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 *);
115
116 /* copy a property */
117 void copy_property(PlyProperty *, PlyProperty *);
118
119 /* store a value into where a pointer and a type specify */
120 void store_item(char *, int, int, unsigned int, double);
121
122 /* return the value of a stored item */
123 void get_stored_item(void *, int, int *, unsigned int *, double *);
124
125 /* return the value stored in an item, given ptr to it and its type */
126 double get_item_value(char *, int);
127
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 *);
131
132 /* get a bunch of elements from a file */
133 void ascii_get_element(PlyFile *, char *);
134 void binary_get_element(PlyFile *, char *);
135
136 /* memory allocation */
137 char *my_alloc(int, int, char *);
138
139
140 /*************/
141 /*  Writing  */
142 /*************/
143
144
145 /******************************************************************************
146    Given a file pointer, get ready to write PLY data to the file.
147
148    Entry:
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
153
154    Exit:
155    returns a pointer to a PlyFile, used to refer to this file, or NULL if error
156 ******************************************************************************/
157
158 PlyFile *ply_write(
159     FILE *fp,
160     int nelems,
161     char **elem_names,
162     int file_type
163     )
164 {
165         int i;
166         PlyFile *plyfile;
167         PlyElement *elem;
168
169         /* check for NULL file pointer */
170         if (fp == NULL)
171                 return (NULL);
172
173         /* create a record for this object */
174
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;
181         plyfile->fp = fp;
182         plyfile->other_elems = NULL;
183
184         /* tuck aside the names of the elements */
185
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]);
191                 elem->num = 0;
192                 elem->nprops = 0;
193         }
194
195         /* return pointer to the file descriptor */
196         return (plyfile);
197 }
198
199
200 /******************************************************************************
201    Open a polygon file for writing.
202
203    Entry:
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
208
209    Exit:
210    version - version number of PLY file
211    returns a file identifier, used to refer to this file, or NULL if error
212 ******************************************************************************/
213
214 PlyFile *ply_open_for_writing(
215     char *filename,
216     int nelems,
217     char **elem_names,
218     int file_type,
219     float *version
220     )
221 {
222         PlyFile *plyfile;
223         char *name;
224         FILE *fp;
225
226         /* tack on the extension .ply, if necessary */
227
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");
233
234         /* open the file for writing */
235
236         fp = fopen(name, "w");
237         if (fp == NULL) {
238                 return (NULL);
239         }
240
241         /* create the actual PlyFile structure */
242
243         plyfile = ply_write(fp, nelems, elem_names, file_type);
244         if (plyfile == NULL)
245                 return (NULL);
246
247         /* say what PLY file version number we're writing */
248         *version = plyfile->version;
249
250         /* return pointer to the file descriptor */
251         return (plyfile);
252 }
253
254
255 /******************************************************************************
256    Describe an element, including its properties and how many will be written
257    to the file.
258
259    Entry:
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 ******************************************************************************/
266
267 void ply_describe_element(
268     PlyFile *plyfile,
269     char *elem_name,
270     int nelems,
271     int nprops,
272     PlyProperty *prop_list
273     )
274 {
275         int i;
276         PlyElement *elem;
277         PlyProperty *prop;
278
279         /* look for appropriate element */
280         elem = find_element(plyfile, elem_name);
281         if (elem == NULL) {
282                 fprintf(stderr, "ply_describe_element: can't find element '%s'\n", elem_name);
283                 exit(-1);
284         }
285
286         elem->num = nelems;
287
288         /* copy the list of properties */
289
290         elem->nprops = nprops;
291         elem->props = (PlyProperty **) myalloc(sizeof(PlyProperty *) * nprops);
292         elem->store_prop = (char *) myalloc(sizeof(char) * nprops);
293
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]);
299         }
300 }
301
302
303 /******************************************************************************
304    Describe a property of an element.
305
306    Entry:
307    plyfile   - file identifier
308    elem_name - name of element that information is being specified about
309    prop      - the new property
310 ******************************************************************************/
311
312 void ply_describe_property(
313     PlyFile *plyfile,
314     char *elem_name,
315     PlyProperty *prop
316     )
317 {
318         PlyElement *elem;
319         PlyProperty *elem_prop;
320
321         /* look for appropriate element */
322         elem = find_element(plyfile, elem_name);
323         if (elem == NULL) {
324                 fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
325                         elem_name);
326                 return;
327         }
328
329         /* create room for new property */
330
331         if (elem->nprops == 0) {
332                 elem->props = (PlyProperty **) myalloc(sizeof(PlyProperty *));
333                 elem->store_prop = (char *) myalloc(sizeof(char));
334                 elem->nprops = 1;
335         }
336         else {
337                 elem->nprops++;
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);
342         }
343
344         /* copy the new property */
345
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);
350 }
351
352
353 /******************************************************************************
354    Describe what the "other" properties are that are to be stored, and where
355    they are in an element.
356 ******************************************************************************/
357
358 void ply_describe_other_properties(
359     PlyFile *plyfile,
360     PlyOtherProp *other,
361     int offset
362     )
363 {
364         int i;
365         PlyElement *elem;
366         PlyProperty *prop;
367
368         /* look for appropriate element */
369         elem = find_element(plyfile, other->name);
370         if (elem == NULL) {
371                 fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n",
372                         other->name);
373                 return;
374         }
375
376         /* create room for other properties */
377
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);
382                 elem->nprops = 0;
383         }
384         else {
385                 int newsize;
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);
391         }
392
393         /* copy the other properties */
394
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;
400                 elem->nprops++;
401         }
402
403         /* save other info about other properties */
404         elem->other_size = other->size;
405         elem->other_offset = offset;
406 }
407
408
409 /******************************************************************************
410    State how many of a given element will be written.
411
412    Entry:
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 ******************************************************************************/
417
418 void ply_element_count(
419     PlyFile *plyfile,
420     char *elem_name,
421     int nelems
422     )
423 {
424         PlyElement *elem;
425
426         /* look for appropriate element */
427         elem = find_element(plyfile, elem_name);
428         if (elem == NULL) {
429                 fprintf(stderr, "ply_element_count: can't find element '%s'\n", elem_name);
430                 exit(-1);
431         }
432
433         elem->num = nelems;
434 }
435
436
437 /******************************************************************************
438    Signal that we've described everything a PLY file's header and that the
439    header should be written to the file.
440
441    Entry:
442    plyfile - file identifier
443 ******************************************************************************/
444
445 void ply_header_complete(PlyFile *plyfile)
446 {
447         int i, j;
448         FILE *fp = plyfile->fp;
449         PlyElement *elem;
450         PlyProperty *prop;
451
452         fprintf(fp, "ply\n");
453
454         switch (plyfile->file_type) {
455                 case PLY_ASCII:
456                         fprintf(fp, "format ascii 1.0\n");
457                         break;
458                 case PLY_BINARY_BE:
459                         fprintf(fp, "format binary_big_endian 1.0\n");
460                         break;
461                 case PLY_BINARY_LE:
462                         fprintf(fp, "format binary_little_endian 1.0\n");
463                         break;
464                 default:
465                         fprintf(stderr, "ply_header_complete: bad file type = %d\n",
466                                 plyfile->file_type);
467                         exit(-1);
468         }
469
470         /* write out the comments */
471
472         for (i = 0; i < plyfile->num_comments; i++)
473                 fprintf(fp, "comment %s\n", plyfile->comments[i]);
474
475         /* write out object information */
476
477         for (i = 0; i < plyfile->num_obj_info; i++)
478                 fprintf(fp, "obj_info %s\n", plyfile->obj_info[i]);
479
480         /* write out information about each element */
481
482         for (i = 0; i < plyfile->nelems; i++) {
483
484                 elem = plyfile->elems[i];
485                 fprintf(fp, "element %s %d\n", elem->name, elem->num);
486
487                 /* write out each property */
488                 for (j = 0; j < elem->nprops; j++) {
489                         prop = elem->props[j];
490                         if (prop->is_list) {
491                                 fprintf(fp, "property list ");
492                                 write_scalar_type(fp, prop->count_external);
493                                 fprintf(fp, " ");
494                                 write_scalar_type(fp, prop->external_type);
495                                 fprintf(fp, " %s\n", prop->name);
496                         }
497                         else {
498                                 fprintf(fp, "property ");
499                                 write_scalar_type(fp, prop->external_type);
500                                 fprintf(fp, " %s\n", prop->name);
501                         }
502                 }
503         }
504
505         fprintf(fp, "end_header\n");
506 }
507
508
509 /******************************************************************************
510    Specify which elements are going to be written.  This should be called
511    before a call to the routine ply_put_element().
512
513    Entry:
514    plyfile   - file identifier
515    elem_name - name of element we're talking about
516 ******************************************************************************/
517
518 void ply_put_element_setup(PlyFile *plyfile, char *elem_name)
519 {
520         PlyElement *elem;
521
522         elem = find_element(plyfile, elem_name);
523         if (elem == NULL) {
524                 fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name);
525                 exit(-1);
526         }
527
528         plyfile->which_elem = elem;
529 }
530
531
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().
536
537    Entry:
538    plyfile  - file identifier
539    elem_ptr - pointer to the element
540 ******************************************************************************/
541
542 void ply_put_element(PlyFile *plyfile, void *elem_ptr)
543 {
544         int j, k;
545         FILE *fp = plyfile->fp;
546         PlyElement *elem;
547         PlyProperty *prop;
548         char *elem_data, *item;
549         char **item_ptr;
550         int list_count;
551         int item_size;
552         int int_val;
553         unsigned int uint_val;
554         double double_val;
555         char **other_ptr;
556
557         elem = plyfile->which_elem;
558         elem_data = elem_ptr;
559         other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
560
561         /* write out either to an ascii or binary file */
562
563         if (plyfile->file_type == PLY_ASCII) {
564
565                 /* write an ascii file */
566
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;
572                         else
573                                 elem_data = elem_ptr;
574                         if (prop->is_list) {
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);
582                                 item = item_ptr[0];
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);
589                                         item += item_size;
590                                 }
591                         }
592                         else {
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);
598                         }
599                 }
600
601                 fprintf(fp, "\n");
602         }
603         else {
604
605                 /* write a binary file */
606
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;
612                         else
613                                 elem_data = elem_ptr;
614                         if (prop->is_list) {
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);
623                                 item = item_ptr[0];
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);
630                                         item += item_size;
631                                 }
632                         }
633                         else {
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);
640                         }
641                 }
642
643         }
644 }
645
646
647 /******************************************************************************
648    Specify a comment that will be written in the header.
649
650    Entry:
651    plyfile - file identifier
652    comment - the comment to be written
653 ******************************************************************************/
654
655 void ply_put_comment(PlyFile *plyfile, char *comment)
656 {
657         /* (re)allocate space for new comment */
658         if (plyfile->num_comments == 0)
659                 plyfile->comments = (char **) myalloc(sizeof(char *));
660         else
661                 plyfile->comments = (char **) realloc(plyfile->comments,
662                                                       sizeof(char *) * (plyfile->num_comments + 1));
663
664         /* add comment to list */
665         plyfile->comments[plyfile->num_comments] = strdup(comment);
666         plyfile->num_comments++;
667 }
668
669
670 /******************************************************************************
671    Specify a piece of object information (arbitrary text) that will be written
672    in the header.
673
674    Entry:
675    plyfile  - file identifier
676    obj_info - the text information to be written
677 ******************************************************************************/
678
679 void ply_put_obj_info(PlyFile *plyfile, char *obj_info)
680 {
681         /* (re)allocate space for new info */
682         if (plyfile->num_obj_info == 0)
683                 plyfile->obj_info = (char **) myalloc(sizeof(char *));
684         else
685                 plyfile->obj_info = (char **) realloc(plyfile->obj_info,
686                                                       sizeof(char *) * (plyfile->num_obj_info + 1));
687
688         /* add info to list */
689         plyfile->obj_info[plyfile->num_obj_info] = strdup(obj_info);
690         plyfile->num_obj_info++;
691 }
692
693
694
695
696
697
698
699 /*************/
700 /*  Reading  */
701 /*************/
702
703
704
705 /******************************************************************************
706    Given a file pointer, get ready to read PLY data from the file.
707
708    Entry:
709    fp - the given file pointer
710
711    Exit:
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 ******************************************************************************/
716
717 PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
718 {
719         int i, j;
720         PlyFile *plyfile;
721         int nwords;
722         char **words;
723         int found_format = 0;
724         char **elist;
725         PlyElement *elem;
726         char *orig_line;
727
728         /* check for NULL file pointer */
729         if (fp == NULL)
730                 return (NULL);
731
732         /* create record for this object */
733
734         plyfile = (PlyFile *) myalloc(sizeof(PlyFile));
735         plyfile->nelems = 0;
736         plyfile->comments = NULL;
737         plyfile->num_comments = 0;
738         plyfile->obj_info = NULL;
739         plyfile->num_obj_info = 0;
740         plyfile->fp = fp;
741         plyfile->other_elems = NULL;
742
743         /* read and parse the file's header */
744
745         words = get_words(plyfile->fp, &nwords, &orig_line);
746         if (!words || !equal_strings(words[0], "ply"))
747                 return (NULL);
748
749         while (words) {
750
751                 /* parse words */
752
753                 if (equal_strings(words[0], "format")) {
754                         if (nwords != 3)
755                                 return (NULL);
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;
762                         else
763                                 return (NULL);
764                         plyfile->version = (float)atof(words[2]);
765                         found_format = 1;
766                 }
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"))
776                         break;
777
778                 /* free up words space */
779                 free(words);
780
781                 words = get_words(plyfile->fp, &nwords, &orig_line);
782         }
783
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 */
786
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 */
793         }
794
795         /* set return values about the elements */
796
797         elist = (char **) myalloc(sizeof(char *) * plyfile->nelems);
798         for (i = 0; i < plyfile->nelems; i++)
799                 elist[i] = strdup(plyfile->elems[i]->name);
800
801         *elem_names = elist;
802         *nelems = plyfile->nelems;
803
804         /* return a pointer to the file's information */
805
806         return (plyfile);
807 }
808
809
810 /******************************************************************************
811    Open a polygon file for reading.
812
813    Entry:
814    filename - name of file to read from
815
816    Exit:
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 ******************************************************************************/
823
824 PlyFile *ply_open_for_reading(
825     char *filename,
826     int *nelems,
827     char ***elem_names,
828     int *file_type,
829     float *version
830     )
831 {
832         FILE *fp;
833         PlyFile *plyfile;
834         char *name;
835
836         /* tack on the extension .ply, if necessary */
837
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");
843
844         /* open the file for reading */
845
846         fp = fopen(name, "r");
847         if (fp == NULL)
848                 return (NULL);
849
850         /* create the PlyFile data structure */
851
852         plyfile = ply_read(fp, nelems, elem_names);
853
854         /* determine the file type and version */
855
856         *file_type = plyfile->file_type;
857         *version = plyfile->version;
858
859         /* return a pointer to the file's information */
860
861         return (plyfile);
862 }
863
864
865 /******************************************************************************
866    Get information about a particular element.
867
868    Entry:
869    plyfile   - file identifier
870    elem_name - name of element to get information about
871
872    Exit:
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 ******************************************************************************/
877
878 PlyProperty **ply_get_element_description(
879     PlyFile *plyfile,
880     char *elem_name,
881     int *nelems,
882     int *nprops
883     )
884 {
885         int i;
886         PlyElement *elem;
887         PlyProperty *prop;
888         PlyProperty **prop_list;
889
890         /* find information about the element */
891         elem = find_element(plyfile, elem_name);
892         if (elem == NULL)
893                 return (NULL);
894
895         *nelems = elem->num;
896         *nprops = elem->nprops;
897
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]);
903                 prop_list[i] = prop;
904         }
905
906         /* return this duplicate property list */
907         return (prop_list);
908 }
909
910
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().
914
915    Entry:
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 ******************************************************************************/
921
922 void ply_get_element_setup(
923     PlyFile *plyfile,
924     char *elem_name,
925     int nprops,
926     PlyProperty *prop_list
927     )
928 {
929         int i;
930         PlyElement *elem;
931         PlyProperty *prop;
932         int index;
933
934         /* find information about the element */
935         elem = find_element(plyfile, elem_name);
936         plyfile->which_elem = elem;
937
938         /* deposit the property information into the element's description */
939         for (i = 0; i < nprops; i++) {
940
941                 /* look for actual property */
942                 prop = find_property(elem, prop_list[i].name, &index);
943                 if (prop == NULL) {
944                         fprintf(stderr, "Warning:  Can't find property '%s' in element '%s'\n",
945                                 prop_list[i].name, elem_name);
946                         continue;
947                 }
948
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;
954
955                 /* specify that the user wants this property */
956                 elem->store_prop[index] = STORE_PROP;
957         }
958 }
959
960
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().
966
967    Entry:
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 ******************************************************************************/
972
973 void ply_get_property(
974     PlyFile *plyfile,
975     char *elem_name,
976     PlyProperty *prop
977     )
978 {
979         PlyElement *elem;
980         PlyProperty *prop_ptr;
981         int index;
982
983         /* find information about the element */
984         elem = find_element(plyfile, elem_name);
985         plyfile->which_elem = elem;
986
987         /* deposit the property information into the element's description */
988
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);
993                 return;
994         }
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;
999
1000         /* specify that the user wants this property */
1001         elem->store_prop[index] = STORE_PROP;
1002 }
1003
1004
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().
1009
1010    Entry:
1011    plyfile  - file identifier
1012    elem_ptr - pointer to location where the element information should be put
1013 ******************************************************************************/
1014
1015 void ply_get_element(PlyFile *plyfile, void *elem_ptr)
1016 {
1017         if (plyfile->file_type == PLY_ASCII)
1018                 ascii_get_element(plyfile, (char *) elem_ptr);
1019         else
1020                 binary_get_element(plyfile, (char *) elem_ptr);
1021 }
1022
1023
1024 /******************************************************************************
1025    Extract the comments from the header information of a PLY file.
1026
1027    Entry:
1028    plyfile - file identifier
1029
1030    Exit:
1031    num_comments - number of comments returned
1032    returns a pointer to a list of comments
1033 ******************************************************************************/
1034
1035 char **ply_get_comments(PlyFile *plyfile, int *num_comments)
1036 {
1037         *num_comments = plyfile->num_comments;
1038         return (plyfile->comments);
1039 }
1040
1041
1042 /******************************************************************************
1043    Extract the object information (arbitrary text) from the header information
1044    of a PLY file.
1045
1046    Entry:
1047    plyfile - file identifier
1048
1049    Exit:
1050    num_obj_info - number of lines of text information returned
1051    returns a pointer to a list of object info lines
1052 ******************************************************************************/
1053
1054 char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info)
1055 {
1056         *num_obj_info = plyfile->num_obj_info;
1057         return (plyfile->obj_info);
1058 }
1059
1060
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
1065    information.
1066
1067    Entry:
1068    plyfile - file identifier
1069    elem    - element for which we want to save away other properties
1070 ******************************************************************************/
1071
1072 void setup_other_props(PlyElement *elem)
1073 {
1074         int i;
1075         PlyProperty *prop;
1076         int size = 0;
1077         int type_size;
1078
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. */
1082
1083         for (type_size = 8; type_size > 0; type_size /= 2) {
1084
1085                 /* add up the space taken by each property, and save this information */
1086                 /* away in the property descriptor */
1087
1088                 for (i = 0; i < elem->nprops; i++) {
1089
1090                         /* don't bother with properties we've been asked to store explicitly */
1091                         if (elem->store_prop[i])
1092                                 continue;
1093
1094                         prop = elem->props[i];
1095
1096                         /* internal types will be same as external */
1097                         prop->internal_type = prop->external_type;
1098                         prop->count_internal = prop->count_external;
1099
1100                         /* check list case */
1101                         if (prop->is_list) {
1102
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 */
1107                                 }
1108
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];
1113                                 }
1114                         }
1115                         /* not list */
1116                         else if (type_size == ply_type_size[prop->external_type]) {
1117                                 prop->offset = size;
1118                                 size += ply_type_size[prop->external_type];
1119                         }
1120                 }
1121
1122         }
1123
1124         /* save the size for the other_props structure */
1125         elem->other_size = size;
1126 }
1127
1128
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.
1133
1134    Entry:
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
1138
1139    Exit:
1140    returns pointer to structure containing description of other_props
1141 ******************************************************************************/
1142
1143 PlyOtherProp *ply_get_other_properties(
1144     PlyFile *plyfile,
1145     char *elem_name,
1146     int offset
1147     )
1148 {
1149         int i;
1150         PlyElement *elem;
1151         PlyOtherProp *other;
1152         PlyProperty *prop;
1153         int nprops;
1154
1155         /* find information about the element */
1156         elem = find_element(plyfile, elem_name);
1157         if (elem == NULL) {
1158                 fprintf(stderr, "ply_get_other_properties: Can't find element '%s'\n",
1159                         elem_name);
1160                 return (NULL);
1161         }
1162
1163         /* remember that this is the "current" element */
1164         plyfile->which_elem = elem;
1165
1166         /* save the offset to where to store the other_props */
1167         elem->other_offset = offset;
1168
1169         /* place the appropriate pointers, etc. in the element's property list */
1170         setup_other_props(elem);
1171
1172         /* create structure for describing other_props */
1173         other = (PlyOtherProp *) myalloc(sizeof(PlyOtherProp));
1174         other->name = strdup(elem_name);
1175 #if 0
1176         if (elem->other_offset == NO_OTHER_PROPS) {
1177                 other->size = 0;
1178                 other->props = NULL;
1179                 other->nprops = 0;
1180                 return (other);
1181         }
1182 #endif
1183         other->size = elem->other_size;
1184         other->props = (PlyProperty **) myalloc(sizeof(PlyProperty) * elem->nprops);
1185   
1186         /* save descriptions of each "other" property */
1187         nprops = 0;
1188         for (i = 0; i < elem->nprops; i++) {
1189                 if (elem->store_prop[i])
1190                         continue;
1191                 prop = (PlyProperty *) myalloc(sizeof(PlyProperty));
1192                 copy_property(prop, elem->props[i]);
1193                 other->props[nprops] = prop;
1194                 nprops++;
1195         }
1196         other->nprops = nprops;
1197
1198 #if 1
1199         /* set other_offset pointer appropriately if there are NO other properties */
1200         if (other->nprops == 0) {
1201                 elem->other_offset = NO_OTHER_PROPS;
1202         }
1203 #endif
1204   
1205         /* return structure */
1206         return (other);
1207 }
1208
1209
1210
1211
1212 /*************************/
1213 /*  Other Element Stuff  */
1214 /*************************/
1215
1216
1217
1218
1219 /******************************************************************************
1220    Grab all the data for an element that a user does not want to explicitly
1221    read in.
1222
1223    Entry:
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
1227
1228    Exit:
1229    returns pointer to ALL the "other" element data for this PLY file
1230 ******************************************************************************/
1231
1232 PlyOtherElems *ply_get_other_element(
1233     PlyFile *plyfile,
1234     char *elem_name,
1235     int elem_count
1236     )
1237 {
1238         int i;
1239         PlyElement *elem;
1240         PlyOtherElems *other_elems;
1241         OtherElem *other;
1242
1243         /* look for appropriate element */
1244         elem = find_element(plyfile, elem_name);
1245         if (elem == NULL) {
1246                 fprintf(stderr,
1247                         "ply_get_other_element: can't find element '%s'\n", elem_name);
1248                 exit(-1);
1249         }
1250
1251         /* create room for the new "other" element, initializing the */
1252         /* other data structure if necessary */
1253
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;
1260         }
1261         else {
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++;
1267         }
1268
1269         /* count of element instances in file */
1270         other->elem_count = elem_count;
1271
1272         /* save name of element */
1273         other->elem_name = strdup(elem_name);
1274
1275         /* create a list to hold all the current elements */
1276         other->other_data = (OtherData **)
1277                             malloc(sizeof(OtherData *) * other->elem_count);
1278
1279         /* set up for getting elements */
1280         other->other_props = ply_get_other_properties(plyfile, elem_name,
1281                                                       offsetof(OtherData, other_props));
1282
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]);
1288         }
1289
1290         /* return pointer to the other elements data */
1291         return (other_elems);
1292 }
1293
1294
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.
1298
1299    Entry:
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 ******************************************************************************/
1303
1304 void ply_describe_other_elements(
1305     PlyFile *plyfile,
1306     PlyOtherElems *other_elems
1307     )
1308 {
1309         int i;
1310         OtherElem *other;
1311
1312         /* ignore this call if there is no other element */
1313         if (other_elems == NULL)
1314                 return;
1315
1316         /* save pointer to this information */
1317         plyfile->other_elems = other_elems;
1318
1319         /* describe the other properties of this element */
1320
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));
1326         }
1327 }
1328
1329
1330 /******************************************************************************
1331    Write out the "other" elements specified for this PLY file.
1332
1333    Entry:
1334    plyfile - pointer to PLY file to write out other elements for
1335 ******************************************************************************/
1336
1337 void ply_put_other_elements(PlyFile *plyfile)
1338 {
1339         int i, j;
1340         OtherElem *other;
1341
1342         /* make sure we have other elements to write */
1343         if (plyfile->other_elems == NULL)
1344                 return;
1345
1346         /* write out the data for each "other" element */
1347
1348         for (i = 0; i < plyfile->other_elems->num_elems; i++) {
1349
1350                 other = &(plyfile->other_elems->other_list[i]);
1351                 ply_put_element_setup(plyfile, other->elem_name);
1352
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]);
1356         }
1357 }
1358
1359
1360 /******************************************************************************
1361    Free up storage used by an "other" elements data structure.
1362
1363    Entry:
1364    other_elems - data structure to free up
1365 ******************************************************************************/
1366
1367
1368
1369
1370 /*******************/
1371 /*  Miscellaneous  */
1372 /*******************/
1373
1374
1375
1376 /******************************************************************************
1377    Close a PLY file.
1378
1379    Entry:
1380    plyfile - identifier of file to close
1381 ******************************************************************************/
1382
1383 void ply_close(PlyFile *plyfile)
1384 {
1385         fclose(plyfile->fp);
1386
1387         /* free up memory associated with the PLY file */
1388         free(plyfile);
1389 }
1390
1391
1392 /******************************************************************************
1393    Get version number and file type of a PlyFile.
1394
1395    Entry:
1396    ply - pointer to PLY file
1397
1398    Exit:
1399    version - version of the file
1400    file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
1401 ******************************************************************************/
1402
1403 void ply_get_info(PlyFile *ply, float *version, int *file_type)
1404 {
1405         if (ply == NULL)
1406                 return;
1407
1408         *version = ply->version;
1409         *file_type = ply->file_type;
1410 }
1411
1412
1413 /******************************************************************************
1414    Compare two strings.  Returns 1 if they are the same, 0 if not.
1415 ******************************************************************************/
1416
1417 int equal_strings(char *s1, char *s2)
1418 {
1419
1420         while (*s1 && *s2)
1421                 if (*s1++ != *s2++)
1422                         return (0);
1423
1424         if (*s1 != *s2)
1425                 return (0);
1426         else
1427                 return (1);
1428 }
1429
1430
1431 /******************************************************************************
1432    Find an element from the element list of a given PLY object.
1433
1434    Entry:
1435    plyfile - file id for PLY file
1436    element - name of element we're looking for
1437
1438    Exit:
1439    returns the element, or NULL if not found
1440 ******************************************************************************/
1441
1442 PlyElement *find_element(PlyFile *plyfile, char *element)
1443 {
1444         int i;
1445
1446         for (i = 0; i < plyfile->nelems; i++)
1447                 if (equal_strings(element, plyfile->elems[i]->name))
1448                         return (plyfile->elems[i]);
1449
1450         return (NULL);
1451 }
1452
1453
1454 /******************************************************************************
1455    Find a property in the list of properties of a given element.
1456
1457    Entry:
1458    elem      - pointer to element in which we want to find the property
1459    prop_name - name of property to find
1460
1461    Exit:
1462    index - index to position in list
1463    returns a pointer to the property, or NULL if not found
1464 ******************************************************************************/
1465
1466 PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index)
1467 {
1468         int i;
1469
1470         for (i = 0; i < elem->nprops; i++)
1471                 if (equal_strings(prop_name, elem->props[i]->name)) {
1472                         *index = i;
1473                         return (elem->props[i]);
1474                 }
1475
1476         *index = -1;
1477         return (NULL);
1478 }
1479
1480
1481 /******************************************************************************
1482    Read an element from an ascii file.
1483
1484    Entry:
1485    plyfile  - file identifier
1486    elem_ptr - pointer to element
1487 ******************************************************************************/
1488
1489 void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
1490 {
1491         int j, k;
1492         PlyElement *elem;
1493         PlyProperty *prop;
1494         char **words;
1495         int nwords;
1496         int which_word;
1497         char *elem_data, *item;
1498         char *item_ptr;
1499         int item_size;
1500         int int_val;
1501         unsigned int uint_val;
1502         double double_val;
1503         int list_count;
1504         int store_it;
1505         char **store_array;
1506         char *orig_line;
1507         char *other_data;
1508         int other_flag;
1509
1510         other_flag = 0;
1511         other_data = NULL;
1512         item = NULL;
1513         item_size = 0;
1514
1515         /* the kind of element we're reading currently */
1516         elem = plyfile->which_elem;
1517
1518         /* do we need to setup for other_props? */
1519
1520         if (elem->other_offset != NO_OTHER_PROPS) {
1521                 char **ptr;
1522                 other_flag = 1;
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);
1527                 *ptr = other_data;
1528         }
1529         else {
1530                 other_flag = 0;
1531                 other_data = NULL;
1532                 item = NULL;
1533                 item_size = 0;
1534         }
1535
1536         /* read in the element */
1537
1538         words = get_words(plyfile->fp, &nwords, &orig_line);
1539         if (words == NULL) {
1540                 fprintf(stderr, "ply_get_element: unexpected end of file\n");
1541                 exit(-1);
1542         }
1543
1544         which_word = 0;
1545
1546         for (j = 0; j < elem->nprops; j++) {
1547
1548                 prop = elem->props[j];
1549                 store_it = (elem->store_prop[j] | other_flag);
1550
1551                 /* store either in the user's structure or in other_props */
1552                 if (elem->store_prop[j])
1553                         elem_data = elem_ptr;
1554                 else
1555                         elem_data = other_data;
1556
1557                 if (prop->is_list) {   /* a list */
1558
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);
1562                         if (store_it) {
1563                                 item = elem_data + prop->count_offset;
1564                                 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1565                         }
1566
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);
1571
1572                         if (list_count == 0) {
1573                                 if (store_it)
1574                                         *store_array = NULL;
1575                         }
1576                         else {
1577                                 if (store_it) {
1578                                         item_ptr = (char *) myalloc(sizeof(char) * item_size * list_count);
1579                                         item = item_ptr;
1580                                         *store_array = item_ptr;
1581                                 }
1582
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);
1587                                         if (store_it) {
1588                                                 store_item(item, prop->internal_type,
1589                                                            int_val, uint_val, double_val);
1590                                                 item += item_size;
1591                                         }
1592                                 }
1593                         }
1594
1595                 }
1596                 else {                 /* not a list */
1597                         get_ascii_item(words[which_word++], prop->external_type,
1598                                        &int_val, &uint_val, &double_val);
1599                         if (store_it) {
1600                                 item = elem_data + prop->offset;
1601                                 store_item(item, prop->internal_type, int_val, uint_val, double_val);
1602                         }
1603                 }
1604
1605         }
1606
1607         free(words);
1608 }
1609
1610
1611 /******************************************************************************
1612    Read an element from a binary file.
1613
1614    Entry:
1615    plyfile  - file identifier
1616    elem_ptr - pointer to an element
1617 ******************************************************************************/
1618
1619 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
1620 {
1621         int j, k;
1622         PlyElement *elem;
1623         PlyProperty *prop;
1624         FILE *fp = plyfile->fp;
1625         char *elem_data, *item;
1626         char *item_ptr;
1627         int item_size;
1628         int int_val;
1629         unsigned int uint_val;
1630         double double_val;
1631         int list_count;
1632         int store_it;
1633         char **store_array;
1634         char *other_data;
1635         int other_flag;
1636
1637
1638         other_flag = 0;
1639         other_data = NULL;
1640         item = NULL;
1641         item_size = 0;
1642
1643         /* the kind of element we're reading currently */
1644         elem = plyfile->which_elem;
1645
1646         /* do we need to setup for other_props? */
1647
1648         if (elem->other_offset != NO_OTHER_PROPS) {
1649                 char **ptr;
1650                 other_flag = 1;
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);
1655                 *ptr = other_data;
1656         }
1657         else {
1658                 other_flag = 0;
1659                 other_data = NULL;
1660                 item = NULL;
1661                 item_size = 0;
1662         }
1663         /* read in a number of elements */
1664
1665         for (j = 0; j < elem->nprops; j++) {
1666
1667                 prop = elem->props[j];
1668                 store_it = (elem->store_prop[j] | other_flag);
1669
1670                 /* store either in the user's structure or in other_props */
1671                 if (elem->store_prop[j])
1672                         elem_data = elem_ptr;
1673                 else
1674                         elem_data = other_data;
1675
1676                 if (prop->is_list) {   /* a list */
1677
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);
1681                         if (store_it) {
1682                                 item = elem_data + prop->count_offset;
1683                                 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1684                         }
1685
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
1690                          * properties.
1691                          */
1692                         if (store_it) {
1693                                 item_size = ply_type_size[prop->internal_type];
1694                         }
1695                         store_array = (char **) (elem_data + prop->offset);
1696                         if (list_count == 0) {
1697                                 if (store_it)
1698                                         *store_array = NULL;
1699                         }
1700                         else {
1701                                 if (store_it) {
1702                                         item_ptr = (char *) myalloc(sizeof(char) * item_size * list_count);
1703                                         item = item_ptr;
1704                                         *store_array = item_ptr;
1705                                 }
1706
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);
1711                                         if (store_it) {
1712                                                 store_item(item, prop->internal_type,
1713                                                            int_val, uint_val, double_val);
1714                                                 item += item_size;
1715                                         }
1716                                 }
1717                         }
1718
1719                 }
1720                 else {                 /* not a list */
1721                         get_binary_item(fp, prop->external_type,
1722                                         &int_val, &uint_val, &double_val);
1723                         if (store_it) {
1724                                 item = elem_data + prop->offset;
1725                                 store_item(item, prop->internal_type, int_val, uint_val, double_val);
1726                         }
1727                 }
1728
1729         }
1730 }
1731
1732
1733 /******************************************************************************
1734    Write to a file the word that represents a PLY data type.
1735
1736    Entry:
1737    fp   - file pointer
1738    code - code for type
1739 ******************************************************************************/
1740
1741 void write_scalar_type(FILE *fp, int code)
1742 {
1743         /* make sure this is a valid code */
1744
1745         if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
1746                 fprintf(stderr, "write_scalar_type: bad data code = %d\n", code);
1747                 exit(-1);
1748         }
1749
1750         /* write the code to a file */
1751
1752         fprintf(fp, "%s", type_names[code]);
1753 }
1754
1755
1756 /******************************************************************************
1757    Get a text line from a file and break it up into words.
1758
1759    IMPORTANT: The calling routine call "free" on the returned pointer once
1760    finished with it.
1761
1762    Entry:
1763    fp - file to read from
1764
1765    Exit:
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 ******************************************************************************/
1770
1771 char **get_words(FILE *fp, int *nwords, char **orig_line)
1772 {
1773 #define BIG_STRING 4096
1774         static char str[BIG_STRING];
1775         static char str_copy[BIG_STRING];
1776         char **words;
1777         int max_words = 10;
1778         int num_words = 0;
1779         char *ptr, *ptr2;
1780         char *result;
1781
1782         words = (char **) myalloc(sizeof(char *) * max_words);
1783
1784         /* read in a line */
1785         result = fgets(str, BIG_STRING, fp);
1786         if (result == NULL) {
1787                 *nwords = 0;
1788                 *orig_line = NULL;
1789                 return (NULL);
1790         }
1791
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) */
1795
1796         str[BIG_STRING - 2] = ' ';
1797         str[BIG_STRING - 1] = '\0';
1798
1799         for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
1800                 *ptr2 = *ptr;
1801                 if (*ptr == '\t') {
1802                         *ptr = ' ';
1803                         *ptr2 = ' ';
1804                 }
1805                 else if (*ptr == '\n') {
1806                         *ptr = ' ';
1807                         *ptr2 = '\0';
1808                         break;
1809                 }
1810         }
1811
1812         /* find the words in the line */
1813
1814         ptr = str;
1815         while (*ptr != '\0') {
1816
1817                 /* jump over leading spaces */
1818                 while (*ptr == ' ')
1819                         ptr++;
1820
1821                 /* break if we reach the end */
1822                 if (*ptr == '\0')
1823                         break;
1824
1825                 /* save pointer to beginning of word */
1826                 if (num_words >= max_words) {
1827                         max_words += 10;
1828                         words = (char **) realloc(words, sizeof(char *) * max_words);
1829                 }
1830                 words[num_words++] = ptr;
1831
1832                 /* jump over non-spaces */
1833                 while (*ptr != ' ')
1834                         ptr++;
1835
1836                 /* place a null character here to mark the end of the word */
1837                 *ptr++ = '\0';
1838         }
1839
1840         /* return the list of words */
1841         *nwords = num_words;
1842         *orig_line = str_copy;
1843         return (words);
1844 }
1845
1846
1847 /******************************************************************************
1848    Return the value of an item, given a pointer to it and its type.
1849
1850    Entry:
1851    item - pointer to item
1852    type - data type that "item" points to
1853
1854    Exit:
1855    returns a double-precision float that contains the value of the item
1856 ******************************************************************************/
1857
1858 double get_item_value(char *item, int type)
1859 {
1860         unsigned char *puchar;
1861         char *pchar;
1862         short int *pshort;
1863         unsigned short int *pushort;
1864         int *pint;
1865         unsigned int *puint;
1866         float *pfloat;
1867         double *pdouble;
1868         int int_value;
1869         unsigned int uint_value;
1870         double double_value;
1871
1872         switch (type) {
1873                 case PLY_CHAR:
1874                         pchar = (char *) item;
1875                         int_value = *pchar;
1876                         return ((double) int_value);
1877                 case PLY_UCHAR:
1878                         puchar = (unsigned char *) item;
1879                         int_value = *puchar;
1880                         return ((double) int_value);
1881                 case PLY_SHORT:
1882                         pshort = (short int *) item;
1883                         int_value = *pshort;
1884                         return ((double) int_value);
1885                 case PLY_USHORT:
1886                         pushort = (unsigned short int *) item;
1887                         int_value = *pushort;
1888                         return ((double) int_value);
1889                 case PLY_INT:
1890                         pint = (int *) item;
1891                         int_value = *pint;
1892                         return ((double) int_value);
1893                 case PLY_UINT:
1894                         puint = (unsigned int *) item;
1895                         uint_value = *puint;
1896                         return ((double) uint_value);
1897                 case PLY_FLOAT:
1898                         pfloat = (float *) item;
1899                         double_value = *pfloat;
1900                         return (double_value);
1901                 case PLY_DOUBLE:
1902                         pdouble = (double *) item;
1903                         double_value = *pdouble;
1904                         return (double_value);
1905                 default:
1906                         fprintf(stderr, "get_item_value: bad type = %d\n", type);
1907                         exit(-1);
1908         }
1909 }
1910
1911
1912 /******************************************************************************
1913    Write out an item to a file as raw binary bytes.
1914
1915    Entry:
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 ******************************************************************************/
1922
1923 void write_binary_item(
1924     FILE *fp,
1925     int int_val,
1926     unsigned int uint_val,
1927     double double_val,
1928     int type
1929     )
1930 {
1931         unsigned char uchar_val;
1932         char char_val;
1933         unsigned short ushort_val;
1934         short short_val;
1935         float float_val;
1936
1937         switch (type) {
1938                 case PLY_CHAR:
1939                         char_val = (char)int_val;
1940                         fwrite(&char_val, 1, 1, fp);
1941                         break;
1942                 case PLY_SHORT:
1943                         short_val = (short)int_val;
1944                         fwrite(&short_val, 2, 1, fp);
1945                         break;
1946                 case PLY_INT:
1947                         fwrite(&int_val, 4, 1, fp);
1948                         break;
1949                 case PLY_UCHAR:
1950                         uchar_val = (unsigned char) uint_val;
1951                         fwrite(&uchar_val, 1, 1, fp);
1952                         break;
1953                 case PLY_USHORT:
1954                         ushort_val = (unsigned short)uint_val;
1955                         fwrite(&ushort_val, 2, 1, fp);
1956                         break;
1957                 case PLY_UINT:
1958                         fwrite(&uint_val, 4, 1, fp);
1959                         break;
1960                 case PLY_FLOAT:
1961                         float_val = (float) double_val;
1962                         fwrite(&float_val, 4, 1, fp);
1963                         break;
1964                 case PLY_DOUBLE:
1965                         fwrite(&double_val, 8, 1, fp);
1966                         break;
1967                 default:
1968                         fprintf(stderr, "write_binary_item: bad type = %d\n", type);
1969                         exit(-1);
1970         }
1971 }
1972
1973
1974 /******************************************************************************
1975    Write out an item to a file as ascii characters.
1976
1977    Entry:
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 ******************************************************************************/
1984
1985 void write_ascii_item(
1986     FILE *fp,
1987     int int_val,
1988     unsigned int uint_val,
1989     double double_val,
1990     int type
1991     )
1992 {
1993         switch (type) {
1994                 case PLY_CHAR:
1995                 case PLY_SHORT:
1996                 case PLY_INT:
1997                         fprintf(fp, "%d ", int_val);
1998                         break;
1999                 case PLY_UCHAR:
2000                 case PLY_USHORT:
2001                 case PLY_UINT:
2002                         fprintf(fp, "%u ", uint_val);
2003                         break;
2004                 case PLY_FLOAT:
2005                 case PLY_DOUBLE:
2006                         fprintf(fp, "%g ", double_val);
2007                         break;
2008                 default:
2009                         fprintf(stderr, "write_ascii_item: bad type = %d\n", type);
2010                         exit(-1);
2011         }
2012 }
2013
2014
2015 /******************************************************************************
2016    Write out an item to a file as ascii characters.
2017
2018    Entry:
2019    fp   - file to write to
2020    item - pointer to item to write
2021    type - data type that "item" points to
2022
2023    Exit:
2024    returns a double-precision float that contains the value of the written item
2025 ******************************************************************************/
2026
2027 double old_write_ascii_item(FILE *fp, char *item, int type)
2028 {
2029         unsigned char *puchar;
2030         char *pchar;
2031         short int *pshort;
2032         unsigned short int *pushort;
2033         int *pint;
2034         unsigned int *puint;
2035         float *pfloat;
2036         double *pdouble;
2037         int int_value;
2038         unsigned int uint_value;
2039         double double_value;
2040
2041         switch (type) {
2042                 case PLY_CHAR:
2043                         pchar = (char *) item;
2044                         int_value = *pchar;
2045                         fprintf(fp, "%d ", int_value);
2046                         return ((double) int_value);
2047                 case PLY_UCHAR:
2048                         puchar = (unsigned char *) item;
2049                         int_value = *puchar;
2050                         fprintf(fp, "%d ", int_value);
2051                         return ((double) int_value);
2052                 case PLY_SHORT:
2053                         pshort = (short int *) item;
2054                         int_value = *pshort;
2055                         fprintf(fp, "%d ", int_value);
2056                         return ((double) int_value);
2057                 case PLY_USHORT:
2058                         pushort = (unsigned short int *) item;
2059                         int_value = *pushort;
2060                         fprintf(fp, "%d ", int_value);
2061                         return ((double) int_value);
2062                 case PLY_INT:
2063                         pint = (int *) item;
2064                         int_value = *pint;
2065                         fprintf(fp, "%d ", int_value);
2066                         return ((double) int_value);
2067                 case PLY_UINT:
2068                         puint = (unsigned int *) item;
2069                         uint_value = *puint;
2070                         fprintf(fp, "%u ", uint_value);
2071                         return ((double) uint_value);
2072                 case PLY_FLOAT:
2073                         pfloat = (float *) item;
2074                         double_value = *pfloat;
2075                         fprintf(fp, "%g ", double_value);
2076                         return (double_value);
2077                 case PLY_DOUBLE:
2078                         pdouble = (double *) item;
2079                         double_value = *pdouble;
2080                         fprintf(fp, "%g ", double_value);
2081                         return (double_value);
2082                 default:
2083                         fprintf(stderr, "old_write_ascii_item: bad type = %d\n", type);
2084                         exit(-1);
2085         }
2086 }
2087
2088
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.
2092
2093    Entry:
2094    ptr  - pointer to the item
2095    type - data type supposedly in the item
2096
2097    Exit:
2098    int_val    - integer value
2099    uint_val   - unsigned integer value
2100    double_val - double-precision floating point value
2101 ******************************************************************************/
2102
2103 void get_stored_item(
2104     void *ptr,
2105     int type,
2106     int *int_val,
2107     unsigned int *uint_val,
2108     double *double_val
2109     )
2110 {
2111         switch (type) {
2112                 case PLY_CHAR:
2113                         *int_val = *((char *) ptr);
2114                         *uint_val = *int_val;
2115                         *double_val = *int_val;
2116                         break;
2117                 case PLY_UCHAR:
2118                         *uint_val = *((unsigned char *) ptr);
2119                         *int_val = *uint_val;
2120                         *double_val = *uint_val;
2121                         break;
2122                 case PLY_SHORT:
2123                         *int_val = *((short int *) ptr);
2124                         *uint_val = *int_val;
2125                         *double_val = *int_val;
2126                         break;
2127                 case PLY_USHORT:
2128                         *uint_val = *((unsigned short int *) ptr);
2129                         *int_val = *uint_val;
2130                         *double_val = *uint_val;
2131                         break;
2132                 case PLY_INT:
2133                         *int_val = *((int *) ptr);
2134                         *uint_val = *int_val;
2135                         *double_val = *int_val;
2136                         break;
2137                 case PLY_UINT:
2138                         *uint_val = *((unsigned int *) ptr);
2139                         *int_val = *uint_val;
2140                         *double_val = *uint_val;
2141                         break;
2142                 case PLY_FLOAT:
2143                         *double_val = *((float *) ptr);
2144                         *int_val = (int)*double_val;
2145                         *uint_val = (unsigned int)*double_val;
2146                         break;
2147                 case PLY_DOUBLE:
2148                         *double_val = *((double *) ptr);
2149                         *int_val = (int)*double_val;
2150                         *uint_val = (unsigned int) *double_val;
2151                         break;
2152                 default:
2153                         fprintf(stderr, "get_stored_item: bad type = %d\n", type);
2154                         exit(-1);
2155         }
2156 }
2157
2158
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.
2162
2163    Entry:
2164    fp   - file to get item from
2165    type - data type supposedly in the word
2166
2167    Exit:
2168    int_val    - integer value
2169    uint_val   - unsigned integer value
2170    double_val - double-precision floating point value
2171 ******************************************************************************/
2172
2173 void get_binary_item(
2174     FILE *fp,
2175     int type,
2176     int *int_val,
2177     unsigned int *uint_val,
2178     double *double_val
2179     )
2180 {
2181         char c[8];
2182         void *ptr;
2183
2184         ptr = (void *) c;
2185
2186         switch (type) {
2187                 case PLY_CHAR:
2188                         fread(ptr, 1, 1, fp);
2189                         *int_val = *((char *) ptr);
2190                         *uint_val = *int_val;
2191                         *double_val = *int_val;
2192                         break;
2193                 case PLY_UCHAR:
2194                         fread(ptr, 1, 1, fp);
2195                         *uint_val = *((unsigned char *) ptr);
2196                         *int_val = *uint_val;
2197                         *double_val = *uint_val;
2198                         break;
2199                 case PLY_SHORT:
2200                         fread(ptr, 2, 1, fp);
2201                         *int_val = *((short int *) ptr);
2202                         *uint_val = *int_val;
2203                         *double_val = *int_val;
2204                         break;
2205                 case PLY_USHORT:
2206                         fread(ptr, 2, 1, fp);
2207                         *uint_val = *((unsigned short int *) ptr);
2208                         *int_val = *uint_val;
2209                         *double_val = *uint_val;
2210                         break;
2211                 case PLY_INT:
2212                         fread(ptr, 4, 1, fp);
2213                         *int_val = *((int *) ptr);
2214                         *uint_val = *int_val;
2215                         *double_val = *int_val;
2216                         break;
2217                 case PLY_UINT:
2218                         fread(ptr, 4, 1, fp);
2219                         *uint_val = *((unsigned int *) ptr);
2220                         *int_val = *uint_val;
2221                         *double_val = *uint_val;
2222                         break;
2223                 case PLY_FLOAT:
2224                         fread(ptr, 4, 1, fp);
2225                         *double_val = *((float *) ptr);
2226                         *int_val = (int)*double_val;
2227                         *uint_val = (unsigned int) *double_val;
2228                         break;
2229                 case PLY_DOUBLE:
2230                         fread(ptr, 8, 1, fp);
2231                         *double_val = *((double *) ptr);
2232                         *int_val = (int)*double_val;
2233                         *uint_val = (unsigned int)*double_val;
2234                         break;
2235                 default:
2236                         fprintf(stderr, "get_binary_item: bad type = %d\n", type);
2237                         exit(-1);
2238         }
2239 }
2240
2241
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.
2245
2246    Entry:
2247    word - word to extract value from
2248    type - data type supposedly in the word
2249
2250    Exit:
2251    int_val    - integer value
2252    uint_val   - unsigned integer value
2253    double_val - double-precision floating point value
2254 ******************************************************************************/
2255
2256 void get_ascii_item(
2257     char *word,
2258     int type,
2259     int *int_val,
2260     unsigned int *uint_val,
2261     double *double_val
2262     )
2263 {
2264         switch (type) {
2265                 case PLY_CHAR:
2266                 case PLY_UCHAR:
2267                 case PLY_SHORT:
2268                 case PLY_USHORT:
2269                 case PLY_INT:
2270                         *int_val = atoi(word);
2271                         *uint_val = *int_val;
2272                         *double_val = *int_val;
2273                         break;
2274
2275                 case PLY_UINT:
2276                         *uint_val = strtoul(word, (char **) NULL, 10);
2277                         *int_val = *uint_val;
2278                         *double_val = *uint_val;
2279                         break;
2280
2281                 case PLY_FLOAT:
2282                 case PLY_DOUBLE:
2283                         *double_val = atof(word);
2284                         *int_val = (int) *double_val;
2285                         *uint_val = (unsigned int) *double_val;
2286                         break;
2287
2288                 default:
2289                         fprintf(stderr, "get_ascii_item: bad type = %d\n", type);
2290                         exit(-1);
2291         }
2292 }
2293
2294
2295 /******************************************************************************
2296    Store a value into a place being pointed to, guided by a data type.
2297
2298    Entry:
2299    item       - place to store value
2300    type       - data type
2301    int_val    - integer version of value
2302    uint_val   - unsigned integer version of value
2303    double_val - double version of value
2304
2305    Exit:
2306    item - pointer to stored value
2307 ******************************************************************************/
2308
2309 void store_item(
2310     char *item,
2311     int type,
2312     int int_val,
2313     unsigned int uint_val,
2314     double double_val
2315     )
2316 {
2317         unsigned char *puchar;
2318         short int *pshort;
2319         unsigned short int *pushort;
2320         int *pint;
2321         unsigned int *puint;
2322         float *pfloat;
2323         double *pdouble;
2324
2325         switch (type) {
2326                 case PLY_CHAR:
2327                         *item = (char) int_val;
2328                         break;
2329                 case PLY_UCHAR:
2330                         puchar = (unsigned char *) item;
2331                         *puchar = (unsigned char)uint_val;
2332                         break;
2333                 case PLY_SHORT:
2334                         pshort = (short *) item;
2335                         *pshort = (short)int_val;
2336                         break;
2337                 case PLY_USHORT:
2338                         pushort = (unsigned short *) item;
2339                         *pushort = (unsigned short)uint_val;
2340                         break;
2341                 case PLY_INT:
2342                         pint = (int *) item;
2343                         *pint = int_val;
2344                         break;
2345                 case PLY_UINT:
2346                         puint = (unsigned int *) item;
2347                         *puint = uint_val;
2348                         break;
2349                 case PLY_FLOAT:
2350                         pfloat = (float *) item;
2351                         *pfloat = (float)double_val;
2352                         break;
2353                 case PLY_DOUBLE:
2354                         pdouble = (double *) item;
2355                         *pdouble = double_val;
2356                         break;
2357                 default:
2358                         fprintf(stderr, "store_item: bad type = %d\n", type);
2359                         exit(-1);
2360         }
2361 }
2362
2363
2364 /******************************************************************************
2365    Add an element to a PLY file descriptor.
2366
2367    Entry:
2368    plyfile - PLY file descriptor
2369    words   - list of words describing the element
2370    nwords  - number of words in the list
2371 ******************************************************************************/
2372
2373 void add_element(PlyFile *plyfile, char **words)
2374 {
2375         PlyElement *elem;
2376
2377         /* create the new element */
2378         elem = (PlyElement *) myalloc(sizeof(PlyElement));
2379         elem->name = strdup(words[1]);
2380         elem->num = atoi(words[2]);
2381         elem->nprops = 0;
2382
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 *));
2386         else
2387                 plyfile->elems = (PlyElement **) realloc(plyfile->elems,
2388                                                          sizeof(PlyElement *) * (plyfile->nelems + 1));
2389
2390         /* add the new element to the object's list */
2391         plyfile->elems[plyfile->nelems] = elem;
2392         plyfile->nelems++;
2393 }
2394
2395
2396 /******************************************************************************
2397    Return the type of a property, given the name of the property.
2398
2399    Entry:
2400    name - name of property type
2401
2402    Exit:
2403    returns integer code for property, or 0 if not found
2404 ******************************************************************************/
2405
2406 int get_prop_type(char *type_name)
2407 {
2408         int i;
2409
2410         for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
2411                 if (equal_strings(type_name, type_names[i]))
2412                         return (i);
2413
2414         /* if we get here, we didn't find the type */
2415         return (0);
2416 }
2417
2418
2419 /******************************************************************************
2420    Add a property to a PLY file descriptor.
2421
2422    Entry:
2423    plyfile - PLY file descriptor
2424    words   - list of words describing the property
2425    nwords  - number of words in the list
2426 ******************************************************************************/
2427
2428 void add_property(PlyFile *plyfile, char **words)
2429 {
2430         PlyProperty *prop;
2431         PlyElement *elem;
2432
2433         /* create the new property */
2434
2435         prop = (PlyProperty *) myalloc(sizeof(PlyProperty));
2436
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]);
2441                 prop->is_list = 1;
2442         }
2443         else {                                      /* not a list */
2444                 prop->external_type = get_prop_type(words[1]);
2445                 prop->name = strdup(words[2]);
2446                 prop->is_list = 0;
2447         }
2448
2449         /* add this property to the list of properties of the current element */
2450
2451         elem = plyfile->elems[plyfile->nelems - 1];
2452
2453         if (elem->nprops == 0)
2454                 elem->props = (PlyProperty **) myalloc(sizeof(PlyProperty *));
2455         else
2456                 elem->props = (PlyProperty **) realloc(elem->props,
2457                                                        sizeof(PlyProperty *) * (elem->nprops + 1));
2458
2459         elem->props[elem->nprops] = prop;
2460         elem->nprops++;
2461 }
2462
2463
2464 /******************************************************************************
2465    Add a comment to a PLY file descriptor.
2466
2467    Entry:
2468    plyfile - PLY file descriptor
2469    line    - line containing comment
2470 ******************************************************************************/
2471
2472 void add_comment(PlyFile *plyfile, char *line)
2473 {
2474         int i;
2475
2476         /* skip over "comment" and leading spaces and tabs */
2477         i = 7;
2478         while (line[i] == ' ' || line[i] == '\t')
2479                 i++;
2480
2481         ply_put_comment(plyfile, &line[i]);
2482 }
2483
2484
2485 /******************************************************************************
2486    Add a some object information to a PLY file descriptor.
2487
2488    Entry:
2489    plyfile - PLY file descriptor
2490    line    - line containing text info
2491 ******************************************************************************/
2492
2493 void add_obj_info(PlyFile *plyfile, char *line)
2494 {
2495         int i;
2496
2497         /* skip over "obj_info" and leading spaces and tabs */
2498         i = 8;
2499         while (line[i] == ' ' || line[i] == '\t')
2500                 i++;
2501
2502         ply_put_obj_info(plyfile, &line[i]);
2503 }
2504
2505
2506 /******************************************************************************
2507    Copy a property.
2508 ******************************************************************************/
2509
2510 void copy_property(PlyProperty *dest, PlyProperty *src)
2511 {
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;
2516
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;
2521 }
2522
2523
2524 /******************************************************************************
2525    Allocate some memory.
2526
2527    Entry:
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 ******************************************************************************/
2532
2533 static char *my_alloc(int size, int lnum, char *fname)
2534 {
2535         char *ptr;
2536
2537         ptr = (char *) malloc(size);
2538
2539         if (ptr == 0) {
2540                 fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname);
2541         }
2542
2543         return (ptr);
2544 }
2545