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