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