9cb9d81da22f34394d4504e5f292612dd699b9f9
[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   } else {
1529     other_flag = 0;
1530         other_data = NULL;
1531         item = NULL;
1532         item_size = 0;
1533   }
1534
1535   /* read in the element */
1536
1537   words = get_words (plyfile->fp, &nwords, &orig_line);
1538   if (words == NULL) {
1539     fprintf (stderr, "ply_get_element: unexpected end of file\n");
1540     exit (-1);
1541   }
1542
1543   which_word = 0;
1544
1545   for (j = 0; j < elem->nprops; j++) {
1546
1547     prop = elem->props[j];
1548     store_it = (elem->store_prop[j] | other_flag);
1549
1550     /* store either in the user's structure or in other_props */
1551     if (elem->store_prop[j])
1552       elem_data = elem_ptr;
1553     else
1554       elem_data = other_data;
1555
1556     if (prop->is_list) {       /* a list */
1557
1558       /* get and store the number of items in the list */
1559       get_ascii_item (words[which_word++], prop->count_external,
1560                       &int_val, &uint_val, &double_val);
1561       if (store_it) {
1562         item = elem_data + prop->count_offset;
1563         store_item(item, prop->count_internal, int_val, uint_val, double_val);
1564       }
1565
1566       /* allocate space for an array of items and store a ptr to the array */
1567       list_count = int_val;
1568       item_size = ply_type_size[prop->internal_type];
1569       store_array = (char **) (elem_data + prop->offset);
1570
1571       if (list_count == 0) {
1572         if (store_it)
1573           *store_array = NULL;
1574       }
1575       else {
1576         if (store_it) {
1577           item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1578           item = item_ptr;
1579           *store_array = item_ptr;
1580         }
1581
1582         /* read items and store them into the array */
1583         for (k = 0; k < list_count; k++) {
1584           get_ascii_item (words[which_word++], prop->external_type,
1585                           &int_val, &uint_val, &double_val);
1586           if (store_it) {
1587             store_item (item, prop->internal_type,
1588                         int_val, uint_val, double_val);
1589             item += item_size;
1590           }
1591         }
1592       }
1593
1594     }
1595     else {                     /* not a list */
1596       get_ascii_item (words[which_word++], prop->external_type,
1597                       &int_val, &uint_val, &double_val);
1598       if (store_it) {
1599         item = elem_data + prop->offset;
1600         store_item (item, prop->internal_type, int_val, uint_val, double_val);
1601       }
1602     }
1603
1604   }
1605
1606   free (words);
1607 }
1608
1609
1610 /******************************************************************************
1611 Read an element from a binary file.
1612
1613 Entry:
1614   plyfile  - file identifier
1615   elem_ptr - pointer to an element
1616 ******************************************************************************/
1617
1618 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
1619 {
1620   int j,k;
1621   PlyElement *elem;
1622   PlyProperty *prop;
1623   FILE *fp = plyfile->fp;
1624   char *elem_data,*item;
1625   char *item_ptr;
1626   int item_size;
1627   int int_val;
1628   unsigned int uint_val;
1629   double double_val;
1630   int list_count;
1631   int store_it;
1632   char **store_array;
1633   char *other_data;
1634   int other_flag;
1635
1636
1637   other_flag = 0;
1638   other_data = NULL;
1639   item = NULL;
1640   item_size = 0;
1641
1642   /* the kind of element we're reading currently */
1643   elem = plyfile->which_elem;
1644
1645   /* do we need to setup for other_props? */
1646
1647   if (elem->other_offset != NO_OTHER_PROPS) {
1648     char **ptr;
1649     other_flag = 1;
1650     /* make room for other_props */
1651     other_data = (char *) myalloc (elem->other_size);
1652     /* store pointer in user's structure to the other_props */
1653     ptr = (char **) (elem_ptr + elem->other_offset);
1654     *ptr = other_data;
1655   }
1656   else {
1657     other_flag = 0;
1658         other_data = NULL;
1659         item = NULL;
1660         item_size = 0;
1661   }
1662   /* read in a number of elements */
1663
1664   for (j = 0; j < elem->nprops; j++) {
1665
1666     prop = elem->props[j];
1667     store_it = (elem->store_prop[j] | other_flag);
1668
1669     /* store either in the user's structure or in other_props */
1670     if (elem->store_prop[j])
1671       elem_data = elem_ptr;
1672     else
1673       elem_data = other_data;
1674
1675     if (prop->is_list) {       /* a list */
1676
1677       /* get and store the number of items in the list */
1678       get_binary_item (fp, prop->count_external,
1679                       &int_val, &uint_val, &double_val);
1680       if (store_it) {
1681         item = elem_data + prop->count_offset;
1682         store_item(item, prop->count_internal, int_val, uint_val, double_val);
1683       }
1684
1685       /* allocate space for an array of items and store a ptr to the array */
1686       list_count = int_val;
1687       /* The "if" was added by Afra Zomorodian 8/22/95
1688        * so that zipper won't crash reading plies that have additional
1689        * properties.
1690        */ 
1691       if (store_it) {
1692         item_size = ply_type_size[prop->internal_type];
1693       }
1694       store_array = (char **) (elem_data + prop->offset);
1695       if (list_count == 0) {
1696         if (store_it)
1697           *store_array = NULL;
1698       }
1699       else {
1700         if (store_it) {
1701           item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1702           item = item_ptr;
1703           *store_array = item_ptr;
1704         }
1705
1706         /* read items and store them into the array */
1707         for (k = 0; k < list_count; k++) {
1708           get_binary_item (fp, prop->external_type,
1709                           &int_val, &uint_val, &double_val);
1710           if (store_it) {
1711             store_item (item, prop->internal_type,
1712                         int_val, uint_val, double_val);
1713             item += item_size;
1714           }
1715         }
1716       }
1717
1718     }
1719     else {                     /* not a list */
1720       get_binary_item (fp, prop->external_type,
1721                       &int_val, &uint_val, &double_val);
1722       if (store_it) {
1723         item = elem_data + prop->offset;
1724         store_item (item, prop->internal_type, int_val, uint_val, double_val);
1725       }
1726     }
1727
1728   }
1729 }
1730
1731
1732 /******************************************************************************
1733 Write to a file the word that represents a PLY data type.
1734
1735 Entry:
1736   fp   - file pointer
1737   code - code for type
1738 ******************************************************************************/
1739
1740 void write_scalar_type (FILE *fp, int code)
1741 {
1742   /* make sure this is a valid code */
1743
1744   if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
1745     fprintf (stderr, "write_scalar_type: bad data code = %d\n", code);
1746     exit (-1);
1747   }
1748
1749   /* write the code to a file */
1750
1751   fprintf (fp, "%s", type_names[code]);
1752 }
1753
1754
1755 /******************************************************************************
1756 Get a text line from a file and break it up into words.
1757
1758 IMPORTANT: The calling routine call "free" on the returned pointer once
1759 finished with it.
1760
1761 Entry:
1762   fp - file to read from
1763
1764 Exit:
1765   nwords    - number of words returned
1766   orig_line - the original line of characters
1767   returns a list of words from the line, or NULL if end-of-file
1768 ******************************************************************************/
1769
1770 char **get_words(FILE *fp, int *nwords, char **orig_line)
1771 {
1772 #define BIG_STRING 4096
1773   static char str[BIG_STRING];
1774   static char str_copy[BIG_STRING];
1775   char **words;
1776   int max_words = 10;
1777   int num_words = 0;
1778   char *ptr,*ptr2;
1779   char *result;
1780
1781   words = (char **) myalloc (sizeof (char *) * max_words);
1782
1783   /* read in a line */
1784   result = fgets (str, BIG_STRING, fp);
1785   if (result == NULL) {
1786     *nwords = 0;
1787     *orig_line = NULL;
1788     return (NULL);
1789   }
1790
1791   /* convert line-feed and tabs into spaces */
1792   /* (this guarentees that there will be a space before the */
1793   /*  null character at the end of the string) */
1794
1795   str[BIG_STRING-2] = ' ';
1796   str[BIG_STRING-1] = '\0';
1797
1798   for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
1799     *ptr2 = *ptr;
1800     if (*ptr == '\t') {
1801       *ptr = ' ';
1802       *ptr2 = ' ';
1803     }
1804     else if (*ptr == '\n') {
1805       *ptr = ' ';
1806       *ptr2 = '\0';
1807       break;
1808     }
1809   }
1810
1811   /* find the words in the line */
1812
1813   ptr = str;
1814   while (*ptr != '\0') {
1815
1816     /* jump over leading spaces */
1817     while (*ptr == ' ')
1818       ptr++;
1819
1820     /* break if we reach the end */
1821     if (*ptr == '\0')
1822       break;
1823
1824     /* save pointer to beginning of word */
1825     if (num_words >= max_words) {
1826       max_words += 10;
1827       words = (char **) realloc (words, sizeof (char *) * max_words);
1828     }
1829     words[num_words++] = ptr;
1830
1831     /* jump over non-spaces */
1832     while (*ptr != ' ')
1833       ptr++;
1834
1835     /* place a null character here to mark the end of the word */
1836     *ptr++ = '\0';
1837   }
1838
1839   /* return the list of words */
1840   *nwords = num_words;
1841   *orig_line = str_copy;
1842   return (words);
1843 }
1844
1845
1846 /******************************************************************************
1847 Return the value of an item, given a pointer to it and its type.
1848
1849 Entry:
1850   item - pointer to item
1851   type - data type that "item" points to
1852
1853 Exit:
1854   returns a double-precision float that contains the value of the item
1855 ******************************************************************************/
1856
1857 double get_item_value(char *item, int type)
1858 {
1859   unsigned char *puchar;
1860   char *pchar;
1861   short int *pshort;
1862   unsigned short int *pushort;
1863   int *pint;
1864   unsigned int *puint;
1865   float *pfloat;
1866   double *pdouble;
1867   int int_value;
1868   unsigned int uint_value;
1869   double double_value;
1870
1871   switch (type) {
1872     case PLY_CHAR:
1873       pchar = (char *) item;
1874       int_value = *pchar;
1875       return ((double) int_value);
1876     case PLY_UCHAR:
1877       puchar = (unsigned char *) item;
1878       int_value = *puchar;
1879       return ((double) int_value);
1880     case PLY_SHORT:
1881       pshort = (short int *) item;
1882       int_value = *pshort;
1883       return ((double) int_value);
1884     case PLY_USHORT:
1885       pushort = (unsigned short int *) item;
1886       int_value = *pushort;
1887       return ((double) int_value);
1888     case PLY_INT:
1889       pint = (int *) item;
1890       int_value = *pint;
1891       return ((double) int_value);
1892     case PLY_UINT:
1893       puint = (unsigned int *) item;
1894       uint_value = *puint;
1895       return ((double) uint_value);
1896     case PLY_FLOAT:
1897       pfloat = (float *) item;
1898       double_value = *pfloat;
1899       return (double_value);
1900     case PLY_DOUBLE:
1901       pdouble = (double *) item;
1902       double_value = *pdouble;
1903       return (double_value);
1904     default:
1905       fprintf (stderr, "get_item_value: bad type = %d\n", type);
1906       exit (-1);
1907   }
1908 }
1909
1910
1911 /******************************************************************************
1912 Write out an item to a file as raw binary bytes.
1913
1914 Entry:
1915   fp         - file to write to
1916   int_val    - integer version of item
1917   uint_val   - unsigned integer version of item
1918   double_val - double-precision float version of item
1919   type       - data type to write out
1920 ******************************************************************************/
1921
1922 void write_binary_item(
1923   FILE *fp,
1924   int int_val,
1925   unsigned int uint_val,
1926   double double_val,
1927   int type
1928 )
1929 {
1930   unsigned char uchar_val;
1931   char char_val;
1932   unsigned short ushort_val;
1933   short short_val;
1934   float float_val;
1935
1936   switch (type) {
1937     case PLY_CHAR:
1938       char_val = (char)int_val;
1939       fwrite (&char_val, 1, 1, fp);
1940       break;
1941     case PLY_SHORT:
1942       short_val = (short)int_val;
1943       fwrite (&short_val, 2, 1, fp);
1944       break;
1945     case PLY_INT:
1946       fwrite (&int_val, 4, 1, fp);
1947       break;
1948     case PLY_UCHAR:
1949       uchar_val = (unsigned char) uint_val;
1950       fwrite (&uchar_val, 1, 1, fp);
1951       break;
1952     case PLY_USHORT:
1953       ushort_val = (unsigned short)uint_val;
1954       fwrite (&ushort_val, 2, 1, fp);
1955       break;
1956     case PLY_UINT:
1957       fwrite (&uint_val, 4, 1, fp);
1958       break;
1959     case PLY_FLOAT:
1960       float_val = (float) double_val;
1961       fwrite (&float_val, 4, 1, fp);
1962       break;
1963     case PLY_DOUBLE:
1964       fwrite (&double_val, 8, 1, fp);
1965       break;
1966     default:
1967       fprintf (stderr, "write_binary_item: bad type = %d\n", type);
1968       exit (-1);
1969   }
1970 }
1971
1972
1973 /******************************************************************************
1974 Write out an item to a file as ascii characters.
1975
1976 Entry:
1977   fp         - file to write to
1978   int_val    - integer version of item
1979   uint_val   - unsigned integer version of item
1980   double_val - double-precision float version of item
1981   type       - data type to write out
1982 ******************************************************************************/
1983
1984 void write_ascii_item(
1985   FILE *fp,
1986   int int_val,
1987   unsigned int uint_val,
1988   double double_val,
1989   int type
1990 )
1991 {
1992   switch (type) {
1993     case PLY_CHAR:
1994     case PLY_SHORT:
1995     case PLY_INT:
1996       fprintf (fp, "%d ", int_val);
1997       break;
1998     case PLY_UCHAR:
1999     case PLY_USHORT:
2000     case PLY_UINT:
2001       fprintf (fp, "%u ", uint_val);
2002       break;
2003     case PLY_FLOAT:
2004     case PLY_DOUBLE:
2005       fprintf (fp, "%g ", double_val);
2006       break;
2007     default:
2008       fprintf (stderr, "write_ascii_item: bad type = %d\n", type);
2009       exit (-1);
2010   }
2011 }
2012
2013
2014 /******************************************************************************
2015 Write out an item to a file as ascii characters.
2016
2017 Entry:
2018   fp   - file to write to
2019   item - pointer to item to write
2020   type - data type that "item" points to
2021
2022 Exit:
2023   returns a double-precision float that contains the value of the written item
2024 ******************************************************************************/
2025
2026 double old_write_ascii_item(FILE *fp, char *item, int type)
2027 {
2028   unsigned char *puchar;
2029   char *pchar;
2030   short int *pshort;
2031   unsigned short int *pushort;
2032   int *pint;
2033   unsigned int *puint;
2034   float *pfloat;
2035   double *pdouble;
2036   int int_value;
2037   unsigned int uint_value;
2038   double double_value;
2039
2040   switch (type) {
2041     case PLY_CHAR:
2042       pchar = (char *) item;
2043       int_value = *pchar;
2044       fprintf (fp, "%d ", int_value);
2045       return ((double) int_value);
2046     case PLY_UCHAR:
2047       puchar = (unsigned char *) item;
2048       int_value = *puchar;
2049       fprintf (fp, "%d ", int_value);
2050       return ((double) int_value);
2051     case PLY_SHORT:
2052       pshort = (short int *) item;
2053       int_value = *pshort;
2054       fprintf (fp, "%d ", int_value);
2055       return ((double) int_value);
2056     case PLY_USHORT:
2057       pushort = (unsigned short int *) item;
2058       int_value = *pushort;
2059       fprintf (fp, "%d ", int_value);
2060       return ((double) int_value);
2061     case PLY_INT:
2062       pint = (int *) item;
2063       int_value = *pint;
2064       fprintf (fp, "%d ", int_value);
2065       return ((double) int_value);
2066     case PLY_UINT:
2067       puint = (unsigned int *) item;
2068       uint_value = *puint;
2069       fprintf (fp, "%u ", uint_value);
2070       return ((double) uint_value);
2071     case PLY_FLOAT:
2072       pfloat = (float *) item;
2073       double_value = *pfloat;
2074       fprintf (fp, "%g ", double_value);
2075       return (double_value);
2076     case PLY_DOUBLE:
2077       pdouble = (double *) item;
2078       double_value = *pdouble;
2079       fprintf (fp, "%g ", double_value);
2080       return (double_value);
2081     default:
2082       fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type);
2083       exit (-1);
2084   }
2085 }
2086
2087
2088 /******************************************************************************
2089 Get the value of an item that is in memory, and place the result
2090 into an integer, an unsigned integer and a double.
2091
2092 Entry:
2093   ptr  - pointer to the item
2094   type - data type supposedly in the item
2095
2096 Exit:
2097   int_val    - integer value
2098   uint_val   - unsigned integer value
2099   double_val - double-precision floating point value
2100 ******************************************************************************/
2101
2102 void get_stored_item(
2103   void *ptr,
2104   int type,
2105   int *int_val,
2106   unsigned int *uint_val,
2107   double *double_val
2108 )
2109 {
2110   switch (type) {
2111     case PLY_CHAR:
2112       *int_val = *((char *) ptr);
2113       *uint_val = *int_val;
2114       *double_val = *int_val;
2115       break;
2116     case PLY_UCHAR:
2117       *uint_val = *((unsigned char *) ptr);
2118       *int_val = *uint_val;
2119       *double_val = *uint_val;
2120       break;
2121     case PLY_SHORT:
2122       *int_val = *((short int *) ptr);
2123       *uint_val = *int_val;
2124       *double_val = *int_val;
2125       break;
2126     case PLY_USHORT:
2127       *uint_val = *((unsigned short int *) ptr);
2128       *int_val = *uint_val;
2129       *double_val = *uint_val;
2130       break;
2131     case PLY_INT:
2132       *int_val = *((int *) ptr);
2133       *uint_val = *int_val;
2134       *double_val = *int_val;
2135       break;
2136     case PLY_UINT:
2137       *uint_val = *((unsigned int *) ptr);
2138       *int_val = *uint_val;
2139       *double_val = *uint_val;
2140       break;
2141     case PLY_FLOAT:
2142       *double_val = *((float *) ptr);
2143       *int_val = (int)*double_val;
2144       *uint_val = (unsigned int)*double_val;
2145       break;
2146     case PLY_DOUBLE:
2147       *double_val = *((double *) ptr);
2148       *int_val = (int)*double_val;
2149       *uint_val =(unsigned int) *double_val;
2150       break;
2151     default:
2152       fprintf (stderr, "get_stored_item: bad type = %d\n", type);
2153       exit (-1);
2154   }
2155 }
2156
2157
2158 /******************************************************************************
2159 Get the value of an item from a binary file, and place the result
2160 into an integer, an unsigned integer and a double.
2161
2162 Entry:
2163   fp   - file to get item from
2164   type - data type supposedly in the word
2165
2166 Exit:
2167   int_val    - integer value
2168   uint_val   - unsigned integer value
2169   double_val - double-precision floating point value
2170 ******************************************************************************/
2171
2172 void get_binary_item(
2173   FILE *fp,
2174   int type,
2175   int *int_val,
2176   unsigned int *uint_val,
2177   double *double_val
2178 )
2179 {
2180   char c[8];
2181   void *ptr;
2182
2183   ptr = (void *) c;
2184
2185   switch (type) {
2186     case PLY_CHAR:
2187       fread (ptr, 1, 1, fp);
2188       *int_val = *((char *) ptr);
2189       *uint_val = *int_val;
2190       *double_val = *int_val;
2191       break;
2192     case PLY_UCHAR:
2193       fread (ptr, 1, 1, fp);
2194       *uint_val = *((unsigned char *) ptr);
2195       *int_val = *uint_val;
2196       *double_val = *uint_val;
2197       break;
2198     case PLY_SHORT:
2199       fread (ptr, 2, 1, fp);
2200       *int_val = *((short int *) ptr);
2201       *uint_val = *int_val;
2202       *double_val = *int_val;
2203       break;
2204     case PLY_USHORT:
2205       fread (ptr, 2, 1, fp);
2206       *uint_val = *((unsigned short int *) ptr);
2207       *int_val = *uint_val;
2208       *double_val = *uint_val;
2209       break;
2210     case PLY_INT:
2211       fread (ptr, 4, 1, fp);
2212       *int_val = *((int *) ptr);
2213       *uint_val = *int_val;
2214       *double_val = *int_val;
2215       break;
2216     case PLY_UINT:
2217       fread (ptr, 4, 1, fp);
2218       *uint_val = *((unsigned int *) ptr);
2219       *int_val = *uint_val;
2220       *double_val = *uint_val;
2221       break;
2222     case PLY_FLOAT:
2223       fread (ptr, 4, 1, fp);
2224       *double_val = *((float *) ptr);
2225       *int_val = (int)*double_val;
2226       *uint_val =(unsigned int) *double_val;
2227       break;
2228     case PLY_DOUBLE:
2229       fread (ptr, 8, 1, fp);
2230       *double_val = *((double *) ptr);
2231       *int_val = (int)*double_val;
2232       *uint_val = (unsigned int)*double_val;
2233       break;
2234     default:
2235       fprintf (stderr, "get_binary_item: bad type = %d\n", type);
2236       exit (-1);
2237   }
2238 }
2239
2240
2241 /******************************************************************************
2242 Extract the value of an item from an ascii word, and place the result
2243 into an integer, an unsigned integer and a double.
2244
2245 Entry:
2246   word - word to extract value from
2247   type - data type supposedly in the word
2248
2249 Exit:
2250   int_val    - integer value
2251   uint_val   - unsigned integer value
2252   double_val - double-precision floating point value
2253 ******************************************************************************/
2254
2255 void get_ascii_item(
2256   char *word,
2257   int type,
2258   int *int_val,
2259   unsigned int *uint_val,
2260   double *double_val
2261 )
2262 {
2263   switch (type) {
2264     case PLY_CHAR:
2265     case PLY_UCHAR:
2266     case PLY_SHORT:
2267     case PLY_USHORT:
2268     case PLY_INT:
2269       *int_val = atoi (word);
2270       *uint_val = *int_val;
2271       *double_val = *int_val;
2272       break;
2273
2274     case PLY_UINT:
2275       *uint_val = strtoul (word, (char **) NULL, 10);
2276       *int_val = *uint_val;
2277       *double_val = *uint_val;
2278       break;
2279
2280     case PLY_FLOAT:
2281     case PLY_DOUBLE:
2282       *double_val = atof (word);
2283       *int_val = (int) *double_val;
2284       *uint_val = (unsigned int) *double_val;
2285       break;
2286
2287     default:
2288       fprintf (stderr, "get_ascii_item: bad type = %d\n", type);
2289       exit (-1);
2290   }
2291 }
2292
2293
2294 /******************************************************************************
2295 Store a value into a place being pointed to, guided by a data type.
2296
2297 Entry:
2298   item       - place to store value
2299   type       - data type
2300   int_val    - integer version of value
2301   uint_val   - unsigned integer version of value
2302   double_val - double version of value
2303
2304 Exit:
2305   item - pointer to stored value
2306 ******************************************************************************/
2307
2308 void store_item (
2309   char *item,
2310   int type,
2311   int int_val,
2312   unsigned int uint_val,
2313   double double_val
2314 )
2315 {
2316   unsigned char *puchar;
2317   short int *pshort;
2318   unsigned short int *pushort;
2319   int *pint;
2320   unsigned int *puint;
2321   float *pfloat;
2322   double *pdouble;
2323
2324   switch (type) {
2325     case PLY_CHAR:
2326       *item = (char) int_val;
2327       break;
2328     case PLY_UCHAR:
2329       puchar = (unsigned char *) item;
2330       *puchar = (unsigned char)uint_val;
2331       break;
2332     case PLY_SHORT:
2333       pshort = (short *) item;
2334       *pshort = (short)int_val;
2335       break;
2336     case PLY_USHORT:
2337       pushort = (unsigned short *) item;
2338       *pushort = (unsigned short)uint_val;
2339       break;
2340     case PLY_INT:
2341       pint = (int *) item;
2342       *pint = int_val;
2343       break;
2344     case PLY_UINT:
2345       puint = (unsigned int *) item;
2346       *puint = uint_val;
2347       break;
2348     case PLY_FLOAT:
2349       pfloat = (float *) item;
2350       *pfloat = (float)double_val;
2351       break;
2352     case PLY_DOUBLE:
2353       pdouble = (double *) item;
2354       *pdouble = double_val;
2355       break;
2356     default:
2357       fprintf (stderr, "store_item: bad type = %d\n", type);
2358       exit (-1);
2359   }
2360 }
2361
2362
2363 /******************************************************************************
2364 Add an element to a PLY file descriptor.
2365
2366 Entry:
2367   plyfile - PLY file descriptor
2368   words   - list of words describing the element
2369   nwords  - number of words in the list
2370 ******************************************************************************/
2371
2372 void add_element (PlyFile *plyfile, char **words)
2373 {
2374   PlyElement *elem;
2375
2376   /* create the new element */
2377   elem = (PlyElement *) myalloc (sizeof (PlyElement));
2378   elem->name = strdup (words[1]);
2379   elem->num = atoi (words[2]);
2380   elem->nprops = 0;
2381
2382   /* make room for new element in the object's list of elements */
2383   if (plyfile->nelems == 0)
2384     plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
2385   else
2386     plyfile->elems = (PlyElement **) realloc (plyfile->elems,
2387                      sizeof (PlyElement *) * (plyfile->nelems + 1));
2388
2389   /* add the new element to the object's list */
2390   plyfile->elems[plyfile->nelems] = elem;
2391   plyfile->nelems++;
2392 }
2393
2394
2395 /******************************************************************************
2396 Return the type of a property, given the name of the property.
2397
2398 Entry:
2399   name - name of property type
2400
2401 Exit:
2402   returns integer code for property, or 0 if not found
2403 ******************************************************************************/
2404
2405 int get_prop_type(char *type_name)
2406 {
2407   int i;
2408
2409   for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
2410     if (equal_strings (type_name, type_names[i]))
2411       return (i);
2412
2413   /* if we get here, we didn't find the type */
2414   return (0);
2415 }
2416
2417
2418 /******************************************************************************
2419 Add a property to a PLY file descriptor.
2420
2421 Entry:
2422   plyfile - PLY file descriptor
2423   words   - list of words describing the property
2424   nwords  - number of words in the list
2425 ******************************************************************************/
2426
2427 void add_property (PlyFile *plyfile, char **words)
2428 {
2429   PlyProperty *prop;
2430   PlyElement *elem;
2431
2432   /* create the new property */
2433
2434   prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
2435
2436   if (equal_strings (words[1], "list")) {       /* is a list */
2437     prop->count_external = get_prop_type (words[2]);
2438     prop->external_type = get_prop_type (words[3]);
2439     prop->name = strdup (words[4]);
2440     prop->is_list = 1;
2441   }
2442   else {                                        /* not a list */
2443     prop->external_type = get_prop_type (words[1]);
2444     prop->name = strdup (words[2]);
2445     prop->is_list = 0;
2446   }
2447
2448   /* add this property to the list of properties of the current element */
2449
2450   elem = plyfile->elems[plyfile->nelems - 1];
2451
2452   if (elem->nprops == 0)
2453     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
2454   else
2455     elem->props = (PlyProperty **) realloc (elem->props,
2456                   sizeof (PlyProperty *) * (elem->nprops + 1));
2457
2458   elem->props[elem->nprops] = prop;
2459   elem->nprops++;
2460 }
2461
2462
2463 /******************************************************************************
2464 Add a comment to a PLY file descriptor.
2465
2466 Entry:
2467   plyfile - PLY file descriptor
2468   line    - line containing comment
2469 ******************************************************************************/
2470
2471 void add_comment (PlyFile *plyfile, char *line)
2472 {
2473   int i;
2474
2475   /* skip over "comment" and leading spaces and tabs */
2476   i = 7;
2477   while (line[i] == ' ' || line[i] == '\t')
2478     i++;
2479
2480   ply_put_comment (plyfile, &line[i]);
2481 }
2482
2483
2484 /******************************************************************************
2485 Add a some object information to a PLY file descriptor.
2486
2487 Entry:
2488   plyfile - PLY file descriptor
2489   line    - line containing text info
2490 ******************************************************************************/
2491
2492 void add_obj_info (PlyFile *plyfile, char *line)
2493 {
2494   int i;
2495
2496   /* skip over "obj_info" and leading spaces and tabs */
2497   i = 8;
2498   while (line[i] == ' ' || line[i] == '\t')
2499     i++;
2500
2501   ply_put_obj_info (plyfile, &line[i]);
2502 }
2503
2504
2505 /******************************************************************************
2506 Copy a property.
2507 ******************************************************************************/
2508
2509 void copy_property(PlyProperty *dest, PlyProperty *src)
2510 {
2511   dest->name = strdup (src->name);
2512   dest->external_type = src->external_type;
2513   dest->internal_type = src->internal_type;
2514   dest->offset = src->offset;
2515
2516   dest->is_list = src->is_list;
2517   dest->count_external = src->count_external;
2518   dest->count_internal = src->count_internal;
2519   dest->count_offset = src->count_offset;
2520 }
2521
2522
2523 /******************************************************************************
2524 Allocate some memory.
2525
2526 Entry:
2527   size  - amount of memory requested (in bytes)
2528   lnum  - line number from which memory was requested
2529   fname - file name from which memory was requested
2530 ******************************************************************************/
2531
2532 static char *my_alloc(int size, int lnum, char *fname)
2533 {
2534   char *ptr;
2535
2536   ptr = (char *) malloc (size);
2537
2538   if (ptr == 0) {
2539     fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname);
2540   }
2541
2542   return (ptr);
2543 }
2544