plyfile.cpp

00001 /* Copyright (c) 2005-2007, Stefan Eilemann <eile@equalizergraphics.com> 
00002    All rights reserved.
00003    - Cleaned up code for 64 bit, little and big endian support
00004    - Added new ply data types (uint8, float32, int32)
00005  */
00006 
00007 /*
00008 
00009 The interface routines for reading and writing PLY polygon files.
00010 
00011 Greg Turk, February 1994
00012 
00013 ---------------------------------------------------------------
00014 
00015 A PLY file contains a single polygonal _object_.
00016 
00017 An object is composed of lists of _elements_.  Typical elements are
00018 vertices, faces, edges and materials.
00019 
00020 Each type of element for a given object has one or more _properties_
00021 associated with the element type.  For instance, a vertex element may
00022 have as properties the floating-point values x,y,z and the three unsigned
00023 chars representing red, green and blue.
00024 
00025 ---------------------------------------------------------------
00026 
00027 Copyright (c) 1994 The Board of Trustees of The Leland Stanford
00028 Junior University.  All rights reserved.   
00029   
00030 Permission to use, copy, modify and distribute this software and its   
00031 documentation for any purpose is hereby granted without fee, provided   
00032 that the above copyright notice and this permission notice appear in   
00033 all copies of this software and that you do not sell the software.   
00034   
00035 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,   
00036 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY   
00037 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   
00038 
00039 */
00040 
00041 #include "ply.h"
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <math.h>
00045 #include <string.h>
00046 
00047 const char *type_names[] = {
00048     "invalid",
00049     "char", "short", "int",
00050     "uchar", "ushort", "uint",
00051     "float", "double", "float32", "uint8", "int32"
00052 };
00053 
00054 int ply_type_size[] = {
00055     0, 1, 2, 4, 1, 2, 4, 4, 8, 4, 1, 4
00056 };
00057 
00058 #define NO_OTHER_PROPS  -1
00059 
00060 #define DONT_STORE_PROP  0
00061 #define STORE_PROP       1
00062 
00063 #define OTHER_PROP       0
00064 #define NAMED_PROP       1
00065 
00066 
00067 /* returns 1 if strings are equal, 0 if not */
00068 int equal_strings(const char *, const char *);
00069 
00070 /* find an element in a plyfile's list */
00071 PlyElement *find_element(PlyFile *, const char *);
00072 
00073 /* find a property in an element's list */
00074 PlyProperty *find_property(PlyElement *, const char *, int *);
00075 
00076 /* write to a file the word describing a PLY file data type */
00077 void write_scalar_type (FILE *, int);
00078 
00079 /* read a line from a file and break it up into separate words */
00080 char **get_words(FILE *, int *, char **);
00081 
00082 /* write an item to a file */
00083 void write_binary_item(PlyFile *, int, unsigned int, double, int);
00084 void write_ascii_item(FILE *, int, unsigned int, double, int);
00085 
00086 /* add information to a PLY file descriptor */
00087 void add_element(PlyFile *, char **, int);
00088 void add_property(PlyFile *, char **, int);
00089 void add_comment(PlyFile *, char *);
00090 void add_obj_info(PlyFile *, char *);
00091 
00092 /* copy a property */
00093 void copy_property(PlyProperty *, PlyProperty *);
00094 
00095 /* store a value into where a pointer and a type specify */
00096 void store_item(char *, int, int, unsigned int, double);
00097 
00098 /* return the value of a stored item */
00099 void get_stored_item( void *, int, int *, unsigned int *, double *);
00100 
00101 /* return the value stored in an item, given ptr to it and its type */
00102 double get_item_value(char *, int);
00103 
00104 /* get binary or ascii item and store it according to ptr and type */
00105 void get_ascii_item(char *, int, int *, unsigned int *, double *);
00106 void get_binary_item(PlyFile *, int, int *, unsigned int *, double *);
00107 
00108 /* get a bunch of elements from a file */
00109 void ascii_get_element(PlyFile *, char *);
00110 void binary_get_element(PlyFile *, char *);
00111 
00112 /* memory allocation */
00113 char *my_alloc(int, int, const char *);
00114 
00115 /************************/
00116 /* Byte-swapping macros */
00117 /************************/
00118 
00119 void swap2Bytes( void* ptr )
00120 {
00121     unsigned char* bytes = (unsigned char*)ptr;
00122     unsigned short* result = (unsigned short*)ptr;
00123     
00124     *result = (bytes[0]<<8) | bytes[1];
00125 }
00126 
00127 void swap4Bytes( void* ptr )
00128 {
00129     unsigned char* bytes = (unsigned char*)ptr;
00130     unsigned int* result = (unsigned int*)ptr;
00131 
00132     *result = (bytes[0]<<24) | (bytes[1]<<16) | (bytes[2]<<8) | bytes[3];
00133 }    
00134 
00135 void swap8Bytes( void* ptr )
00136 {
00137     unsigned char* bytes = (unsigned char*)ptr;
00138     unsigned long long* result = (unsigned long long*)ptr;
00139     
00140     *result = ((unsigned long long)(bytes[0])) << 56 |
00141         ((unsigned long long)(bytes[1])) << 48 |
00142         ((unsigned long long)(bytes[2])) << 40 |
00143         ((unsigned long long)(bytes[3])) << 32 |
00144         ((unsigned long long)(bytes[4])) << 24 |
00145         ((unsigned long long)(bytes[5])) << 16 |
00146         ((unsigned long long)(bytes[6])) << 8  |
00147         bytes[7];
00148 
00149 
00150 }
00151 
00152 #ifdef LITTLE_ENDIAN
00153 void swap2LE( void* ) {}
00154 void swap2LE( short* ) {}
00155 void swap2LE( unsigned short* ) {}
00156 void swap4LE( void* ) {}
00157 void swap4LE( int* ) {}
00158 void swap4LE( unsigned int* ) {}
00159 void swap4LE( float* ) {}
00160 void swap8LE( void* ) {}
00161 void swap8LE( long long* ) {}
00162 void swap8LE( unsigned long long* ) {}
00163 void swap8LE( double* ) {}
00164 
00165 void swap2BE( void* ptr ) { swap2Bytes(ptr); }
00166 void swap2BE( short* ptr ) { swap2Bytes(ptr); }
00167 void swap2BE( unsigned short* ptr ) { swap2Bytes(ptr); }
00168 void swap4BE( void* ptr ) { swap4Bytes(ptr); }
00169 void swap4BE( int* ptr ) { swap4Bytes(ptr); }
00170 void swap4BE( unsigned int* ptr ) { swap4Bytes(ptr); }
00171 void swap4BE( float* ptr ) { swap4Bytes(ptr); }
00172 void swap8BE( long long* ptr ) { swap8Bytes(ptr); }
00173 void swap8BE( void* ptr ) { swap8Bytes(ptr); }
00174 void swap8BE( unsigned long long* ptr ) { swap8Bytes(ptr); }
00175 void swap8BE( double* ptr ) { swap8Bytes(ptr); }
00176 
00177 #else // LITTLE_ENDIAN
00178 
00179 void swap2LE( void* ptr ) { swap2Bytes(ptr); }
00180 void swap2LE( short* ptr ) { swap2Bytes(ptr); }
00181 void swap2LE( unsigned short* ptr ) { swap2Bytes(ptr); }
00182 void swap4LE( void* ptr ) { swap4Bytes(ptr); }
00183 void swap4LE( int* ptr ) { swap4Bytes(ptr); }
00184 void swap4LE( unsigned int* ptr ) { swap4Bytes(ptr); }
00185 void swap4LE( float* ptr ) { swap4Bytes(ptr); }
00186 void swap8LE( long long* ptr ) { swap8Bytes(ptr); }
00187 void swap8LE( void* ptr ) { swap8Bytes(ptr); }
00188 void swap8LE( unsigned long long* ptr ) { swap8Bytes(ptr); }
00189 void swap8LE( double* ptr ) { swap8Bytes(ptr); }
00190 
00191 void swap2BE( void* ) {}
00192 void swap2BE( short* ) {}
00193 void swap2BE( unsigned short* ) {}
00194 void swap4BE( void* ) {}
00195 void swap4BE( int* ) {}
00196 void swap4BE( unsigned int* ) {}
00197 void swap4BE( float* ) {}
00198 void swap8BE( void* ) {}
00199 void swap8BE( long long* ) {}
00200 void swap8BE( unsigned long long* ) {}
00201 void swap8BE( double* ) {}
00202 
00203 #endif // LITTLE_ENDIAN
00204 
00205 
00206 /*************/
00207 /*  Writing  */
00208 /*************/
00209 
00210 
00211 /******************************************************************************
00212 Given a file pointer, get ready to write PLY data to the file.
00213 
00214 Entry:
00215   fp         - the given file pointer
00216   nelems     - number of elements in object
00217   elem_names - list of element names
00218   file_type  - file type, either ascii or binary
00219 
00220 Exit:
00221   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
00222 ******************************************************************************/
00223 
00224 PlyFile *ply_write(
00225   FILE *fp,
00226   int nelems,
00227   const char **elem_names,
00228   int file_type
00229 )
00230 {
00231   int i;
00232   PlyFile *plyfile;
00233   PlyElement *elem;
00234 
00235   /* check for NULL file pointer */
00236   if (fp == NULL)
00237     return (NULL);
00238 
00239   /* create a record for this object */
00240 
00241   plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
00242   plyfile->file_type = file_type;
00243   plyfile->num_comments = 0;
00244   plyfile->num_obj_info = 0;
00245   plyfile->nelems = nelems;
00246   plyfile->version = 1.0;
00247   plyfile->fp = fp;
00248   plyfile->other_elems = NULL;
00249 
00250   /* tuck aside the names of the elements */
00251 
00252   plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems);
00253   for (i = 0; i < nelems; i++) {
00254     elem = (PlyElement *) myalloc (sizeof (PlyElement));
00255     plyfile->elems[i] = elem;
00256     elem->name = strdup (elem_names[i]);
00257     elem->num = 0;
00258     elem->nprops = 0;
00259   }
00260 
00261   /* return pointer to the file descriptor */
00262   return (plyfile);
00263 }
00264 
00265 
00266 /******************************************************************************
00267 Open a polygon file for writing.
00268 
00269 Entry:
00270   filename   - name of file to read from
00271   nelems     - number of elements in object
00272   elem_names - list of element names
00273   file_type  - file type, either ascii or binary
00274 
00275 Exit:
00276   version - version number of PLY file
00277   returns a file identifier, used to refer to this file, or NULL if error
00278 ******************************************************************************/
00279 
00280 PlyFile *ply_open_for_writing(
00281   char *filename,
00282   int nelems,
00283   const char **elem_names,
00284   int file_type,
00285   float *version
00286 )
00287 {
00288   PlyFile *plyfile;
00289   char *name;
00290   FILE *fp;
00291 
00292 
00293   /* tack on the extension .ply, if necessary */
00294   name = (char *) myalloc (sizeof (char) * 
00295                            (static_cast<int>(strlen (filename)) + 5));
00296   strcpy (name, filename);
00297   if (strlen (name) < 4 ||
00298       strcmp (name + strlen (name) - 4, ".ply") != 0)
00299       strcat (name, ".ply");
00300 
00301   /* open the file for writing */
00302 
00303   fp = fopen (name, "wb");
00304   free (name); //wjs remove memory leak//
00305   if (fp == NULL) {
00306     return (NULL);
00307   }
00308 
00309   /* create the actual PlyFile structure */
00310 
00311   plyfile = ply_write (fp, nelems, elem_names, file_type);
00312   if (plyfile == NULL)
00313     return (NULL);
00314 
00315   /* say what PLY file version number we're writing */
00316   *version = plyfile->version;
00317 
00318   /* return pointer to the file descriptor */
00319   return (plyfile);
00320 }
00321 
00322 
00323 /******************************************************************************
00324 Describe an element, including its properties and how many will be written
00325 to the file.
00326 
00327 Entry:
00328   plyfile   - file identifier
00329   elem_name - name of element that information is being specified about
00330   nelems    - number of elements of this type to be written
00331   nprops    - number of properties contained in the element
00332   prop_list - list of properties
00333 ******************************************************************************/
00334 
00335 void ply_describe_element(
00336   PlyFile *plyfile,
00337   const char *elem_name,
00338   int nelems,
00339   int nprops,
00340   PlyProperty *prop_list
00341 )
00342 {
00343   int i;
00344   PlyElement *elem;
00345   PlyProperty *prop;
00346 
00347   /* look for appropriate element */
00348   elem = find_element (plyfile, elem_name);
00349   if (elem == NULL) {
00350     fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name);
00351     exit (-1);
00352   }
00353 
00354   elem->num = nelems;
00355 
00356   /* copy the list of properties */
00357 
00358   elem->nprops = nprops;
00359   elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops);
00360   elem->store_prop = (char *) myalloc (sizeof (char) * nprops);
00361 
00362   for (i = 0; i < nprops; i++) {
00363     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00364     elem->props[i] = prop;
00365     elem->store_prop[i] = NAMED_PROP;
00366     copy_property (prop, &prop_list[i]);
00367   }
00368 }
00369 
00370 
00371 /******************************************************************************
00372 Describe a property of an element.
00373 
00374 Entry:
00375   plyfile   - file identifier
00376   elem_name - name of element that information is being specified about
00377   prop      - the new property
00378 ******************************************************************************/
00379 
00380 void ply_describe_property(
00381   PlyFile *plyfile,
00382   const char *elem_name,
00383   PlyProperty *prop
00384 )
00385 {
00386   PlyElement *elem;
00387   PlyProperty *elem_prop;
00388 
00389   /* look for appropriate element */
00390   elem = find_element (plyfile, elem_name);
00391   if (elem == NULL) {
00392     fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
00393             elem_name);
00394     return;
00395   }
00396 
00397   /* create room for new property */
00398 
00399   if (elem->nprops == 0) {
00400     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
00401     elem->store_prop = (char *) myalloc (sizeof (char));
00402     elem->nprops = 1;
00403   }
00404   else {
00405     elem->nprops++;
00406     elem->props = (PlyProperty **)
00407                   realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
00408     elem->store_prop = (char *)
00409                   realloc (elem->store_prop, sizeof (char) * elem->nprops);
00410   }
00411 
00412   /* copy the new property */
00413   elem->other_offset = 0; //added by wjs Purify UMR
00414   elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00415   elem->props[elem->nprops - 1] = elem_prop;
00416   elem->store_prop[elem->nprops - 1] = NAMED_PROP;
00417   copy_property (elem_prop, prop);
00418 }
00419 
00420 
00421 /******************************************************************************
00422 Describe what the "other" properties are that are to be stored, and where
00423 they are in an element.
00424 ******************************************************************************/
00425 
00426 void ply_describe_other_properties(
00427   PlyFile *plyfile,
00428   PlyOtherProp *other,
00429   int offset
00430 )
00431 {
00432   int i;
00433   PlyElement *elem;
00434   PlyProperty *prop;
00435 
00436   /* look for appropriate element */
00437   elem = find_element (plyfile, other->name);
00438   if (elem == NULL) {
00439     fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n",
00440             other->name);
00441     return;
00442   }
00443 
00444   /* create room for other properties */
00445 
00446   if (elem->nprops == 0) {
00447     elem->props = (PlyProperty **)
00448                   myalloc (sizeof (PlyProperty *) * other->nprops);
00449     elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops);
00450     elem->nprops = 0;
00451   }
00452   else {
00453     int newsize;
00454     newsize = elem->nprops + other->nprops;
00455     elem->props = (PlyProperty **)
00456                   realloc (elem->props, sizeof (PlyProperty *) * newsize);
00457     elem->store_prop = (char *)
00458                   realloc (elem->store_prop, sizeof (char) * newsize);
00459   }
00460 
00461   /* copy the other properties */
00462 
00463   for (i = 0; i < other->nprops; i++) {
00464     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00465     copy_property (prop, other->props[i]);
00466     elem->props[elem->nprops] = prop;
00467     elem->store_prop[elem->nprops] = OTHER_PROP;
00468     elem->nprops++;
00469   }
00470 
00471   /* save other info about other properties */
00472   elem->other_size = other->size;
00473   elem->other_offset = offset;
00474 }
00475 
00476 
00477 /******************************************************************************
00478 State how many of a given element will be written.
00479 
00480 Entry:
00481   plyfile   - file identifier
00482   elem_name - name of element that information is being specified about
00483   nelems    - number of elements of this type to be written
00484 ******************************************************************************/
00485 
00486 void ply_element_count(
00487   PlyFile *plyfile,
00488   const char *elem_name,
00489   int nelems
00490 )
00491 {
00492   PlyElement *elem;
00493 
00494   /* look for appropriate element */
00495   elem = find_element (plyfile, elem_name);
00496   if (elem == NULL) {
00497     fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name);
00498     exit (-1);
00499   }
00500 
00501   elem->num = nelems;
00502 }
00503 
00504 
00505 /******************************************************************************
00506 Signal that we've described everything a PLY file's header and that the
00507 header should be written to the file.
00508 
00509 Entry:
00510   plyfile - file identifier
00511 ******************************************************************************/
00512 
00513 void ply_header_complete(PlyFile *plyfile)
00514 {
00515   int i,j;
00516   FILE *fp = plyfile->fp;
00517   PlyElement *elem;
00518   PlyProperty *prop;
00519 
00520   fprintf (fp, "ply\n");
00521 
00522   switch (plyfile->file_type) {
00523     case PLY_ASCII:
00524       fprintf (fp, "format ascii 1.0\n");
00525       break;
00526     case PLY_BINARY_BE:
00527       fprintf (fp, "format binary_big_endian 1.0\n");
00528       break;
00529     case PLY_BINARY_LE:
00530       fprintf (fp, "format binary_little_endian 1.0\n");
00531       break;
00532     default:
00533       fprintf (stderr, "ply_header_complete: bad file type = %d\n",
00534                plyfile->file_type);
00535       exit (-1);
00536   }
00537 
00538   /* write out the comments */
00539 
00540   for (i = 0; i < plyfile->num_comments; i++)
00541     fprintf (fp, "comment %s\n", plyfile->comments[i]);
00542 
00543   /* write out object information */
00544 
00545   for (i = 0; i < plyfile->num_obj_info; i++)
00546     fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]);
00547 
00548   /* write out information about each element */
00549 
00550   for (i = 0; i < plyfile->nelems; i++) {
00551 
00552     elem = plyfile->elems[i];
00553     fprintf (fp, "element %s %d\n", elem->name, elem->num);
00554 
00555     /* write out each property */
00556     for (j = 0; j < elem->nprops; j++) {
00557       prop = elem->props[j];
00558       if (prop->is_list) {
00559         fprintf (fp, "property list ");
00560         write_scalar_type (fp, prop->count_external);
00561         fprintf (fp, " ");
00562         write_scalar_type (fp, prop->external_type);
00563         fprintf (fp, " %s\n", prop->name);
00564       }
00565       else {
00566         fprintf (fp, "property ");
00567         write_scalar_type (fp, prop->external_type);
00568         fprintf (fp, " %s\n", prop->name);
00569       }
00570     }
00571   }
00572 
00573   fprintf (fp, "end_header\n");
00574 }
00575 
00576 
00577 /******************************************************************************
00578 Specify which elements are going to be written.  This should be called
00579 before a call to the routine ply_put_element().
00580 
00581 Entry:
00582   plyfile   - file identifier
00583   elem_name - name of element we're talking about
00584 ******************************************************************************/
00585 
00586 void ply_put_element_setup(PlyFile *plyfile, const char *elem_name)
00587 {
00588   PlyElement *elem;
00589 
00590   elem = find_element (plyfile, elem_name);
00591   if (elem == NULL) {
00592     fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name);
00593     exit (-1);
00594   }
00595 
00596   plyfile->which_elem = elem;
00597 }
00598 
00599 
00600 /******************************************************************************
00601 Write an element to the file.  This routine assumes that we're
00602 writing the type of element specified in the last call to the routine
00603 ply_put_element_setup().
00604 
00605 Entry:
00606   plyfile  - file identifier
00607   elem_ptr - pointer to the element
00608 ******************************************************************************/
00609 
00610 void ply_put_element(PlyFile *plyfile, void *elem_ptr)
00611 {
00612   int j, k;
00613   FILE *fp = plyfile->fp;
00614   PlyElement *elem;
00615   PlyProperty *prop;
00616   char *elem_data,*item;
00617   char **item_ptr;
00618   int list_count;
00619   int item_size;
00620   int int_val;
00621   unsigned int uint_val;
00622   double double_val;
00623   char **other_ptr;
00624 
00625   elem = plyfile->which_elem;
00626   elem_data = (char *)elem_ptr;
00627   other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
00628 
00629   /* write out either to an ascii or binary file */
00630 
00631   if (plyfile->file_type == PLY_ASCII) {
00632 
00633     /* write an ascii file */
00634 
00635     /* write out each property of the element */
00636     for (j = 0; j < elem->nprops; j++) {
00637       prop = elem->props[j];
00638       if (elem->store_prop[j] == OTHER_PROP)
00639         elem_data = *other_ptr;
00640       else
00641         elem_data = (char *)elem_ptr;
00642       if (prop->is_list) {
00643         item = elem_data + prop->count_offset;
00644         get_stored_item ((void *) item, prop->count_internal,
00645                          &int_val, &uint_val, &double_val);
00646         write_ascii_item (fp, int_val, uint_val, double_val,
00647                           prop->count_external);
00648         list_count = uint_val;
00649         item_ptr = (char **) (elem_data + prop->offset);
00650         item = item_ptr[0];
00651        item_size = ply_type_size[prop->internal_type];
00652         for (k = 0; k < list_count; k++) {
00653           get_stored_item ((void *) item, prop->internal_type,
00654                            &int_val, &uint_val, &double_val);
00655           write_ascii_item (fp, int_val, uint_val, double_val,
00656                             prop->external_type);
00657           item += item_size;
00658         }
00659       }
00660       else {
00661         item = elem_data + prop->offset;
00662         get_stored_item ((void *) item, prop->internal_type,
00663                          &int_val, &uint_val, &double_val);
00664         write_ascii_item (fp, int_val, uint_val, double_val,
00665                           prop->external_type);
00666       }
00667     }
00668 
00669     fprintf (fp, "\n");
00670   }
00671   else {
00672 
00673     /* write a binary file */
00674 
00675     /* write out each property of the element */
00676     for (j = 0; j < elem->nprops; j++) {
00677       prop = elem->props[j];
00678       if (elem->store_prop[j] == OTHER_PROP)
00679         elem_data = *other_ptr;
00680       else
00681         elem_data = (char *)elem_ptr;
00682       if (prop->is_list) {
00683         item = elem_data + prop->count_offset;
00684         item_size = ply_type_size[prop->count_internal];
00685         get_stored_item ((void *) item, prop->count_internal,
00686                          &int_val, &uint_val, &double_val);
00687         write_binary_item (plyfile, int_val, uint_val, double_val,
00688                            prop->count_external);
00689         list_count = uint_val;
00690         item_ptr = (char **) (elem_data + prop->offset);
00691         item = item_ptr[0];
00692         item_size = ply_type_size[prop->internal_type];
00693         for (k = 0; k < list_count; k++) {
00694           get_stored_item ((void *) item, prop->internal_type,
00695                            &int_val, &uint_val, &double_val);
00696           write_binary_item (plyfile, int_val, uint_val, double_val,
00697                              prop->external_type);
00698           item += item_size;
00699         }
00700       }
00701       else {
00702         item = elem_data + prop->offset;
00703         item_size = ply_type_size[prop->internal_type];
00704         get_stored_item ((void *) item, prop->internal_type,
00705                          &int_val, &uint_val, &double_val);
00706         write_binary_item (plyfile, int_val, uint_val, double_val,
00707                            prop->external_type);
00708       }
00709     }
00710 
00711   }
00712 }
00713 
00714 
00715 /******************************************************************************
00716 Specify a comment that will be written in the header.
00717 
00718 Entry:
00719   plyfile - file identifier
00720   comment - the comment to be written
00721 ******************************************************************************/
00722 
00723 void ply_put_comment(PlyFile *plyfile, const char *comment)
00724 {
00725   /* (re)allocate space for new comment */
00726   if (plyfile->num_comments == 0)
00727     {
00728     plyfile->comments = (char **) myalloc (sizeof (char *));
00729     }
00730   else
00731     {
00732     plyfile->comments = (char **) realloc (plyfile->comments,
00733                                            sizeof (char *) * (plyfile->num_comments + 1));
00734     }
00735   
00736   /* add comment to list */
00737   plyfile->comments[plyfile->num_comments] = strdup (comment);
00738   plyfile->num_comments++;
00739 }
00740 
00741 
00742 /******************************************************************************
00743 Specify a piece of object information (arbitrary text) that will be written
00744 in the header.
00745 
00746 Entry:
00747   plyfile  - file identifier
00748   obj_info - the text information to be written
00749 ******************************************************************************/
00750 
00751 void ply_put_obj_info(PlyFile *plyfile, const char *obj_info)
00752 {
00753   /* (re)allocate space for new info */
00754   if (plyfile->num_obj_info == 0)
00755     {
00756     plyfile->obj_info = (char **) myalloc (sizeof (char *));
00757     }
00758   else
00759     {
00760     plyfile->obj_info = (char **) realloc (plyfile->obj_info,
00761                                            sizeof (char *) * (plyfile->num_obj_info + 1));
00762     }
00763   
00764   /* add info to list */
00765   plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info);
00766   plyfile->num_obj_info++;
00767 }
00768 
00769 
00770 
00771 
00772 
00773 
00774 
00775 /*************/
00776 /*  Reading  */
00777 /*************/
00778 
00779 
00780 
00781 /******************************************************************************
00782 Given a file pointer, get ready to read PLY data from the file.
00783 
00784 Entry:
00785   fp - the given file pointer
00786 
00787 Exit:
00788   nelems     - number of elements in object
00789   elem_names - list of element names
00790   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
00791 ******************************************************************************/
00792 
00793 PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
00794 {
00795   int i,j;
00796   PlyFile *plyfile;
00797   int nwords;
00798   char **words;
00799   char **elist;
00800   PlyElement *elem;
00801   char *orig_line;
00802 
00803   /* check for NULL file pointer */
00804   if (fp == NULL)
00805     return (NULL);
00806 
00807   /* create record for this object */
00808 
00809   plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
00810   plyfile->nelems = 0;
00811   plyfile->comments = NULL;
00812   plyfile->num_comments = 0;
00813   plyfile->obj_info = NULL;
00814   plyfile->num_obj_info = 0;
00815   plyfile->fp = fp;
00816   plyfile->other_elems = NULL;
00817 
00818   /* read and parse the file's header */
00819 
00820   words = get_words (plyfile->fp, &nwords, &orig_line);
00821   if (!words || !equal_strings (words[0], "ply"))
00822     return (NULL);
00823 
00824   while (words) {
00825 
00826     /* parse words */
00827 
00828     if (equal_strings (words[0], "format")) {
00829       if (nwords != 3)
00830         return (NULL);
00831       if (equal_strings (words[1], "ascii"))
00832         plyfile->file_type = PLY_ASCII;
00833       else if (equal_strings (words[1], "binary_big_endian"))
00834         plyfile->file_type = PLY_BINARY_BE;
00835       else if (equal_strings (words[1], "binary_little_endian"))
00836         plyfile->file_type = PLY_BINARY_LE;
00837       else
00838         {
00839         free (words);
00840         return (NULL);
00841         }
00842       plyfile->version = atof (words[2]);
00843     }
00844     else if (equal_strings (words[0], "element"))
00845       add_element (plyfile, words, nwords);
00846     else if (equal_strings (words[0], "property"))
00847       add_property (plyfile, words, nwords);
00848     else if (equal_strings (words[0], "comment"))
00849       add_comment (plyfile, orig_line);
00850     else if (equal_strings (words[0], "obj_info"))
00851       add_obj_info (plyfile, orig_line);
00852     else if (equal_strings (words[0], "end_header"))
00853       {
00854       free (words);
00855       break;
00856       }
00857 
00858     /* free up words space */
00859     free (words);
00860 
00861     words = get_words (plyfile->fp, &nwords, &orig_line);
00862   }
00863   
00864 
00865   /* create tags for each property of each element, to be used */
00866   /* later to say whether or not to store each property for the user */
00867 
00868   for (i = 0; i < plyfile->nelems; i++) {
00869     elem = plyfile->elems[i];
00870     elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
00871     for (j = 0; j < elem->nprops; j++)
00872       elem->store_prop[j] = DONT_STORE_PROP;
00873     elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
00874   }
00875 
00876   /* set return values about the elements */
00877 
00878   elist = (char **) myalloc (sizeof (char *) * plyfile->nelems);
00879   for (i = 0; i < plyfile->nelems; i++)
00880     elist[i] = strdup (plyfile->elems[i]->name);
00881 
00882   *elem_names = elist;
00883   *nelems = plyfile->nelems;
00884 
00885   /* return a pointer to the file's information */
00886 
00887   return (plyfile);
00888 }
00889 
00890 
00891 /******************************************************************************
00892 Open a polygon file for reading.
00893 
00894 Entry:
00895   filename - name of file to read from
00896 
00897 Exit:
00898   nelems     - number of elements in object
00899   elem_names - list of element names
00900   file_type  - file type, either ascii or binary
00901   version    - version number of PLY file
00902   returns a file identifier, used to refer to this file, or NULL if error
00903 ******************************************************************************/
00904 
00905 PlyFile *ply_open_for_reading(
00906   char *filename,
00907   int *nelems,
00908   char ***elem_names,
00909   int *file_type,
00910   float *version
00911 )
00912 {
00913   FILE *fp;
00914   PlyFile *plyfile;
00915   char *name;
00916 
00917   /* tack on the extension .ply, if necessary */
00918 
00919   name = (char *) myalloc (sizeof (char) * 
00920                            (static_cast<int>(strlen (filename) + 5)));
00921   strcpy (name, filename);
00922   if (strlen (name) < 4 ||
00923       strcmp (name + strlen (name) - 4, ".ply") != 0)
00924       strcat (name, ".ply");
00925 
00926   /* open the file for reading */
00927 
00928   fp = fopen (name, "rb");
00929   free(name);
00930   if (fp == NULL)
00931     return (NULL);
00932 
00933   /* create the PlyFile data structure */
00934 
00935   plyfile = ply_read (fp, nelems, elem_names);
00936 
00937   /* determine the file type and version */
00938 
00939   *file_type = plyfile->file_type;
00940   *version = plyfile->version;
00941 
00942   /* return a pointer to the file's information */
00943 
00944   return (plyfile);
00945 }
00946 
00947 
00948 /******************************************************************************
00949 Get information about a particular element.
00950 
00951 Entry:
00952   plyfile   - file identifier
00953   elem_name - name of element to get information about
00954 
00955 Exit:
00956   nelems   - number of elements of this type in the file
00957   nprops   - number of properties
00958   returns a list of properties, or NULL if the file doesn't contain that elem
00959 ******************************************************************************/
00960 
00961 PlyProperty **ply_get_element_description(
00962   PlyFile *plyfile,
00963   char *elem_name,
00964   int *nelems,
00965   int *nprops
00966 )
00967 {
00968   int i;
00969   PlyElement *elem;
00970   PlyProperty *prop;
00971   PlyProperty **prop_list;
00972 
00973   /* find information about the element */
00974   elem = find_element (plyfile, elem_name);
00975   if (elem == NULL)
00976     return (NULL);
00977 
00978   *nelems = elem->num;
00979   *nprops = elem->nprops;
00980 
00981   /* make a copy of the element's property list */
00982   prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
00983   for (i = 0; i < elem->nprops; i++) {
00984     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00985     copy_property (prop, elem->props[i]);
00986     prop_list[i] = prop;
00987   }
00988 
00989   /* return this duplicate property list */
00990   return (prop_list);
00991 }
00992 
00993 
00994 /******************************************************************************
00995 Specify which properties of an element are to be returned.  This should be
00996 called before a call to the routine ply_get_element().
00997 
00998 Entry:
00999   plyfile   - file identifier
01000   elem_name - which element we're talking about
01001   nprops    - number of properties
01002   prop_list - list of properties
01003 ******************************************************************************/
01004 
01005 void ply_get_element_setup( PlyFile *plyfile, char *elem_name, int nprops,
01006                             PlyProperty *prop_list )
01007 {
01008     int i;
01009     PlyElement *elem;
01010     PlyProperty *prop;
01011     int index;
01012 
01013     /* find information about the element */
01014     elem = find_element (plyfile, elem_name);
01015     plyfile->which_elem = elem;
01016 
01017     /* deposit the property information into the element's description */
01018     for (i = 0; i < nprops; i++) 
01019     {
01020         /* look for actual property */
01021         prop = find_property (elem, prop_list[i].name, &index);
01022         if (prop == NULL) 
01023         {
01024             fprintf ( stderr, 
01025                       "Warning:  Can't find property '%s' in element '%s'\n",
01026                       prop_list[i].name, elem_name );
01027             continue;
01028         }
01029 
01030         /* store its description */
01031         prop->internal_type = prop_list[i].internal_type;
01032         prop->offset = prop_list[i].offset;
01033         prop->count_internal = prop_list[i].count_internal;
01034         prop->count_offset = prop_list[i].count_offset;
01035 
01036         /* specify that the user wants this property */
01037         elem->store_prop[index] = STORE_PROP;
01038     }
01039 }
01040 
01041 
01042 /******************************************************************************
01043 Specify a property of an element that is to be returned.  This should be
01044 called (usually multiple times) before a call to the routine ply_get_element().
01045 This routine should be used in preference to the less flexible old routine
01046 called ply_get_element_setup().
01047 
01048 Entry:
01049   plyfile   - file identifier
01050   elem_name - which element we're talking about
01051   prop      - property to add to those that will be returned
01052 ******************************************************************************/
01053 
01054 void ply_get_property(
01055   PlyFile *plyfile,
01056   char *elem_name,
01057   PlyProperty *prop
01058 )
01059 {
01060   PlyElement *elem;
01061   PlyProperty *prop_ptr;
01062   int index;
01063 
01064   /* find information about the element */
01065   elem = find_element (plyfile, elem_name);
01066   plyfile->which_elem = elem;
01067 
01068   /* deposit the property information into the element's description */
01069 
01070   prop_ptr = find_property (elem, prop->name, &index);
01071   if (prop_ptr == NULL) {
01072     fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
01073              prop->name, elem_name);
01074     return;
01075   }
01076   prop_ptr->internal_type  = prop->internal_type;
01077   prop_ptr->offset         = prop->offset;
01078   prop_ptr->count_internal = prop->count_internal;
01079   prop_ptr->count_offset   = prop->count_offset;
01080 
01081   /* specify that the user wants this property */
01082   elem->store_prop[index] = STORE_PROP;
01083 }
01084 
01085 
01086 /******************************************************************************
01087 Read one element from the file.  This routine assumes that we're reading
01088 the type of element specified in the last call to the routine
01089 ply_get_element_setup().
01090 
01091 Entry:
01092   plyfile  - file identifier
01093   elem_ptr - pointer to location where the element information should be put
01094 ******************************************************************************/
01095 
01096 void ply_get_element(PlyFile *plyfile, void *elem_ptr)
01097 {
01098   if (plyfile->file_type == PLY_ASCII)
01099     ascii_get_element (plyfile, (char *) elem_ptr);
01100   else
01101     binary_get_element (plyfile, (char *) elem_ptr);
01102 }
01103 
01104 
01105 /******************************************************************************
01106 Extract the comments from the header information of a PLY file.
01107 
01108 Entry:
01109   plyfile - file identifier
01110 
01111 Exit:
01112   num_comments - number of comments returned
01113   returns a pointer to a list of comments
01114 ******************************************************************************/
01115 
01116 char **ply_get_comments(PlyFile *plyfile, int *num_comments)
01117 {
01118   *num_comments = plyfile->num_comments;
01119   return (plyfile->comments);
01120 }
01121 
01122 
01123 /******************************************************************************
01124 Extract the object information (arbitrary text) from the header information
01125 of a PLY file.
01126 
01127 Entry:
01128   plyfile - file identifier
01129 
01130 Exit:
01131   num_obj_info - number of lines of text information returned
01132   returns a pointer to a list of object info lines
01133 ******************************************************************************/
01134 
01135 char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info)
01136 {
01137   *num_obj_info = plyfile->num_obj_info;
01138   return (plyfile->obj_info);
01139 }
01140 
01141 
01142 /******************************************************************************
01143 Make ready for "other" properties of an element-- those properties that
01144 the user has not explicitly asked for, but that are to be stashed away
01145 in a special structure to be carried along with the element's other
01146 information.
01147 
01148 Entry:
01149   plyfile - file identifier
01150   elem    - element for which we want to save away other properties
01151 ******************************************************************************/
01152 
01153 void setup_other_props(PlyFile *, PlyElement *elem)
01154 {
01155   int i;
01156   PlyProperty *prop;
01157   int size = 0;
01158   int type_size;
01159 
01160   /* Examine each property in decreasing order of size. */
01161   /* We do this so that all data types will be aligned by */
01162   /* word, half-word, or whatever within the structure. */
01163 
01164   for (type_size = 8; type_size > 0; type_size /= 2) {
01165 
01166     /* add up the space taken by each property, and save this information */
01167     /* away in the property descriptor */
01168 
01169     for (i = 0; i < elem->nprops; i++) {
01170 
01171       /* don't bother with properties we've been asked to store explicitly */
01172       if (elem->store_prop[i])
01173         continue;
01174 
01175       prop = elem->props[i];
01176 
01177       /* internal types will be same as external */
01178       prop->internal_type = prop->external_type;
01179       prop->count_internal = prop->count_external;
01180 
01181       /* check list case */
01182       if (prop->is_list) {
01183 
01184         /* pointer to list */
01185         if (type_size == sizeof (void *)) {
01186           prop->offset = size;
01187           size += sizeof (void *);    /* always use size of a pointer here */
01188         }
01189 
01190         /* count of number of list elements */
01191         if (type_size == ply_type_size[prop->count_external]) {
01192           prop->count_offset = size;
01193           size += ply_type_size[prop->count_external];
01194         }
01195       }
01196       /* not list */
01197       else if (type_size == ply_type_size[prop->external_type]) {
01198         prop->offset = size;
01199         size += ply_type_size[prop->external_type];
01200       }
01201     }
01202 
01203   }
01204 
01205   /* save the size for the other_props structure */
01206   elem->other_size = size;
01207 }
01208 
01209 
01210 /******************************************************************************
01211 Specify that we want the "other" properties of an element to be tucked
01212 away within the user's structure.  The user needn't be concerned for how
01213 these properties are stored.
01214 
01215 Entry:
01216   plyfile   - file identifier
01217   elem_name - name of element that we want to store other_props in
01218   offset    - offset to where other_props will be stored inside user's structure
01219 
01220 Exit:
01221   returns pointer to structure containing description of other_props
01222 ******************************************************************************/
01223 
01224 PlyOtherProp *ply_get_other_properties(
01225   PlyFile *plyfile,
01226   char *elem_name,
01227   int offset
01228 )
01229 {
01230   int i;
01231   PlyElement *elem;
01232   PlyOtherProp *other;
01233   PlyProperty *prop;
01234   int nprops;
01235 
01236   /* find information about the element */
01237   elem = find_element (plyfile, elem_name);
01238   if (elem == NULL) {
01239     fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
01240              elem_name);
01241     return (NULL);
01242   }
01243 
01244   /* remember that this is the "current" element */
01245   plyfile->which_elem = elem;
01246 
01247   /* save the offset to where to store the other_props */
01248   elem->other_offset = offset;
01249 
01250   /* place the appropriate pointers, etc. in the element's property list */
01251   setup_other_props (plyfile, elem);
01252 
01253   /* create structure for describing other_props */
01254   other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
01255   other->name = strdup (elem_name);
01256 #if 0
01257   if (elem->other_offset == NO_OTHER_PROPS) {
01258     other->size = 0;
01259     other->props = NULL;
01260     other->nprops = 0;
01261     return (other);
01262   }
01263 #endif
01264   other->size = elem->other_size;
01265   other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops);
01266   
01267   /* save descriptions of each "other" property */
01268   nprops = 0;
01269   for (i = 0; i < elem->nprops; i++) {
01270     if (elem->store_prop[i])
01271       continue;
01272     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
01273     copy_property (prop, elem->props[i]);
01274     other->props[nprops] = prop;
01275     nprops++;
01276   }
01277   other->nprops = nprops;
01278 
01279 #if 1
01280   /* set other_offset pointer appropriately if there are NO other properties */
01281   if (other->nprops == 0) {
01282     elem->other_offset = NO_OTHER_PROPS;
01283   }
01284 #endif
01285   
01286   /* return structure */
01287   return (other);
01288 }
01289 
01290 
01291 
01292 
01293 /*************************/
01294 /*  Other Element Stuff  */
01295 /*************************/
01296 
01297 
01298 
01299 
01300 /******************************************************************************
01301 Grab all the data for an element that a user does not want to explicitly
01302 read in.
01303 
01304 Entry:
01305   plyfile    - pointer to file
01306   elem_name  - name of element whose data is to be read in
01307   elem_count - number of instances of this element stored in the file
01308 
01309 Exit:
01310   returns pointer to ALL the "other" element data for this PLY file
01311 ******************************************************************************/
01312 
01313 PlyOtherElems *ply_get_other_element (
01314   PlyFile *plyfile,
01315   char *elem_name,
01316   int elem_count
01317 )
01318 {
01319   int i;
01320   PlyElement *elem;
01321   PlyOtherElems *other_elems;
01322   OtherElem *other;
01323 
01324   /* look for appropriate element */
01325   elem = find_element (plyfile, elem_name);
01326   if (elem == NULL) {
01327     fprintf (stderr,
01328              "ply_get_other_element: can't find element '%s'\n", elem_name);
01329     exit (-1);
01330   }
01331 
01332   /* create room for the new "other" element, initializing the */
01333   /* other data structure if necessary */
01334 
01335   if (plyfile->other_elems == NULL) {
01336     plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
01337     other_elems = plyfile->other_elems;
01338     other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
01339     other = &(other_elems->other_list[0]);
01340     other_elems->num_elems = 1;
01341   }
01342   else {
01343     other_elems = plyfile->other_elems;
01344     other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
01345                               sizeof (OtherElem) * other_elems->num_elems + 1);
01346     other = &(other_elems->other_list[other_elems->num_elems]);
01347     other_elems->num_elems++;
01348   }
01349 
01350   /* count of element instances in file */
01351   other->elem_count = elem_count;
01352 
01353   /* save name of element */
01354   other->elem_name = strdup (elem_name);
01355 
01356   /* create a list to hold all the current elements */
01357   other->other_data = (OtherData **)
01358                   malloc (sizeof (OtherData *) * other->elem_count);
01359 
01360   /* set up for getting elements */
01361   other->other_props = ply_get_other_properties (plyfile, elem_name,
01362                          offsetof(OtherData,other_props));
01363 
01364   /* grab all these elements */
01365   for (i = 0; i < other->elem_count; i++) {
01366     /* grab and element from the file */
01367     other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
01368     ply_get_element (plyfile, (void *) other->other_data[i]);
01369   }
01370 
01371   /* return pointer to the other elements data */
01372   return (other_elems);
01373 }
01374 
01375 
01376 /******************************************************************************
01377 Pass along a pointer to "other" elements that we want to save in a given
01378 PLY file.  These other elements were presumably read from another PLY file.
01379 
01380 Entry:
01381   plyfile     - file pointer in which to store this other element info
01382   other_elems - info about other elements that we want to store
01383 ******************************************************************************/
01384 
01385 void ply_describe_other_elements (
01386   PlyFile *plyfile,
01387   PlyOtherElems *other_elems
01388 )
01389 {
01390   int i;
01391   OtherElem *other;
01392 
01393   /* ignore this call if there is no other element */
01394   if (other_elems == NULL)
01395     return;
01396 
01397   /* save pointer to this information */
01398   plyfile->other_elems = other_elems;
01399 
01400   /* describe the other properties of this element */
01401 
01402   for (i = 0; i < other_elems->num_elems; i++) {
01403     other = &(other_elems->other_list[i]);
01404     ply_element_count (plyfile, other->elem_name, other->elem_count);
01405     ply_describe_other_properties (plyfile, other->other_props,
01406                                    offsetof(OtherData,other_props));
01407   }
01408 }
01409 
01410 
01411 /******************************************************************************
01412 Write out the "other" elements specified for this PLY file.
01413 
01414 Entry:
01415   plyfile - pointer to PLY file to write out other elements for
01416 ******************************************************************************/
01417 
01418 void ply_put_other_elements (PlyFile *plyfile)
01419 {
01420   int i,j;
01421   OtherElem *other;
01422 
01423   /* make sure we have other elements to write */
01424   if (plyfile->other_elems == NULL)
01425     return;
01426 
01427   /* write out the data for each "other" element */
01428 
01429   for (i = 0; i < plyfile->other_elems->num_elems; i++) {
01430 
01431     other = &(plyfile->other_elems->other_list[i]);
01432     ply_put_element_setup (plyfile, other->elem_name);
01433 
01434     /* write out each instance of the current element */
01435     for (j = 0; j < other->elem_count; j++)
01436       ply_put_element (plyfile, (void *) other->other_data[j]);
01437   }
01438 }
01439 
01440 
01441 /******************************************************************************
01442 Free up storage used by an "other" elements data structure.
01443 
01444 Entry:
01445   other_elems - data structure to free up
01446 ******************************************************************************/
01447 
01448 void ply_free_other_elements (PlyOtherElems *)
01449 {
01450 
01451 }
01452 
01453 
01454 
01455 /*******************/
01456 /*  Miscellaneous  */
01457 /*******************/
01458 
01459 
01460 
01461 /******************************************************************************
01462 Close a PLY file.
01463 
01464 Entry:
01465   plyfile - identifier of file to close
01466 ******************************************************************************/
01467 
01468 void ply_close(PlyFile *plyfile)
01469 {
01470   // Changed by Will Schroeder. Old stuff leaked like a sieve.
01471 
01472   /* free up memory associated with the PLY file */
01473   fclose (plyfile->fp);
01474 
01475   int i, j;
01476   PlyElement *elem;
01477   for (i=0; i<plyfile->nelems; i++)
01478     {
01479     elem = plyfile->elems[i];
01480     if ( elem->name ) {free(elem->name);}
01481     for (j=0; j<elem->nprops; j++)
01482       {
01483       if ( elem->props[j]->name ) {free(const_cast<char *>(elem->props[j]->name));}
01484       free (elem->props[j]);
01485       }
01486     free (elem->props);
01487     free (elem->store_prop);
01488     free (elem);
01489     }
01490   free(plyfile->elems);
01491 
01492   for (i=0; i<plyfile->num_comments; i++)
01493     {
01494     free (plyfile->comments[i]);
01495     }
01496   free (plyfile->comments);
01497   
01498   for (i=0; i<plyfile->num_obj_info; i++)
01499     {
01500     free (plyfile->obj_info[i]);
01501     }
01502   free (plyfile->obj_info);
01503   
01504   free (plyfile);
01505 }
01506 
01507 
01508 /******************************************************************************
01509 Get version number and file type of a PlyFile.
01510 
01511 Entry:
01512   ply - pointer to PLY file
01513 
01514 Exit:
01515   version - version of the file
01516   file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
01517 ******************************************************************************/
01518 
01519 void ply_get_info(PlyFile *ply, float *version, int *file_type)
01520 {
01521   if (ply == NULL)
01522     return;
01523 
01524   *version = ply->version;
01525   *file_type = ply->file_type;
01526 }
01527 
01528 
01529 /******************************************************************************
01530 Compare two strings.  Returns 1 if they are the same, 0 if not.
01531 ******************************************************************************/
01532 
01533 int equal_strings(const char *s1, const char *s2)
01534 {
01535   while (*s1 && *s2)
01536     if (*s1++ != *s2++)
01537       return (0);
01538 
01539   if (*s1 != *s2)
01540     return (0);
01541   else
01542     return (1);
01543 }
01544 
01545 
01546 /******************************************************************************
01547 Find an element from the element list of a given PLY object.
01548 
01549 Entry:
01550   plyfile - file id for PLY file
01551   element - name of element we're looking for
01552 
01553 Exit:
01554   returns the element, or NULL if not found
01555 ******************************************************************************/
01556 
01557 PlyElement *find_element(PlyFile *plyfile, const char *element)
01558 {
01559     int i;
01560 
01561     for (i = 0; i < plyfile->nelems; i++)
01562         if (equal_strings (element, plyfile->elems[i]->name))
01563             return (plyfile->elems[i]);
01564     
01565     return (NULL);
01566 }
01567 
01568 
01569 /******************************************************************************
01570 Find a property in the list of properties of a given element.
01571 
01572 Entry:
01573   elem      - pointer to element in which we want to find the property
01574   prop_name - name of property to find
01575 
01576 Exit:
01577   index - index to position in list
01578   returns a pointer to the property, or NULL if not found
01579 ******************************************************************************/
01580 
01581 PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index)
01582 {
01583     int i;
01584     
01585     for( i = 0; i < elem->nprops; i++)
01586         if (equal_strings (prop_name, elem->props[i]->name))
01587         {
01588             *index = i;
01589             return (elem->props[i]);
01590         }
01591     
01592     *index = -1;
01593     return (NULL);
01594 }
01595 
01596 
01597 /******************************************************************************
01598 Read an element from an ascii file.
01599 
01600 Entry:
01601   plyfile  - file identifier
01602   elem_ptr - pointer to element
01603 ******************************************************************************/
01604 
01605 void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
01606 {
01607   int j,k;
01608   PlyElement *elem;
01609   PlyProperty *prop;
01610   char **words;
01611   int nwords;
01612   int which_word;
01613   char *elem_data,*item=0;
01614   char *item_ptr;
01615   int item_size=0;
01616   int int_val;
01617   unsigned int uint_val;
01618   double double_val;
01619   int list_count;
01620   int store_it;
01621   char **store_array;
01622   char *orig_line;
01623   char *other_data=0;
01624   int other_flag;
01625 
01626   /* the kind of element we're reading currently */
01627   elem = plyfile->which_elem;
01628 
01629   /* do we need to setup for other_props? */
01630 
01631   if (elem->other_offset != NO_OTHER_PROPS) {
01632     char **ptr;
01633     other_flag = 1;
01634     /* make room for other_props */
01635     other_data = (char *) myalloc (elem->other_size);
01636     /* store pointer in user's structure to the other_props */
01637     ptr = (char **) (elem_ptr + elem->other_offset);
01638     *ptr = other_data;
01639   }
01640   else
01641     other_flag = 0;
01642 
01643   /* read in the element */
01644 
01645   words = get_words (plyfile->fp, &nwords, &orig_line);
01646   if (words == NULL) {
01647     fprintf (stderr, "ply_get_element: unexpected end of file\n");
01648     exit (-1);
01649   }
01650 
01651   which_word = 0;
01652 
01653   for (j = 0; j < elem->nprops; j++) {
01654 
01655     prop = elem->props[j];
01656     store_it = (elem->store_prop[j] | other_flag);
01657 
01658     /* store either in the user's structure or in other_props */
01659     if (elem->store_prop[j])
01660       elem_data = elem_ptr;
01661     else
01662       elem_data = other_data;
01663 
01664     if (prop->is_list) {       /* a list */
01665 
01666       /* get and store the number of items in the list */
01667       get_ascii_item (words[which_word++], prop->count_external,
01668                       &int_val, &uint_val, &double_val);
01669       if (store_it) {
01670         item = elem_data + prop->count_offset;
01671         store_item(item, prop->count_internal, int_val, uint_val, double_val);
01672       }
01673 
01674       /* allocate space for an array of items and store a ptr to the array */
01675       list_count = int_val;
01676       item_size = ply_type_size[prop->internal_type];
01677       store_array = (char **) (elem_data + prop->offset);
01678 
01679       if (list_count == 0) {
01680         if (store_it)
01681           *store_array = NULL;
01682       }
01683       else {
01684         if (store_it) {
01685           item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
01686           item = item_ptr;
01687           *store_array = item_ptr;
01688         }
01689 
01690         /* read items and store them into the array */
01691         for (k = 0; k < list_count; k++) {
01692           get_ascii_item (words[which_word++], prop->external_type,
01693                           &int_val, &uint_val, &double_val);
01694           if (store_it) {
01695             store_item (item, prop->internal_type,
01696                         int_val, uint_val, double_val);
01697             item += item_size;
01698           }
01699         }
01700       }
01701 
01702     }
01703     else {                     /* not a list */
01704       get_ascii_item (words[which_word++], prop->external_type,
01705                       &int_val, &uint_val, &double_val);
01706       if (store_it) {
01707         item = elem_data + prop->offset;
01708         store_item (item, prop->internal_type, int_val, uint_val, double_val);
01709       }
01710     }
01711 
01712   }
01713 
01714   free (words);
01715 }
01716 
01717 
01718 /******************************************************************************
01719 Read an element from a binary file.
01720 
01721 Entry:
01722   plyfile  - file identifier
01723   elem_ptr - pointer to an element
01724 ******************************************************************************/
01725 
01726 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
01727 {
01728   int j,k;
01729   PlyElement *elem;
01730   PlyProperty *prop;
01731   //FILE *fp = plyfile->fp;
01732   char *elem_data,*item=0;
01733   char *item_ptr;
01734   int item_size=0;
01735   int int_val;
01736   unsigned int uint_val;
01737   double double_val;
01738   int list_count;
01739   int store_it;
01740   char **store_array;
01741   char *other_data=0;
01742   int other_flag;
01743 
01744   /* the kind of element we're reading currently */
01745   elem = plyfile->which_elem;
01746 
01747   /* do we need to setup for other_props? */
01748 
01749   if (elem->other_offset != NO_OTHER_PROPS) {
01750     char **ptr;
01751     other_flag = 1;
01752     /* make room for other_props */
01753     other_data = (char *) myalloc (elem->other_size);
01754     /* store pointer in user's structure to the other_props */
01755     ptr = (char **) (elem_ptr + elem->other_offset);
01756     *ptr = other_data;
01757   }
01758   else
01759     other_flag = 0;
01760 
01761   /* read in a number of elements */
01762 
01763   for (j = 0; j < elem->nprops; j++) {
01764 
01765     prop = elem->props[j];
01766     store_it = (elem->store_prop[j] | other_flag);
01767 
01768     /* store either in the user's structure or in other_props */
01769     if (elem->store_prop[j])
01770       elem_data = elem_ptr;
01771     else
01772       elem_data = other_data;
01773 
01774     if (prop->is_list) {       /* a list */
01775 
01776       /* get and store the number of items in the list */
01777       get_binary_item (plyfile, prop->count_external,
01778                        &int_val, &uint_val, &double_val);
01779       if (store_it) {
01780         item = elem_data + prop->count_offset;
01781         store_item(item, prop->count_internal, int_val, uint_val, double_val);
01782       }
01783 
01784       /* allocate space for an array of items and store a ptr to the array */
01785       list_count = int_val;
01786       /* The "if" was added by Afra Zomorodian 8/22/95
01787        * so that zipper won't crash reading plies that have additional
01788        * properties.
01789        */ 
01790       if (store_it) {
01791         item_size = ply_type_size[prop->internal_type];
01792       }
01793       store_array = (char **) (elem_data + prop->offset);
01794       if (list_count == 0) {
01795         if (store_it)
01796           *store_array = NULL;
01797       }
01798       else {
01799         if (store_it) {
01800           item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
01801           item = item_ptr;
01802           *store_array = item_ptr;
01803         }
01804 
01805         /* read items and store them into the array */
01806         for (k = 0; k < list_count; k++) {
01807           get_binary_item (plyfile, prop->external_type,
01808                           &int_val, &uint_val, &double_val);
01809           if (store_it) {
01810             store_item (item, prop->internal_type,
01811                         int_val, uint_val, double_val);
01812             item += item_size;
01813           }
01814         }
01815       }
01816 
01817     }
01818     else {                     /* not a list */
01819       get_binary_item (plyfile, prop->external_type,
01820                       &int_val, &uint_val, &double_val);
01821       if (store_it) {
01822         item = elem_data + prop->offset;
01823         store_item (item, prop->internal_type, int_val, uint_val, double_val);
01824       }
01825     }
01826 
01827   }
01828 }
01829 
01830 
01831 /******************************************************************************
01832 Write to a file the word that represents a PLY data type.
01833 
01834 Entry:
01835   fp   - file pointer
01836   code - code for type
01837 ******************************************************************************/
01838 
01839 void write_scalar_type (FILE *fp, int code)
01840 {
01841   /* make sure this is a valid code */
01842 
01843   if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
01844     fprintf (stderr, "write_scalar_type: bad data code = %d\n", code);
01845     exit (-1);
01846   }
01847 
01848   /* write the code to a file */
01849 
01850   fprintf (fp, "%s", type_names[code]);
01851 }
01852 
01853 
01854 /******************************************************************************
01855 Get a text line from a file and break it up into words.
01856 
01857 IMPORTANT: The calling routine call "free" on the returned pointer once
01858 finished with it.
01859 
01860 Entry:
01861   fp - file to read from
01862 
01863 Exit:
01864   nwords    - number of words returned
01865   orig_line - the original line of characters
01866   returns a list of words from the line, or NULL if end-of-file
01867 ******************************************************************************/
01868 
01869 char **get_words(FILE *fp, int *nwords, char **orig_line)
01870 {
01871 #define BIG_STRING 4096
01872   static char str[BIG_STRING];
01873   static char str_copy[BIG_STRING];
01874   char **words;
01875   int max_words = 10;
01876   int num_words = 0;
01877   char *ptr,*ptr2;
01878   char *result;
01879 
01880   /* read in a line */
01881   result = fgets (str, BIG_STRING, fp);
01882   if (result == NULL) {
01883     *nwords = 0;
01884     *orig_line = NULL;
01885     return (NULL);
01886   }
01887 
01888   words = (char **) myalloc (sizeof (char *) * max_words);
01889 
01890   /* convert line-feed and tabs into spaces */
01891   /* (this guarentees that there will be a space before the */
01892   /*  null character at the end of the string) */
01893 
01894   str[BIG_STRING-2] = ' ';
01895   str[BIG_STRING-1] = '\0';
01896 
01897   for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
01898     *ptr2 = *ptr;
01899     if (*ptr == '\t') {
01900       *ptr = ' ';
01901       *ptr2 = ' ';
01902     }
01903     else if (*ptr == '\n') {
01904       *ptr = ' ';
01905       *ptr2 = '\0';
01906       break;
01907     }
01908   }
01909 
01910   /* find the words in the line */
01911 
01912   ptr = str;
01913   while (*ptr != '\0') {
01914 
01915     /* jump over leading spaces */
01916     while (*ptr == ' ')
01917       ptr++;
01918 
01919     /* break if we reach the end */
01920     if (*ptr == '\0')
01921       break;
01922 
01923     /* save pointer to beginning of word */
01924     if (num_words >= max_words) {
01925       max_words += 10;
01926       words = (char **) realloc (words, sizeof (char *) * max_words);
01927     }
01928     words[num_words++] = ptr;
01929 
01930     /* jump over non-spaces */
01931     while (*ptr != ' ')
01932       ptr++;
01933 
01934     /* place a null character here to mark the end of the word */
01935     *ptr++ = '\0';
01936   }
01937 
01938   /* return the list of words */
01939   *nwords = num_words;
01940   *orig_line = str_copy;
01941   return (words);
01942 }
01943 
01944 
01945 /******************************************************************************
01946 Return the value of an item, given a pointer to it and its type.
01947 
01948 Entry:
01949   item - pointer to item
01950   type - data type that "item" points to
01951 
01952 Exit:
01953   returns a double-precision float that contains the value of the item
01954 ******************************************************************************/
01955 
01956 double get_item_value(char *item, int type)
01957 {
01958   unsigned char *puchar;
01959   char *pchar;
01960   short int *pshort;
01961   unsigned short int *pushort;
01962   int *pint;
01963   unsigned int *puint;
01964   float *pfloat;
01965   double *pdouble;
01966   int int_value;
01967   unsigned int uint_value;
01968   double double_value;
01969 
01970   switch (type) {
01971     case PLY_CHAR:
01972       pchar = (char *) item;
01973       int_value = *pchar;
01974       return ((double) int_value);
01975     case PLY_UCHAR:
01976     case PLY_UINT8:
01977       puchar = (unsigned char *) item;
01978       int_value = *puchar;
01979       return ((double) int_value);
01980     case PLY_SHORT:
01981       pshort = (short int *) item;
01982       int_value = *pshort;
01983       return ((double) int_value);
01984     case PLY_USHORT:
01985       pushort = (unsigned short int *) item;
01986       int_value = *pushort;
01987       return ((double) int_value);
01988     case PLY_INT:
01989     case PLY_INT32:
01990       pint = (int *) item;
01991       int_value = *pint;
01992       return ((double) int_value);
01993     case PLY_UINT:
01994       puint = (unsigned int *) item;
01995       uint_value = *puint;
01996       return ((double) uint_value);
01997     case PLY_FLOAT:
01998     case PLY_FLOAT32:
01999       pfloat = (float *) item;
02000       double_value = *pfloat;
02001       return (double_value);
02002     case PLY_DOUBLE:
02003       pdouble = (double *) item;
02004       double_value = *pdouble;
02005       return (double_value);
02006   }
02007   fprintf (stderr, "get_item_value: bad type = %d\n", type);
02008   return 0;
02009 }
02010 
02011 
02012 /******************************************************************************
02013 Write out an item to a file as raw binary bytes.
02014 
02015 Entry:
02016   fp         - file to write to
02017   int_val    - integer version of item
02018   uint_val   - unsigned integer version of item
02019   double_val - double-precision float version of item
02020   type       - data type to write out
02021 ******************************************************************************/
02022 
02023 void write_binary_item(PlyFile *plyfile,
02024                                int int_val,
02025                                unsigned int uint_val,
02026                                double double_val,
02027                                int type
02028 )
02029 {
02030   FILE *fp = plyfile->fp;
02031   unsigned char uchar_val;
02032   char char_val;
02033   unsigned short ushort_val;
02034   short short_val;
02035   float float_val;
02036 
02037   switch (type) {
02038     case PLY_CHAR:
02039       char_val = int_val;
02040       fwrite (&char_val, 1, 1, fp);
02041       break;
02042     case PLY_SHORT:
02043       short_val = int_val;
02044       if( plyfile->file_type == PLY_BINARY_BE )
02045           swap2BE(&short_val);
02046       else
02047           swap2LE(&short_val);
02048       fwrite (&short_val, 2, 1, fp);
02049       break;
02050       case PLY_INT:
02051       case PLY_INT32:
02052           if( plyfile->file_type == PLY_BINARY_BE )
02053           {
02054               swap4BE(&int_val);
02055           }
02056           else
02057           {
02058               swap4LE(&int_val);
02059           }
02060           fwrite (&int_val, 4, 1, fp);
02061           break;
02062       case PLY_UCHAR:
02063       case PLY_UINT8:
02064           uchar_val = uint_val;
02065           fwrite (&uchar_val, 1, 1, fp);
02066           break;
02067       case PLY_USHORT:
02068           if( plyfile->file_type == PLY_BINARY_BE )
02069           {
02070               swap2BE(&ushort_val);
02071           }
02072           else
02073           {
02074               swap2LE(&ushort_val);
02075           }
02076           ushort_val = uint_val;
02077           fwrite (&ushort_val, 2, 1, fp);
02078           break;
02079       case PLY_UINT:
02080           if( plyfile->file_type == PLY_BINARY_BE )
02081           {
02082               swap4BE(&uint_val);
02083           }
02084           else
02085           {
02086               swap4LE(&uint_val);
02087           }
02088           fwrite (&uint_val, 4, 1, fp);
02089           break;
02090       case PLY_FLOAT:
02091       case PLY_FLOAT32:
02092           float_val = double_val;
02093           if( plyfile->file_type == PLY_BINARY_BE )
02094           {
02095               swap4BE(&float_val);
02096           }
02097           else
02098           {
02099               swap4LE(&float_val);
02100           }
02101           fwrite (&float_val, 4, 1, fp);
02102           break;
02103       case PLY_DOUBLE:
02104           if( plyfile->file_type == PLY_BINARY_BE )
02105           {
02106               swap8BE(&double_val);
02107           }
02108           else
02109           {
02110               swap8LE(&double_val);
02111           }
02112           fwrite (&double_val, 8, 1, fp);
02113       break;
02114     default:
02115       fprintf (stderr, "write_binary_item: bad type = %d\n", type);
02116       exit (-1);
02117   }
02118 }
02119 
02120 
02121 /******************************************************************************
02122 Write out an item to a file as ascii characters.
02123 
02124 Entry:
02125   fp         - file to write to
02126   int_val    - integer version of item
02127   uint_val   - unsigned integer version of item
02128   double_val - double-precision float version of item
02129   type       - data type to write out
02130 ******************************************************************************/
02131 
02132 void write_ascii_item(
02133   FILE *fp,
02134   int int_val,
02135   unsigned int uint_val,
02136   double double_val,
02137   int type
02138 )
02139 {
02140   switch (type) {
02141     case PLY_CHAR:
02142     case PLY_SHORT:
02143     case PLY_INT:
02144     case PLY_INT32:
02145       fprintf (fp, "%d ", int_val);
02146       break;
02147     case PLY_UCHAR:
02148     case PLY_UINT8:
02149     case PLY_USHORT:
02150     case PLY_UINT:
02151       fprintf (fp, "%u ", uint_val);
02152       break;
02153     case PLY_FLOAT:
02154     case PLY_FLOAT32:
02155     case PLY_DOUBLE:
02156       fprintf (fp, "%g ", double_val);
02157       break;
02158     default:
02159       fprintf (stderr, "write_ascii_item: bad type = %d\n", type);
02160       exit (-1);
02161   }
02162 }
02163 
02164 /******************************************************************************
02165 Get the value of an item that is in memory, and place the result
02166 into an integer, an unsigned integer and a double.
02167 
02168 Entry:
02169   ptr  - pointer to the item
02170   type - data type supposedly in the item
02171 
02172 Exit:
02173   int_val    - integer value
02174   uint_val   - unsigned integer value
02175   double_val - double-precision floating point value
02176 ******************************************************************************/
02177 
02178 void get_stored_item(
02179   void *ptr,
02180   int type,
02181   int *int_val,
02182   unsigned int *uint_val,
02183   double *double_val
02184 )
02185 {
02186   switch (type) {
02187     case PLY_CHAR:
02188       *int_val = *((char *) ptr);
02189       *uint_val = *int_val;
02190       *double_val = *int_val;
02191       break;
02192     case PLY_UCHAR:
02193     case PLY_UINT8:
02194       *uint_val = *((unsigned char *) ptr);
02195       *int_val = *uint_val;
02196       *double_val = *uint_val;
02197       break;
02198     case PLY_SHORT:
02199       *int_val = *((short int *) ptr);
02200       *uint_val = *int_val;
02201       *double_val = *int_val;
02202       break;
02203     case PLY_USHORT:
02204       *uint_val = *((unsigned short int *) ptr);
02205       *int_val = *uint_val;
02206       *double_val = *uint_val;
02207       break;
02208     case PLY_INT:
02209     case PLY_INT32:
02210       *int_val = *((int *) ptr);
02211       *uint_val = *int_val;
02212       *double_val = *int_val;
02213       break;
02214     case PLY_UINT:
02215       *uint_val = *((unsigned int *) ptr);
02216       *int_val = *uint_val;
02217       *double_val = *uint_val;
02218       break;
02219     case PLY_FLOAT:
02220     case PLY_FLOAT32:
02221       *double_val = *((float *) ptr);
02222       *int_val = (int) *double_val;
02223       *uint_val = (unsigned int) *double_val;
02224       break;
02225     case PLY_DOUBLE:
02226       *double_val = *((double *) ptr);
02227       *int_val = (int) *double_val;
02228       *uint_val = (unsigned int) *double_val;
02229       break;
02230     default:
02231       fprintf (stderr, "get_stored_item: bad type = %d\n", type);
02232       exit (-1);
02233   }
02234 }
02235 
02236 
02237 /******************************************************************************
02238 Get the value of an item from a binary file, and place the result
02239 into an integer, an unsigned integer and a double.
02240 
02241 Entry:
02242   fp   - file to get item from
02243   type - data type supposedly in the word
02244 
02245 Exit:
02246   int_val    - integer value
02247   uint_val   - unsigned integer value
02248   double_val - double-precision floating point value
02249 ******************************************************************************/
02250 
02251 void get_binary_item(
02252   PlyFile *plyfile,
02253   int type,
02254   int *int_val,
02255   unsigned int *uint_val,
02256   double *double_val
02257 )
02258 {
02259   char c[8];
02260   void *ptr;
02261 
02262   ptr = (void *) c;
02263 
02264   switch (type) {
02265     case PLY_CHAR:
02266       if( fread (ptr, 1, 1, plyfile->fp) <= 0 )
02267           abort();
02268       *int_val = *((char *) ptr);
02269       *uint_val = *int_val;
02270       *double_val = *int_val;
02271       break;
02272       case PLY_UCHAR:
02273       case PLY_UINT8:
02274           if( fread (ptr, 1, 1, plyfile->fp) <= 0 )
02275               abort();
02276           *uint_val = *((unsigned char *) ptr);
02277           *int_val = *uint_val;
02278           *double_val = *uint_val;
02279           break;
02280       case PLY_SHORT:
02281           if( fread (ptr, 2, 1, plyfile->fp) <= 0 )
02282               abort();
02283           if( plyfile->file_type == PLY_BINARY_BE )
02284           {
02285               swap2BE(ptr);
02286           }
02287           else
02288           {
02289               swap2LE(ptr);
02290           }
02291           *int_val = *((short int *) ptr);
02292           *uint_val = *int_val;
02293           *double_val = *int_val;
02294           break;
02295       case PLY_USHORT:
02296           if( fread (ptr, 2, 1, plyfile->fp) <= 0 )
02297               abort();
02298           if( plyfile->file_type == PLY_BINARY_BE )
02299           {
02300               swap2BE(ptr);
02301           }
02302           else
02303           {
02304               swap2LE(ptr);
02305           }
02306           *uint_val = *((unsigned short int *) ptr);
02307           *int_val = *uint_val;
02308           *double_val = *uint_val;
02309           break;
02310       case PLY_INT:
02311       case PLY_INT32:
02312           if( fread (ptr, 4, 1, plyfile->fp) <= 0 )
02313               abort();
02314           if( plyfile->file_type == PLY_BINARY_BE )
02315           {
02316               swap4BE(ptr);
02317           }
02318           else
02319           {
02320               swap4LE(ptr);
02321           }
02322           *int_val = *((int *) ptr);
02323           *uint_val = *int_val;
02324           *double_val = *int_val;
02325           break;
02326       case PLY_UINT:
02327           if( fread (ptr, 4, 1, plyfile->fp) <= 0 )
02328               abort();
02329           if( plyfile->file_type == PLY_BINARY_BE )
02330           {
02331               swap4BE(ptr);
02332           }
02333           else
02334           {
02335               swap4LE(ptr);
02336           }
02337           *uint_val = *((unsigned int *) ptr);
02338           *int_val = *uint_val;
02339           *double_val = *uint_val;
02340           break;
02341       case PLY_FLOAT:
02342       case PLY_FLOAT32:
02343           if( fread (ptr, 4, 1, plyfile->fp) <= 0 )
02344               abort();
02345           if( plyfile->file_type == PLY_BINARY_BE )
02346           {
02347               swap4BE(ptr);
02348           }
02349           else
02350           {
02351               swap4LE(ptr);
02352           }
02353           *double_val = *((float *) ptr);
02354           *int_val = (int) *double_val;
02355           *uint_val = (unsigned int) *double_val;
02356           break;
02357       case PLY_DOUBLE:
02358           if( fread (ptr, 8, 1, plyfile->fp) <= 0 )
02359               abort();
02360           if( plyfile->file_type == PLY_BINARY_BE )
02361           {
02362               swap8BE(ptr);
02363           }
02364           else
02365           {
02366               swap8LE(ptr);
02367           }
02368       *double_val = *((double *) ptr);
02369       *int_val = (int) *double_val;
02370       *uint_val = (unsigned int) *double_val;
02371       break;
02372     default:
02373       fprintf (stderr, "get_binary_item: bad type = %d\n", type);
02374       exit (-1);
02375   }
02376 }
02377 
02378 
02379 /******************************************************************************
02380 Extract the value of an item from an ascii word, and place the result
02381 into an integer, an unsigned integer and a double.
02382 
02383 Entry:
02384   word - word to extract value from
02385   type - data type supposedly in the word
02386 
02387 Exit:
02388   int_val    - integer value
02389   uint_val   - unsigned integer value
02390   double_val - double-precision floating point value
02391 ******************************************************************************/
02392 
02393 void get_ascii_item(
02394   char *word,
02395   int type,
02396   int *int_val,
02397   unsigned int *uint_val,
02398   double *double_val
02399 )
02400 {
02401   switch (type) {
02402     case PLY_CHAR:
02403     case PLY_UCHAR:
02404     case PLY_UINT8:
02405     case PLY_SHORT:
02406     case PLY_USHORT:
02407     case PLY_INT:
02408     case PLY_INT32:
02409       *int_val = atoi (word);
02410       *uint_val = *int_val;
02411       *double_val = *int_val;
02412       break;
02413 
02414     case PLY_UINT:
02415       *uint_val = strtoul (word, (char **) NULL, 10);
02416       *int_val = *uint_val;
02417       *double_val = *uint_val;
02418       break;
02419 
02420     case PLY_FLOAT:
02421     case PLY_FLOAT32:
02422     case PLY_DOUBLE:
02423       *double_val = atof (word);
02424       *int_val = (int) *double_val;
02425       *uint_val = (unsigned int) *double_val;
02426       break;
02427 
02428     default:
02429       fprintf (stderr, "get_ascii_item: bad type = %d\n", type);
02430       exit (-1);
02431   }
02432 }
02433 
02434 
02435 /******************************************************************************
02436 Store a value into a place being pointed to, guided by a data type.
02437 
02438 Entry:
02439   item       - place to store value
02440   type       - data type
02441   int_val    - integer version of value
02442   uint_val   - unsigned integer version of value
02443   double_val - double version of value
02444 
02445 Exit:
02446   item - pointer to stored value
02447 ******************************************************************************/
02448 
02449 void store_item (
02450   char *item,
02451   int type,
02452   int int_val,
02453   unsigned int uint_val,
02454   double double_val
02455 )
02456 {
02457   unsigned char *puchar;
02458   short int *pshort;
02459   unsigned short int *pushort;
02460   int *pint;
02461   unsigned int *puint;
02462   float *pfloat;
02463   double *pdouble;
02464 
02465   switch (type) {
02466     case PLY_CHAR:
02467       *item = int_val;
02468       break;
02469     case PLY_UCHAR:
02470     case PLY_UINT8:
02471       puchar = (unsigned char *) item;
02472       *puchar = uint_val;
02473       break;
02474     case PLY_SHORT:
02475       pshort = (short *) item;
02476       *pshort = int_val;
02477       break;
02478     case PLY_USHORT:
02479       pushort = (unsigned short *) item;
02480       *pushort = uint_val;
02481       break;
02482     case PLY_INT:
02483     case PLY_INT32:
02484       pint = (int *) item;
02485       *pint = int_val;
02486       break;
02487     case PLY_UINT:
02488       puint = (unsigned int *) item;
02489       *puint = uint_val;
02490       break;
02491     case PLY_FLOAT:
02492     case PLY_FLOAT32:
02493       pfloat = (float *) item;
02494       *pfloat = double_val;
02495       break;
02496     case PLY_DOUBLE:
02497       pdouble = (double *) item;
02498       *pdouble = double_val;
02499       break;
02500     default:
02501       fprintf (stderr, "store_item: bad type = %d\n", type);
02502       exit (-1);
02503   }
02504 }
02505 
02506 
02507 /******************************************************************************
02508 Add an element to a PLY file descriptor.
02509 
02510 Entry:
02511   plyfile - PLY file descriptor
02512   words   - list of words describing the element
02513   nwords  - number of words in the list
02514 ******************************************************************************/
02515 
02516 void add_element (PlyFile *plyfile, char **words, int)
02517 {
02518   PlyElement *elem;
02519 
02520   /* create the new element */
02521   elem = (PlyElement *) myalloc (sizeof (PlyElement));
02522   elem->name = strdup (words[1]);
02523   elem->num = atoi (words[2]);
02524   elem->nprops = 0;
02525 
02526   /* make room for new element in the object's list of elements */
02527   if (plyfile->nelems == 0)
02528     plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
02529   else
02530     plyfile->elems = (PlyElement **) realloc (plyfile->elems,
02531                      sizeof (PlyElement *) * (plyfile->nelems + 1));
02532 
02533   /* add the new element to the object's list */
02534   plyfile->elems[plyfile->nelems] = elem;
02535   plyfile->nelems++;
02536 }
02537 
02538 
02539 /******************************************************************************
02540 Return the type of a property, given the name of the property.
02541 
02542 Entry:
02543   name - name of property type
02544 
02545 Exit:
02546   returns integer code for property, or 0 if not found
02547 ******************************************************************************/
02548 
02549 int get_prop_type(char *type_name)
02550 {
02551   int i;
02552 
02553   for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
02554     if (equal_strings (type_name, type_names[i]))
02555       return (i);
02556 
02557   /* if we get here, we didn't find the type */
02558   return (0);
02559 }
02560 
02561 
02562 /******************************************************************************
02563 Add a property to a PLY file descriptor.
02564 
02565 Entry:
02566   plyfile - PLY file descriptor
02567   words   - list of words describing the property
02568   nwords  - number of words in the list
02569 ******************************************************************************/
02570 
02571 void add_property (PlyFile *plyfile, char **words, int )
02572 {
02573   PlyProperty *prop;
02574   PlyElement *elem;
02575 
02576   /* create the new property */
02577 
02578   prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
02579 
02580   if (equal_strings (words[1], "list")) {       /* is a list */
02581     prop->count_external = get_prop_type (words[2]);
02582     prop->external_type = get_prop_type (words[3]);
02583     prop->name = strdup (words[4]);
02584     prop->is_list = 1;
02585   }
02586   else {                                        /* not a list */
02587     prop->external_type = get_prop_type (words[1]);
02588     prop->name = strdup (words[2]);
02589     prop->is_list = 0;
02590   }
02591 
02592   /* add this property to the list of properties of the current element */
02593 
02594   elem = plyfile->elems[plyfile->nelems - 1];
02595 
02596   if (elem->nprops == 0)
02597     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
02598   else
02599     elem->props = (PlyProperty **) realloc (elem->props,
02600                   sizeof (PlyProperty *) * (elem->nprops + 1));
02601 
02602   elem->props[elem->nprops] = prop;
02603   elem->nprops++;
02604 }
02605 
02606 
02607 /******************************************************************************
02608 Add a comment to a PLY file descriptor.
02609 
02610 Entry:
02611   plyfile - PLY file descriptor
02612   line    - line containing comment
02613 ******************************************************************************/
02614 
02615 void add_comment (PlyFile *plyfile, char *line)
02616 {
02617   int i;
02618 
02619   /* skip over "comment" and leading spaces and tabs */
02620   i = 7;
02621   while (line[i] == ' ' || line[i] == '\t')
02622     i++;
02623 
02624   ply_put_comment (plyfile, &line[i]);
02625 }
02626 
02627 
02628 /******************************************************************************
02629 Add a some object information to a PLY file descriptor.
02630 
02631 Entry:
02632   plyfile - PLY file descriptor
02633   line    - line containing text info
02634 ******************************************************************************/
02635 
02636 void add_obj_info (PlyFile *plyfile, char *line)
02637 {
02638   int i;
02639 
02640   /* skip over "obj_info" and leading spaces and tabs */
02641   i = 8;
02642   while (line[i] == ' ' || line[i] == '\t')
02643     i++;
02644 
02645   ply_put_obj_info (plyfile, &line[i]);
02646 }
02647 
02648 
02649 /******************************************************************************
02650 Copy a property.
02651 ******************************************************************************/
02652 
02653 void copy_property(PlyProperty *dest, PlyProperty *src)
02654 {
02655   dest->name = strdup (src->name);
02656   dest->external_type = src->external_type;
02657   dest->internal_type = src->internal_type;
02658   dest->offset = src->offset;
02659 
02660   dest->is_list = src->is_list;
02661   dest->count_external = src->count_external;
02662   dest->count_internal = src->count_internal;
02663   dest->count_offset = src->count_offset;
02664 }
02665 
02666 
02667 /******************************************************************************
02668 Allocate some memory.
02669 
02670 Entry:
02671   size  - amount of memory requested (in bytes)
02672   lnum  - line number from which memory was requested
02673   fname - file name from which memory was requested
02674 ******************************************************************************/
02675 
02676 char *my_alloc(int size, int lnum, const char *fname)
02677 {
02678   char *ptr;
02679 
02680   ptr = (char *) malloc (size);
02681 
02682   if (ptr == 0) 
02683       fprintf( stderr, "Memory allocation bombed on line %d in %s\n", 
02684                lnum, fname);
02685 
02686   return (ptr);
02687 }
02688 
Generated on Mon Aug 10 18:58:40 2009 for Equalizer 0.9 by  doxygen 1.5.8