source: GTP/trunk/Lib/Vis/Preprocessing/src/plyfile.c @ 749

Revision 749, 72.7 KB checked in by bittner, 18 years ago (diff)

ply parser support

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