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