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