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