Blender V2.61 - r43446

plyfile.c

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