Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ply.C

Go to the documentation of this file.
00001 /*
00002 
00003 The interface routines for reading and writing PLY polygon files.
00004 
00005 Greg Turk
00006 
00007 ---------------------------------------------------------------
00008 
00009 A PLY file contains a single polygonal _object_.
00010 
00011 An object is composed of lists of _elements_.  Typical elements are
00012 vertices, faces, edges and materials.
00013 
00014 Each type of element for a given object has one or more _properties_
00015 associated with the element type.  For instance, a vertex element may
00016 have as properties the floating-point values x,y,z and the three unsigned
00017 chars representing red, green and blue.
00018 
00019 -----------------------------------------------------------------------
00020 
00021 Copyright (c) 1998 Georgia Institute of Technology.  All rights reserved.   
00022   
00023 Permission to use, copy, modify and distribute this software and its   
00024 documentation for any purpose is hereby granted without fee, provided   
00025 that the above copyright notice and this permission notice appear in   
00026 all copies of this software and that you do not sell the software.   
00027   
00028 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,   
00029 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY   
00030 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   
00031 
00032 */
00033 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <math.h>
00037 #include <string.h>
00038 
00039 #include "ply.H"
00040 
00041 char *type_names[] = {  /* names of scalar types */
00042 "invalid",
00043 "int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64",
00044 };
00045 
00046 char *old_type_names[] = {  /* old names of types for backward compatability */
00047 "invalid",
00048 "char", "short", "int", "uchar", "ushort", "uint", "float", "double",
00049 };
00050 
00051 int ply_type_size[] = {
00052   0, 1, 2, 4, 1, 2, 4, 4, 8
00053 };
00054 
00055 #define NO_OTHER_PROPS  -1
00056 
00057 #define DONT_STORE_PROP  0
00058 #define STORE_PROP       1
00059 
00060 #define OTHER_PROP       0
00061 #define NAMED_PROP       1
00062 
00063 /* returns 1 if strings are equal, 0 if not */
00064 int equal_strings(char *, char *);
00065 
00066 /* find an element in a plyfile's list */
00067 PlyElement *find_element(PlyFile *, char *);
00068 
00069 /* find a property in an element's list */
00070 PlyProperty *find_property(PlyElement *, char *, int *);
00071 
00072 /* write to a file the word describing a PLY file data type */
00073 void write_scalar_type (FILE *, int);
00074 
00075 /* read a line from a file and break it up into separate words */
00076 char **get_words(FILE *, int *, char **);
00077 
00078 /* write an item to a file */
00079 void write_binary_item(FILE *, int, unsigned int, double, int);
00080 void write_ascii_item(FILE *, int, unsigned int, double, int);
00081 
00082 /* add information to a PLY file descriptor */
00083 void add_element(PlyFile *, char **, int);
00084 void add_property(PlyFile *, char **, int);
00085 void add_comment(PlyFile *, char *);
00086 void add_obj_info(PlyFile *, char *);
00087 
00088 /* copy a property */
00089 void copy_property(PlyProperty *, PlyProperty *);
00090 
00091 /* store a value into where a pointer and a type specify */
00092 void store_item(char *, int, int, unsigned int, double);
00093 
00094 /* return the value of a stored item */
00095 void get_stored_item( void *, int, int *, unsigned int *, double *);
00096 
00097 /* return the value stored in an item, given ptr to it and its type */
00098 double get_item_value(char *, int);
00099 
00100 /* get binary or ascii item and store it according to ptr and type */
00101 void get_ascii_item(char *, int, int *, unsigned int *, double *);
00102 void get_binary_item(FILE *, int, int *, unsigned int *, double *);
00103 
00104 /* get a bunch of elements from a file */
00105 void ascii_get_element(PlyFile *, char *);
00106 void binary_get_element(PlyFile *, char *);
00107 
00108 /* memory allocation */
00109 static char *my_alloc(int, int, char *);
00110 
00111 
00112 /*************/
00113 /*  Writing  */
00114 /*************/
00115 
00116 
00117 /******************************************************************************
00118 Given a file pointer, get ready to write PLY data to the file.
00119 
00120 Entry:
00121   fp         - the given file pointer
00122   nelems     - number of elements in object
00123   elem_names - list of element names
00124   file_type  - file type, either ascii or binary
00125 
00126 Exit:
00127   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
00128 ******************************************************************************/
00129 
00130 PlyFile *ply_write(
00131   FILE *fp,
00132   int nelems,
00133   char **elem_names,
00134   int file_type
00135 )
00136 {
00137   int i;
00138   PlyFile *plyfile;
00139   PlyElement *elem;
00140 
00141   /* check for NULL file pointer */
00142   if (fp == NULL)
00143     return (NULL);
00144 
00145   /* create a record for this object */
00146 
00147   plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
00148   plyfile->file_type = file_type;
00149   plyfile->num_comments = 0;
00150   plyfile->num_obj_info = 0;
00151   plyfile->num_elem_types = nelems;
00152   plyfile->version = 1.0;
00153   plyfile->fp = fp;
00154   plyfile->other_elems = NULL;
00155 
00156   /* tuck aside the names of the elements */
00157 
00158   plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems);
00159   for (i = 0; i < nelems; i++) {
00160     elem = (PlyElement *) myalloc (sizeof (PlyElement));
00161     plyfile->elems[i] = elem;
00162     elem->name = strdup (elem_names[i]);
00163     elem->num = 0;
00164     elem->nprops = 0;
00165   }
00166 
00167   /* return pointer to the file descriptor */
00168   return (plyfile);
00169 }
00170 
00171 
00172 /******************************************************************************
00173 Open a polygon file for writing.
00174 
00175 Entry:
00176   filename   - name of file to read from
00177   nelems     - number of elements in object
00178   elem_names - list of element names
00179   file_type  - file type, either ascii or binary
00180 
00181 Exit:
00182   returns a file identifier, used to refer to this file, or NULL if error
00183 ******************************************************************************/
00184 
00185 PlyFile *open_for_writing_ply(
00186   char *filename,
00187   int nelems,
00188   char **elem_names,
00189   int file_type
00190 )
00191 {
00192   int i;
00193   PlyFile *plyfile;
00194   PlyElement *elem;
00195   char *name;
00196   FILE *fp;
00197 
00198   /* tack on the extension .ply, if necessary */
00199 
00200   name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
00201   strcpy (name, filename);
00202   if (strlen (name) < 4 ||
00203       strcmp (name + strlen (name) - 4, ".ply") != 0)
00204       strcat (name, ".ply");
00205 
00206   /* open the file for writing */
00207 
00208   fp = fopen (name, "w");
00209   if (fp == NULL) {
00210     return (NULL);
00211   }
00212 
00213   /* create the actual PlyFile structure */
00214 
00215   plyfile = ply_write (fp, nelems, elem_names, file_type);
00216   if (plyfile == NULL)
00217     return (NULL);
00218 
00219   /* return pointer to the file descriptor */
00220   return (plyfile);
00221 }
00222 
00223 
00224 /******************************************************************************
00225 Describe an element, including its properties and how many will be written
00226 to the file.
00227 
00228 Entry:
00229   plyfile   - file identifier
00230   elem_name - name of element that information is being specified about
00231   nelems    - number of elements of this type to be written
00232   nprops    - number of properties contained in the element
00233   prop_list - list of properties
00234 ******************************************************************************/
00235 
00236 void element_layout_ply(
00237   PlyFile *plyfile,
00238   char *elem_name,
00239   int nelems,
00240   int nprops,
00241   PlyProperty *prop_list
00242 )
00243 {
00244   int i;
00245   PlyElement *elem;
00246   PlyProperty *prop;
00247 
00248   /* look for appropriate element */
00249   elem = find_element (plyfile, elem_name);
00250   if (elem == NULL) {
00251     fprintf(stderr,"element_layout_ply: can't find element '%s'\n",elem_name);
00252     exit (-1);
00253   }
00254 
00255   elem->num = nelems;
00256 
00257   /* copy the list of properties */
00258 
00259   elem->nprops = nprops;
00260   elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops);
00261   elem->store_prop = (char *) myalloc (sizeof (char) * nprops);
00262 
00263   for (i = 0; i < nprops; i++) {
00264     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00265     elem->props[i] = prop;
00266     elem->store_prop[i] = NAMED_PROP;
00267     copy_property (prop, &prop_list[i]);
00268   }
00269 }
00270 
00271 
00272 /******************************************************************************
00273 Describe a property of an element.
00274 
00275 Entry:
00276   plyfile   - file identifier
00277   elem_name - name of element that information is being specified about
00278   prop      - the new property
00279 ******************************************************************************/
00280 
00281 void ply_describe_property(
00282   PlyFile *plyfile,
00283   char *elem_name,
00284   PlyProperty *prop
00285 )
00286 {
00287   PlyElement *elem;
00288   PlyProperty *elem_prop;
00289 
00290   /* look for appropriate element */
00291   elem = find_element (plyfile, elem_name);
00292   if (elem == NULL) {
00293     fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
00294             elem_name);
00295     return;
00296   }
00297 
00298   /* create room for new property */
00299 
00300   if (elem->nprops == 0) {
00301     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
00302     elem->store_prop = (char *) myalloc (sizeof (char));
00303     elem->nprops = 1;
00304   }
00305   else {
00306     elem->nprops++;
00307     elem->props = (PlyProperty **)
00308                   realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
00309     elem->store_prop = (char *)
00310                   realloc (elem->store_prop, sizeof (char) * elem->nprops);
00311   }
00312 
00313   /* copy the new property */
00314 
00315   elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00316   elem->props[elem->nprops - 1] = elem_prop;
00317   elem->store_prop[elem->nprops - 1] = NAMED_PROP;
00318   copy_property (elem_prop, prop);
00319 }
00320 
00321 
00322 /******************************************************************************
00323 State how many of a given element will be written.
00324 
00325 Entry:
00326   plyfile   - file identifier
00327   elem_name - name of element that information is being specified about
00328   nelems    - number of elements of this type to be written
00329 ******************************************************************************/
00330 
00331 void element_count_ply(
00332   PlyFile *plyfile,
00333   char *elem_name,
00334   int nelems
00335 )
00336 {
00337   int i;
00338   PlyElement *elem;
00339   PlyProperty *prop;
00340 
00341   /* look for appropriate element */
00342   elem = find_element (plyfile, elem_name);
00343   if (elem == NULL) {
00344     fprintf(stderr,"element_count_ply: can't find element '%s'\n",elem_name);
00345     exit (-1);
00346   }
00347 
00348   elem->num = nelems;
00349 }
00350 
00351 
00352 /******************************************************************************
00353 Signal that we've described everything a PLY file's header and that the
00354 header should be written to the file.
00355 
00356 Entry:
00357   plyfile - file identifier
00358 ******************************************************************************/
00359 
00360 void header_complete_ply(PlyFile *plyfile)
00361 {
00362   int i,j;
00363   FILE *fp = plyfile->fp;
00364   PlyElement *elem;
00365   PlyProperty *prop;
00366 
00367   fprintf (fp, "ply\n");
00368 
00369   switch (plyfile->file_type) {
00370     case PLY_ASCII:
00371       fprintf (fp, "format ascii 1.0\n");
00372       break;
00373     case PLY_BINARY_BE:
00374       fprintf (fp, "format binary_big_endian 1.0\n");
00375       break;
00376     case PLY_BINARY_LE:
00377       fprintf (fp, "format binary_little_endian 1.0\n");
00378       break;
00379     default:
00380       fprintf (stderr, "ply_header_complete: bad file type = %d\n",
00381                plyfile->file_type);
00382       exit (-1);
00383   }
00384 
00385   /* write out the comments */
00386 
00387   for (i = 0; i < plyfile->num_comments; i++)
00388     fprintf (fp, "comment %s\n", plyfile->comments[i]);
00389 
00390   /* write out object information */
00391 
00392   for (i = 0; i < plyfile->num_obj_info; i++)
00393     fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]);
00394 
00395   /* write out information about each element */
00396 
00397   for (i = 0; i < plyfile->num_elem_types; i++) {
00398 
00399     elem = plyfile->elems[i];
00400     fprintf (fp, "element %s %d\n", elem->name, elem->num);
00401 
00402     /* write out each property */
00403     for (j = 0; j < elem->nprops; j++) {
00404       prop = elem->props[j];
00405       if (prop->is_list == PLY_LIST) {
00406         fprintf (fp, "property list ");
00407         write_scalar_type (fp, prop->count_external);
00408         fprintf (fp, " ");
00409         write_scalar_type (fp, prop->external_type);
00410         fprintf (fp, " %s\n", prop->name);
00411       }
00412       else if (prop->is_list == PLY_STRING) {
00413         fprintf (fp, "property string");
00414         fprintf (fp, " %s\n", prop->name);
00415       }
00416       else {
00417         fprintf (fp, "property ");
00418         write_scalar_type (fp, prop->external_type);
00419         fprintf (fp, " %s\n", prop->name);
00420       }
00421     }
00422   }
00423 
00424   fprintf (fp, "end_header\n");
00425 }
00426 
00427 
00428 /******************************************************************************
00429 Specify which elements are going to be written.  This should be called
00430 before a call to the routine ply_put_element().
00431 
00432 Entry:
00433   plyfile   - file identifier
00434   elem_name - name of element we're talking about
00435 ******************************************************************************/
00436 
00437 void put_element_setup_ply(PlyFile *plyfile, char *elem_name)
00438 {
00439   PlyElement *elem;
00440 
00441   elem = find_element (plyfile, elem_name);
00442   if (elem == NULL) {
00443     fprintf(stderr, "put_element_setup_ply: can't find element '%s'\n", elem_name);
00444     exit (-1);
00445   }
00446 
00447   plyfile->which_elem = elem;
00448 }
00449 
00450 
00451 /******************************************************************************
00452 Write an element to the file.  This routine assumes that we're
00453 writing the type of element specified in the last call to the routine
00454 put_element_setup_ply().
00455 
00456 Entry:
00457   plyfile  - file identifier
00458   elem_ptr - pointer to the element
00459 ******************************************************************************/
00460 
00461 void put_element_ply(PlyFile *plyfile, void *elem_ptr)
00462 {
00463   int i,j,k;
00464   FILE *fp = plyfile->fp;
00465   PlyElement *elem;
00466   PlyProperty *prop;
00467   char *item;
00468   char *elem_data;
00469   char **item_ptr;
00470   int list_count;
00471   int item_size;
00472   int int_val;
00473   unsigned int uint_val;
00474   double double_val;
00475   char **other_ptr;
00476 
00477   elem = plyfile->which_elem;
00478   elem_data = (char *) elem_ptr;
00479   other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
00480 
00481   /* write out either to an ascii or binary file */
00482 
00483   if (plyfile->file_type == PLY_ASCII) {
00484 
00485     /* write an ascii file */
00486 
00487     /* write out each property of the element */
00488     for (j = 0; j < elem->nprops; j++) {
00489 
00490       prop = elem->props[j];
00491 
00492       if (elem->store_prop[j] == OTHER_PROP)
00493         elem_data = *other_ptr;
00494       else
00495         elem_data = (char *) elem_ptr;
00496 
00497       if (prop->is_list == PLY_LIST) {  /* list */
00498         item = elem_data + prop->count_offset;
00499         get_stored_item ((void *) item, prop->count_internal,
00500                          &int_val, &uint_val, &double_val);
00501         write_ascii_item (fp, int_val, uint_val, double_val,
00502                           prop->count_external);
00503         list_count = uint_val;
00504         item_ptr = (char **) (elem_data + prop->offset);
00505         item = item_ptr[0];
00506         item_size = ply_type_size[prop->internal_type];
00507         for (k = 0; k < list_count; k++) {
00508           get_stored_item ((void *) item, prop->internal_type,
00509                            &int_val, &uint_val, &double_val);
00510           write_ascii_item (fp, int_val, uint_val, double_val,
00511                             prop->external_type);
00512           item += item_size;
00513         }
00514       }
00515       else if (prop->is_list == PLY_STRING) {  /* string */
00516    char **str;
00517         item = elem_data + prop->offset;
00518    str = (char **) item;
00519    fprintf (fp, "\"%s\"", *str);
00520       }
00521       else {                                  /* scalar */
00522         item = elem_data + prop->offset;
00523         get_stored_item ((void *) item, prop->internal_type,
00524                          &int_val, &uint_val, &double_val);
00525         write_ascii_item (fp, int_val, uint_val, double_val,
00526                           prop->external_type);
00527       }
00528     }
00529 
00530     fprintf (fp, "\n");
00531   }
00532   else {
00533 
00534     /* write a binary file */
00535 
00536     /* write out each property of the element */
00537     for (j = 0; j < elem->nprops; j++) {
00538       prop = elem->props[j];
00539       if (elem->store_prop[j] == OTHER_PROP)
00540         elem_data = *other_ptr;
00541       else
00542         elem_data = (char *) elem_ptr;
00543       if (prop->is_list == PLY_LIST) {   /* list */
00544         item = elem_data + prop->count_offset;
00545         item_size = ply_type_size[prop->count_internal];
00546         get_stored_item ((void *) item, prop->count_internal,
00547                          &int_val, &uint_val, &double_val);
00548         write_binary_item (fp, int_val, uint_val, double_val,
00549                            prop->count_external);
00550         list_count = uint_val;
00551         item_ptr = (char **) (elem_data + prop->offset);
00552         item = item_ptr[0];
00553         item_size = ply_type_size[prop->internal_type];
00554         for (k = 0; k < list_count; k++) {
00555           get_stored_item ((void *) item, prop->internal_type,
00556                            &int_val, &uint_val, &double_val);
00557           write_binary_item (fp, int_val, uint_val, double_val,
00558                              prop->external_type);
00559           item += item_size;
00560         }
00561       }
00562       else if (prop->is_list == PLY_STRING) {   /* string */
00563    int len;
00564    char **str;
00565         item = elem_data + prop->offset;
00566    str = (char **) item;
00567 
00568    /* write the length */
00569    len = strlen(*str) + 1;
00570    fwrite (&len, sizeof(int), 1, fp);
00571 
00572    /* write the string, including the null character */
00573    fwrite (*str, len, 1, fp);
00574       }
00575       else {                   /* scalar */
00576         item = elem_data + prop->offset;
00577         item_size = ply_type_size[prop->internal_type];
00578         get_stored_item ((void *) item, prop->internal_type,
00579                          &int_val, &uint_val, &double_val);
00580         write_binary_item (fp, int_val, uint_val, double_val,
00581                            prop->external_type);
00582       }
00583     }
00584 
00585   }
00586 }
00587 
00588 
00589 
00590 
00591 
00592 
00593 /*************/
00594 /*  Reading  */
00595 /*************/
00596 
00597 
00598 
00599 /******************************************************************************
00600 Given a file pointer, get ready to read PLY data from the file.
00601 
00602 Entry:
00603   fp - the given file pointer
00604 
00605 Exit:
00606   nelems     - number of elements in object
00607   elem_names - list of element names
00608   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
00609 ******************************************************************************/
00610 
00611 PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
00612 {
00613   int i,j;
00614   PlyFile *plyfile;
00615   int nwords;
00616   char **words;
00617   int found_format = 0;
00618   char **elist;
00619   PlyElement *elem;
00620   char *orig_line;
00621 
00622   /* check for NULL file pointer */
00623   if (fp == NULL)
00624     return (NULL);
00625 
00626   /* create record for this object */
00627 
00628   plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
00629   plyfile->num_elem_types = 0;
00630   plyfile->comments = NULL;
00631   plyfile->num_comments = 0;
00632   plyfile->obj_info = NULL;
00633   plyfile->num_obj_info = 0;
00634   plyfile->fp = fp;
00635   plyfile->other_elems = NULL;
00636   plyfile->rule_list = NULL;
00637 
00638   /* read and parse the file's header */
00639 
00640   words = get_words (plyfile->fp, &nwords, &orig_line);
00641   if (!words || !equal_strings (words[0], "ply"))
00642     return (NULL);
00643 
00644   while (words) {
00645 
00646     /* parse words */
00647 
00648     if (equal_strings (words[0], "format")) {
00649       if (nwords != 3)
00650         return (NULL);
00651       if (equal_strings (words[1], "ascii"))
00652         plyfile->file_type = PLY_ASCII;
00653       else if (equal_strings (words[1], "binary_big_endian"))
00654         plyfile->file_type = PLY_BINARY_BE;
00655       else if (equal_strings (words[1], "binary_little_endian"))
00656         plyfile->file_type = PLY_BINARY_LE;
00657       else
00658         return (NULL);
00659       plyfile->version = atof (words[2]);
00660       found_format = 1;
00661     }
00662     else if (equal_strings (words[0], "element"))
00663       add_element (plyfile, words, nwords);
00664     else if (equal_strings (words[0], "property"))
00665       add_property (plyfile, words, nwords);
00666     else if (equal_strings (words[0], "comment"))
00667       add_comment (plyfile, orig_line);
00668     else if (equal_strings (words[0], "obj_info"))
00669       add_obj_info (plyfile, orig_line);
00670     else if (equal_strings (words[0], "end_header"))
00671       break;
00672 
00673     /* free up words space */
00674     free (words);
00675 
00676     words = get_words (plyfile->fp, &nwords, &orig_line);
00677   }
00678 
00679   /* create tags for each property of each element, to be used */
00680   /* later to say whether or not to store each property for the user */
00681 
00682   for (i = 0; i < plyfile->num_elem_types; i++) {
00683     elem = plyfile->elems[i];
00684     elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
00685     for (j = 0; j < elem->nprops; j++)
00686       elem->store_prop[j] = DONT_STORE_PROP;
00687     elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
00688   }
00689 
00690   /* set return values about the elements */
00691 
00692   elist = (char **) myalloc (sizeof (char *) * plyfile->num_elem_types);
00693   for (i = 0; i < plyfile->num_elem_types; i++)
00694     elist[i] = strdup (plyfile->elems[i]->name);
00695 
00696   *elem_names = elist;
00697   *nelems = plyfile->num_elem_types;
00698 
00699   /* return a pointer to the file's information */
00700 
00701   return (plyfile);
00702 }
00703 
00704 
00705 /******************************************************************************
00706 Open a polygon file for reading.
00707 
00708 Entry:
00709   filename - name of file to read from
00710 
00711 Exit:
00712   nelems     - number of elements in object
00713   elem_names - list of element names
00714   file_type  - file type, either ascii or binary
00715   version    - version number of PLY file
00716   returns a file identifier, used to refer to this file, or NULL if error
00717 ******************************************************************************/
00718 
00719 PlyFile *ply_open_for_reading(
00720   char *filename,
00721   int *nelems,
00722   char ***elem_names,
00723   int *file_type,
00724   float *version
00725 )
00726 {
00727   FILE *fp;
00728   PlyFile *plyfile;
00729   char *name;
00730 
00731   /* tack on the extension .ply, if necessary */
00732 
00733   name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
00734   strcpy (name, filename);
00735   if (strlen (name) < 4 ||
00736       strcmp (name + strlen (name) - 4, ".ply") != 0)
00737       strcat (name, ".ply");
00738 
00739   /* open the file for reading */
00740 
00741   fp = fopen (name, "r");
00742   if (fp == NULL)
00743     return (NULL);
00744 
00745   /* create the PlyFile data structure */
00746 
00747   plyfile = ply_read (fp, nelems, elem_names);
00748 
00749   /* determine the file type and version */
00750 
00751   *file_type = plyfile->file_type;
00752   *version = plyfile->version;
00753 
00754   /* return a pointer to the file's information */
00755 
00756   return (plyfile);
00757 }
00758 
00759 
00760 /******************************************************************************
00761 Get information about a particular element.
00762 
00763 Entry:
00764   plyfile   - file identifier
00765   elem_name - name of element to get information about
00766 
00767 Exit:
00768   nelems   - number of elements of this type in the file
00769   nprops   - number of properties
00770   returns a list of properties, or NULL if the file doesn't contain that elem
00771 ******************************************************************************/
00772 
00773 PlyProperty **get_element_description_ply(
00774   PlyFile *plyfile,
00775   char *elem_name,
00776   int *nelems,
00777   int *nprops
00778 )
00779 {
00780   int i;
00781   PlyElement *elem;
00782   PlyProperty *prop;
00783   PlyProperty **prop_list;
00784 
00785   /* find information about the element */
00786   elem = find_element (plyfile, elem_name);
00787   if (elem == NULL)
00788     return (NULL);
00789 
00790   *nelems = elem->num;
00791   *nprops = elem->nprops;
00792 
00793   /* make a copy of the element's property list */
00794   prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
00795   for (i = 0; i < elem->nprops; i++) {
00796     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00797     copy_property (prop, elem->props[i]);
00798     prop_list[i] = prop;
00799   }
00800 
00801   /* return this duplicate property list */
00802   return (prop_list);
00803 }
00804 
00805 
00806 /******************************************************************************
00807 Specify which properties of an element are to be returned.  This should be
00808 called before a call to the routine get_element_ply().
00809 
00810 Entry:
00811   plyfile   - file identifier
00812   elem_name - which element we're talking about
00813   nprops    - number of properties
00814   prop_list - list of properties
00815 ******************************************************************************/
00816 
00817 void get_element_setup_ply(
00818   PlyFile *plyfile,
00819   char *elem_name,
00820   int nprops,
00821   PlyProperty *prop_list
00822 )
00823 {
00824   int i;
00825   PlyElement *elem;
00826   PlyProperty *prop;
00827   int index;
00828 
00829   /* find information about the element */
00830   elem = find_element (plyfile, elem_name);
00831   plyfile->which_elem = elem;
00832 
00833   /* deposit the property information into the element's description */
00834   for (i = 0; i < nprops; i++) {
00835 
00836     /* look for actual property */
00837     prop = find_property (elem, prop_list[i].name, &index);
00838     if (prop == NULL) {
00839       fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
00840                prop_list[i].name, elem_name);
00841       continue;
00842     }
00843 
00844     /* store its description */
00845     prop->internal_type = prop_list[i].internal_type;
00846     prop->offset = prop_list[i].offset;
00847     prop->count_internal = prop_list[i].count_internal;
00848     prop->count_offset = prop_list[i].count_offset;
00849 
00850     /* specify that the user wants this property */
00851     elem->store_prop[index] = STORE_PROP;
00852   }
00853 }
00854 
00855 
00856 /******************************************************************************
00857 Specify a property of an element that is to be returned.  This should be
00858 called (usually multiple times) before a call to the routine ply_get_element().
00859 This routine should be used in preference to the less flexible old routine
00860 called ply_get_element_setup().
00861 
00862 Entry:
00863   plyfile   - file identifier
00864   elem_name - which element we're talking about
00865   prop      - property to add to those that will be returned
00866 ******************************************************************************/
00867 
00868 void ply_get_property(
00869   PlyFile *plyfile,
00870   char *elem_name,
00871   PlyProperty *prop
00872 )
00873 {
00874   PlyElement *elem;
00875   PlyProperty *prop_ptr;
00876   int index;
00877 
00878   /* find information about the element */
00879   elem = find_element (plyfile, elem_name);
00880   plyfile->which_elem = elem;
00881 
00882   /* deposit the property information into the element's description */
00883 
00884   prop_ptr = find_property (elem, prop->name, &index);
00885   if (prop_ptr == NULL) {
00886     fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
00887              prop->name, elem_name);
00888     return;
00889   }
00890   prop_ptr->internal_type  = prop->internal_type;
00891   prop_ptr->offset         = prop->offset;
00892   prop_ptr->count_internal = prop->count_internal;
00893   prop_ptr->count_offset   = prop->count_offset;
00894 
00895   /* specify that the user wants this property */
00896   elem->store_prop[index] = STORE_PROP;
00897 }
00898 
00899 
00900 /******************************************************************************
00901 Read one element from the file.  This routine assumes that we're reading
00902 the type of element specified in the last call to the routine
00903 ply_get_element_setup().
00904 
00905 Entry:
00906   plyfile  - file identifier
00907   elem_ptr - pointer to location where the element information should be put
00908 ******************************************************************************/
00909 
00910 void ply_get_element(PlyFile *plyfile, void *elem_ptr)
00911 {
00912   if (plyfile->file_type == PLY_ASCII)
00913     ascii_get_element (plyfile, (char *) elem_ptr);
00914   else
00915     binary_get_element (plyfile, (char *) elem_ptr);
00916 }
00917 
00918 
00919 /******************************************************************************
00920 Extract the comments from the header information of a PLY file.
00921 
00922 Entry:
00923   plyfile - file identifier
00924 
00925 Exit:
00926   num_comments - number of comments returned
00927   returns a pointer to a list of comments
00928 ******************************************************************************/
00929 
00930 char **get_comments_ply(PlyFile *plyfile, int *num_comments)
00931 {
00932   *num_comments = plyfile->num_comments;
00933   return (plyfile->comments);
00934 }
00935 
00936 
00937 /******************************************************************************
00938 Extract the object information (arbitrary text) from the header information
00939 of a PLY file.
00940 
00941 Entry:
00942   plyfile - file identifier
00943 
00944 Exit:
00945   num_obj_info - number of lines of text information returned
00946   returns a pointer to a list of object info lines
00947 ******************************************************************************/
00948 
00949 char **get_obj_info_ply(PlyFile *plyfile, int *num_obj_info)
00950 {
00951   *num_obj_info = plyfile->num_obj_info;
00952   return (plyfile->obj_info);
00953 }
00954 
00955 
00956 /******************************************************************************
00957 Make ready for "other" properties of an element-- those properties that
00958 the user has not explicitly asked for, but that are to be stashed away
00959 in a special structure to be carried along with the element's other
00960 information.
00961 
00962 Entry:
00963   plyfile - file identifier
00964   elem    - element for which we want to save away other properties
00965 ******************************************************************************/
00966 
00967 void setup_other_props(PlyFile *plyfile, PlyElement *elem)
00968 {
00969   int i;
00970   PlyProperty *prop;
00971   int size = 0;
00972   int type_size;
00973 
00974   /* Examine each property in decreasing order of size. */
00975   /* We do this so that all data types will be aligned by */
00976   /* word, half-word, or whatever within the structure. */
00977 
00978   for (type_size = 8; type_size > 0; type_size /= 2) {
00979 
00980     /* add up the space taken by each property, and save this information */
00981     /* away in the property descriptor */
00982 
00983     for (i = 0; i < elem->nprops; i++) {
00984 
00985       /* don't bother with properties we've been asked to store explicitly */
00986       if (elem->store_prop[i])
00987         continue;
00988 
00989       prop = elem->props[i];
00990 
00991       /* internal types will be same as external */
00992       prop->internal_type = prop->external_type;
00993       prop->count_internal = prop->count_external;
00994 
00995       /* list case */
00996       if (prop->is_list == PLY_LIST) {
00997 
00998         /* pointer to list */
00999         if (type_size == sizeof (void *)) {
01000           prop->offset = size;
01001           size += sizeof (void *);    /* always use size of a pointer here */
01002         }
01003 
01004         /* count of number of list elements */
01005         if (type_size == ply_type_size[prop->count_external]) {
01006           prop->count_offset = size;
01007           size += ply_type_size[prop->count_external];
01008         }
01009       }
01010       /* string */
01011       else if (prop->is_list == PLY_STRING) {
01012         /* pointer to string */
01013         if (type_size == sizeof (char *)) {
01014           prop->offset = size;
01015           size += sizeof (char *);
01016         }
01017       }
01018       /* scalar */
01019       else if (type_size == ply_type_size[prop->external_type]) {
01020         prop->offset = size;
01021         size += ply_type_size[prop->external_type];
01022       }
01023     }
01024 
01025   }
01026 
01027   /* save the size for the other_props structure */
01028   elem->other_size = size;
01029 }
01030 
01031 
01032 /******************************************************************************
01033 Specify that we want the "other" properties of an element to be tucked
01034 away within the user's structure.
01035 
01036 Entry:
01037   plyfile - file identifier
01038   elem    - the element that we want to store other_props in
01039   offset  - offset to where other_props will be stored inside user's structure
01040 
01041 Exit:
01042   returns pointer to structure containing description of other_props
01043 ******************************************************************************/
01044 
01045 static PlyOtherProp *get_other_properties(
01046   PlyFile *plyfile,
01047   PlyElement *elem,
01048   int offset
01049 )
01050 {
01051   int i;
01052   PlyOtherProp *other;
01053   PlyProperty *prop;
01054   int nprops;
01055 
01056   /* remember that this is the "current" element */
01057   plyfile->which_elem = elem;
01058 
01059   /* save the offset to where to store the other_props */
01060   elem->other_offset = offset;
01061 
01062   /* place the appropriate pointers, etc. in the element's property list */
01063   setup_other_props (plyfile, elem);
01064 
01065   /* create structure for describing other_props */
01066   other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
01067   other->name = strdup (elem->name);
01068 #if 0
01069   if (elem->other_offset == NO_OTHER_PROPS) {
01070     other->size = 0;
01071     other->props = NULL;
01072     other->nprops = 0;
01073     return (other);
01074   }
01075 #endif
01076   other->size = elem->other_size;
01077   other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops);
01078   
01079   /* save descriptions of each "other" property */
01080   nprops = 0;
01081   for (i = 0; i < elem->nprops; i++) {
01082     if (elem->store_prop[i])
01083       continue;
01084     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
01085     copy_property (prop, elem->props[i]);
01086     other->props[nprops] = prop;
01087     nprops++;
01088   }
01089   other->nprops = nprops;
01090 
01091   /* set other_offset pointer appropriately if there are NO other properties */
01092   if (other->nprops == 0) {
01093     elem->other_offset = NO_OTHER_PROPS;
01094   }
01095  
01096   /* return structure */
01097   return (other);
01098 }
01099 
01100 
01101 /******************************************************************************
01102 Specify that we want the "other" properties of an element to be tucked
01103 away within the user's structure.  The user needn't be concerned for how
01104 these properties are stored.
01105 
01106 Entry:
01107   plyfile   - file identifier
01108   elem_name - name of element that we want to store other_props in
01109   offset    - offset to where other_props will be stored inside user's structure
01110 
01111 Exit:
01112   returns pointer to structure containing description of other_props
01113 ******************************************************************************/
01114 
01115 PlyOtherProp *ply_get_other_properties(
01116   PlyFile *plyfile,
01117   char *elem_name,
01118   int offset
01119 )
01120 {
01121   PlyElement *elem;
01122   PlyOtherProp *other;
01123 
01124   /* find information about the element */
01125   elem = find_element (plyfile, elem_name);
01126   if (elem == NULL) {
01127     fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
01128              elem_name);
01129     return (NULL);
01130   }
01131 
01132   other = get_other_properties (plyfile, elem, offset);
01133   return (other);
01134 }
01135 
01136 
01137 
01138 
01139 /*************************/
01140 /*  Other Element Stuff  */
01141 /*************************/
01142 
01143 
01144 
01145 
01146 
01147 /******************************************************************************
01148 Grab all the data for the current element that a user does not want to
01149 explicitly read in.  Stores this in the PLY object's data structure.
01150 
01151 Entry:
01152   plyfile - pointer to file
01153 
01154 Exit:
01155   returns pointer to ALL the "other" element data for this PLY file
01156 ******************************************************************************/
01157 
01158 PlyOtherElems *get_other_element_ply (PlyFile *plyfile)
01159 {
01160   int i;
01161   PlyElement *elem;
01162   char *elem_name;
01163   int elem_count;
01164   PlyOtherElems *other_elems;
01165   OtherElem *other;
01166 
01167   elem = plyfile->which_elem;
01168   elem_name = elem->name;
01169   elem_count = elem->num;
01170 
01171   /* create room for the new "other" element, initializing the */
01172   /* other data structure if necessary */
01173 
01174   if (plyfile->other_elems == NULL) {
01175     plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
01176     other_elems = plyfile->other_elems;
01177     other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
01178     other = &(other_elems->other_list[0]);
01179     other_elems->num_elems = 1;
01180   }
01181   else {
01182     other_elems = plyfile->other_elems;
01183     other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
01184                               sizeof (OtherElem) * other_elems->num_elems + 1);
01185     other = &(other_elems->other_list[other_elems->num_elems]);
01186     other_elems->num_elems++;
01187   }
01188 
01189   /* count of element instances in file */
01190   other->elem_count = elem_count;
01191 
01192   /* save name of element */
01193   other->elem_name = strdup (elem_name);
01194 
01195   /* create a list to hold all the current elements */
01196   other->other_data = (OtherData **)
01197                   malloc (sizeof (OtherData *) * other->elem_count);
01198 
01199   /* set up for getting elements */
01200   other->other_props = ply_get_other_properties (plyfile, elem_name,
01201                          offsetof(OtherData,other_props));
01202 
01203   /* grab all these elements */
01204   for (i = 0; i < other->elem_count; i++) {
01205     /* grab and element from the file */
01206     other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
01207     ply_get_element (plyfile, (void *) other->other_data[i]);
01208   }
01209 
01210   /* return pointer to the other elements data */
01211   return (other_elems);
01212 }
01213 
01214 
01215 /******************************************************************************
01216 Write out the "other" elements specified for this PLY file.
01217 
01218 Entry:
01219   plyfile - pointer to PLY file to write out other elements for
01220 ******************************************************************************/
01221 
01222 void put_other_elements_ply (PlyFile *plyfile)
01223 {
01224   int i,j;
01225   OtherElem *other;
01226 
01227   /* make sure we have other elements to write */
01228   if (plyfile->other_elems == NULL)
01229     return;
01230 
01231   /* write out the data for each "other" element */
01232 
01233   for (i = 0; i < plyfile->other_elems->num_elems; i++) {
01234 
01235     other = &(plyfile->other_elems->other_list[i]);
01236     put_element_setup_ply (plyfile, other->elem_name);
01237 
01238     /* write out each instance of the current element */
01239     for (j = 0; j < other->elem_count; j++)
01240       put_element_ply (plyfile, (void *) other->other_data[j]);
01241   }
01242 }
01243 
01244 
01245 /******************************************************************************
01246 Free up storage used by an "other" elements data structure.
01247 
01248 Entry:
01249   other_elems - data structure to free up
01250 ******************************************************************************/
01251 
01252 void free_other_elements_ply (PlyOtherElems *other_elems)
01253 {
01254 
01255 }
01256 
01257 
01258 
01259 /*******************/
01260 /*  Miscellaneous  */
01261 /*******************/
01262 
01263 
01264 
01265 /******************************************************************************
01266 Close a PLY file.
01267 
01268 Entry:
01269   plyfile - identifier of file to close
01270 ******************************************************************************/
01271 
01272 void ply_close(PlyFile *plyfile)
01273 {
01274   fclose (plyfile->fp);
01275 
01276   /* free up memory associated with the PLY file */
01277   free (plyfile);
01278 }
01279 
01280 
01281 /******************************************************************************
01282 Get version number and file type of a PlyFile.
01283 
01284 Entry:
01285   ply - pointer to PLY file
01286 
01287 Exit:
01288   version - version of the file
01289   file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
01290 ******************************************************************************/
01291 
01292 void get_info_ply(PlyFile *ply, float *version, int *file_type)
01293 {
01294   if (ply == NULL)
01295     return;
01296 
01297   *version = ply->version;
01298   *file_type = ply->file_type;
01299 }
01300 
01301 
01302 /******************************************************************************
01303 Compare two strings.  Returns 1 if they are the same, 0 if not.
01304 ******************************************************************************/
01305 
01306 int equal_strings(char *s1, char *s2)
01307 {
01308   int i;
01309 
01310   while (*s1 && *s2)
01311     if (*s1++ != *s2++)
01312       return (0);
01313 
01314   if (*s1 != *s2)
01315     return (0);
01316   else
01317     return (1);
01318 }
01319 
01320 
01321 /******************************************************************************
01322 Re-create the command line that was used to invoke this program.
01323 
01324 Entry:
01325   argc - number of words in argv
01326   argv - array of words in command line
01327 ******************************************************************************/
01328 
01329 char *recreate_command_line (int argc, char *argv[])
01330 {
01331   int i;
01332   char *line;
01333   int len = 0;
01334 
01335   /* count total number of characters needed, including separating spaces */
01336   for (i = 0; i < argc; i++)
01337     len += strlen(argv[i]) + 1;
01338 
01339   /* create empty line */
01340   line = (char *) malloc (sizeof(char) * len);
01341   line[0] = '\0';
01342 
01343   /* repeatedly append argv */
01344   for (i = 0; i < argc; i++) {
01345     strcat (line, argv[i]);
01346     if (i != argc - 1)
01347       strcat (line, " ");
01348   }
01349 
01350   return (line);
01351 }
01352 
01353 
01354 /******************************************************************************
01355 Find an element from the element list of a given PLY object.
01356 
01357 Entry:
01358   plyfile - file id for PLY file
01359   element - name of element we're looking for
01360 
01361 Exit:
01362   returns the element, or NULL if not found
01363 ******************************************************************************/
01364 
01365 PlyElement *find_element(PlyFile *plyfile, char *element)
01366 {
01367   int i;
01368 
01369   for (i = 0; i < plyfile->num_elem_types; i++)
01370     if (equal_strings (element, plyfile->elems[i]->name))
01371       return (plyfile->elems[i]);
01372 
01373   return (NULL);
01374 }
01375 
01376 
01377 /******************************************************************************
01378 Find a property in the list of properties of a given element.
01379 
01380 Entry:
01381   elem      - pointer to element in which we want to find the property
01382   prop_name - name of property to find
01383 
01384 Exit:
01385   index - index to position in list
01386   returns a pointer to the property, or NULL if not found
01387 ******************************************************************************/
01388 
01389 PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index)
01390 {
01391   int i;
01392 
01393   for (i = 0; i < elem->nprops; i++)
01394     if (equal_strings (prop_name, elem->props[i]->name)) {
01395       *index = i;
01396       return (elem->props[i]);
01397     }
01398 
01399   *index = -1;
01400   return (NULL);
01401 }
01402 
01403 
01404 /******************************************************************************
01405 Read an element from an ascii file.
01406 
01407 Entry:
01408   plyfile  - file identifier
01409   elem_ptr - pointer to element
01410 ******************************************************************************/
01411 
01412 void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
01413 {
01414   int i,j,k;
01415   PlyElement *elem;
01416   PlyProperty *prop;
01417   char **words;
01418   int nwords;
01419   int which_word;
01420   FILE *fp = plyfile->fp;
01421   char *elem_data,*item;
01422   char *item_ptr;
01423   int item_size;
01424   int int_val;
01425   unsigned int uint_val;
01426   double double_val;
01427   int list_count;
01428   int store_it;
01429   char **store_array;
01430   char *orig_line;
01431   char *other_data;
01432   int other_flag;
01433 
01434   /* the kind of element we're reading currently */
01435   elem = plyfile->which_elem;
01436 
01437   /* do we need to setup for other_props? */
01438 
01439   if (elem->other_offset != NO_OTHER_PROPS) {
01440     char **ptr;
01441     other_flag = 1;
01442     /* make room for other_props */
01443     other_data = (char *) myalloc (elem->other_size);
01444     /* store pointer in user's structure to the other_props */
01445     ptr = (char **) (elem_ptr + elem->other_offset);
01446     *ptr = other_data;
01447   }
01448   else
01449     other_flag = 0;
01450 
01451   /* read in the element */
01452 
01453   words = get_words (plyfile->fp, &nwords, &orig_line);
01454   if (words == NULL) {
01455     fprintf (stderr, "ply_get_element: unexpected end of file\n");
01456     exit (-1);
01457   }
01458 
01459   which_word = 0;
01460 
01461   for (j = 0; j < elem->nprops; j++) {
01462 
01463     prop = elem->props[j];
01464     store_it = (elem->store_prop[j] | other_flag);
01465 
01466     /* store either in the user's structure or in other_props */
01467     if (elem->store_prop[j])
01468       elem_data = elem_ptr;
01469     else
01470       elem_data = other_data;
01471 
01472     if (prop->is_list == PLY_LIST) {       /* a list */
01473 
01474       /* get and store the number of items in the list */
01475       get_ascii_item (words[which_word++], prop->count_external,
01476                       &int_val, &uint_val, &double_val);
01477       if (store_it) {
01478         item = elem_data + prop->count_offset;
01479         store_item(item, prop->count_internal, int_val, uint_val, double_val);
01480       }
01481 
01482       /* allocate space for an array of items and store a ptr to the array */
01483       list_count = int_val;
01484       item_size = ply_type_size[prop->internal_type];
01485       store_array = (char **) (elem_data + prop->offset);
01486 
01487       if (list_count == 0) {
01488         if (store_it)
01489           *store_array = NULL;
01490       }
01491       else {
01492         if (store_it) {
01493           item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
01494           item = item_ptr;
01495           *store_array = item_ptr;
01496         }
01497 
01498         /* read items and store them into the array */
01499         for (k = 0; k < list_count; k++) {
01500           get_ascii_item (words[which_word++], prop->external_type,
01501                           &int_val, &uint_val, &double_val);
01502           if (store_it) {
01503             store_item (item, prop->internal_type,
01504                         int_val, uint_val, double_val);
01505             item += item_size;
01506           }
01507         }
01508       }
01509 
01510     }
01511     else if (prop->is_list == PLY_STRING) {   /* a string */
01512       if (store_it) {
01513    char *str;
01514    char **str_ptr;
01515    str = strdup (words[which_word++]);
01516         item = elem_data + prop->offset;
01517    str_ptr = (char **) item;
01518    *str_ptr = str;
01519       }
01520       else {
01521         which_word++;
01522       }
01523     }
01524     else {                     /* a scalar */
01525       get_ascii_item (words[which_word++], prop->external_type,
01526                       &int_val, &uint_val, &double_val);
01527       if (store_it) {
01528         item = elem_data + prop->offset;
01529         store_item (item, prop->internal_type, int_val, uint_val, double_val);
01530       }
01531     }
01532 
01533   }
01534 
01535   free (words);
01536 }
01537 
01538 
01539 /******************************************************************************
01540 Read an element from a binary file.
01541 
01542 Entry:
01543   plyfile  - file identifier
01544   elem_ptr - pointer to an element
01545 ******************************************************************************/
01546 
01547 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
01548 {
01549   int i,j,k;
01550   PlyElement *elem;
01551   PlyProperty *prop;
01552   FILE *fp = plyfile->fp;
01553   char *elem_data;
01554   char *item;
01555   char *item_ptr;
01556   int item_size;
01557   int int_val;
01558   unsigned int uint_val;
01559   double double_val;
01560   int list_count;
01561   int store_it;
01562   char **store_array;
01563   char *other_data;
01564   int other_flag;
01565 
01566   /* the kind of element we're reading currently */
01567   elem = plyfile->which_elem;
01568 
01569   /* do we need to setup for other_props? */
01570 
01571   if (elem->other_offset != NO_OTHER_PROPS) {
01572     char **ptr;
01573     other_flag = 1;
01574     /* make room for other_props */
01575     other_data = (char *) myalloc (elem->other_size);
01576     /* store pointer in user's structure to the other_props */
01577     ptr = (char **) (elem_ptr + elem->other_offset);
01578     *ptr = other_data;
01579   }
01580   else
01581     other_flag = 0;
01582 
01583   /* read in a number of elements */
01584 
01585   for (j = 0; j < elem->nprops; j++) {
01586 
01587     prop = elem->props[j];
01588     store_it = (elem->store_prop[j] | other_flag);
01589 
01590     /* store either in the user's structure or in other_props */
01591     if (elem->store_prop[j])
01592       elem_data = elem_ptr;
01593     else
01594       elem_data = other_data;
01595 
01596     if (prop->is_list == PLY_LIST) {          /* list */
01597 
01598       /* get and store the number of items in the list */
01599       get_binary_item (fp, prop->count_external,
01600                       &int_val, &uint_val, &double_val);
01601       if (store_it) {
01602         item = elem_data + prop->count_offset;
01603         store_item(item, prop->count_internal, int_val, uint_val, double_val);
01604       }
01605 
01606       /* allocate space for an array of items and store a ptr to the array */
01607       list_count = int_val;
01608       item_size = ply_type_size[prop->internal_type];
01609       store_array = (char **) (elem_data + prop->offset);
01610       if (list_count == 0) {
01611         if (store_it)
01612           *store_array = NULL;
01613       }
01614       else {
01615         if (store_it) {
01616           item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
01617           item = item_ptr;
01618           *store_array = item_ptr;
01619         }
01620 
01621         /* read items and store them into the array */
01622         for (k = 0; k < list_count; k++) {
01623           get_binary_item (fp, prop->external_type,
01624                           &int_val, &uint_val, &double_val);
01625           if (store_it) {
01626             store_item (item, prop->internal_type,
01627                         int_val, uint_val, double_val);
01628             item += item_size;
01629           }
01630         }
01631       }
01632 
01633     }
01634     else if (prop->is_list == PLY_STRING) {     /* string */
01635       int len;
01636       char *str;
01637       fread (&len, sizeof(int), 1, fp);
01638       str = (char *) myalloc (len);
01639       fread (str, len, 1, fp);
01640       if (store_it) {
01641    char **str_ptr;
01642         item = elem_data + prop->offset;
01643    str_ptr = (char **) item;
01644    *str_ptr = str;
01645       }
01646     }
01647     else {                                      /* scalar */
01648       get_binary_item (fp, prop->external_type,
01649                       &int_val, &uint_val, &double_val);
01650       if (store_it) {
01651         item = elem_data + prop->offset;
01652         store_item (item, prop->internal_type, int_val, uint_val, double_val);
01653       }
01654     }
01655 
01656   }
01657 }
01658 
01659 
01660 /******************************************************************************
01661 Write to a file the word that represents a PLY data type.
01662 
01663 Entry:
01664   fp   - file pointer
01665   code - code for type
01666 ******************************************************************************/
01667 
01668 void write_scalar_type (FILE *fp, int code)
01669 {
01670   /* make sure this is a valid code */
01671 
01672   if (code <= StartType || code >= EndType) {
01673     fprintf (stderr, "write_scalar_type: bad data code = %d\n", code);
01674     exit (-1);
01675   }
01676 
01677   /* write the code to a file */
01678 
01679   fprintf (fp, "%s", type_names[code]);
01680 }
01681 
01682 
01683 /******************************************************************************
01684 Get a text line from a file and break it up into words.
01685 
01686 IMPORTANT: The calling routine should call "free" on the returned pointer once
01687 finished with it.
01688 
01689 Entry:
01690   fp - file to read from
01691 
01692 Exit:
01693   nwords    - number of words returned
01694   orig_line - the original line of characters
01695   returns a list of words from the line, or NULL if end-of-file
01696 ******************************************************************************/
01697 
01698 char **get_words(FILE *fp, int *nwords, char **orig_line)
01699 {
01700 #define BIG_STRING 4096
01701   int i,j;
01702   static char str[BIG_STRING];
01703   static char str_copy[BIG_STRING];
01704   char **words;
01705   int max_words = 10;
01706   int num_words = 0;
01707   char *ptr,*ptr2;
01708   char *result;
01709 
01710   words = (char **) myalloc (sizeof (char *) * max_words);
01711 
01712   /* read in a line */
01713   result = fgets (str, BIG_STRING, fp);
01714   if (result == NULL) {
01715     *nwords = 0;
01716     *orig_line = NULL;
01717     return (NULL);
01718   }
01719 
01720   /* convert line-feed and tabs into spaces */
01721   /* (this guarentees that there will be a space before the */
01722   /*  null character at the end of the string) */
01723 
01724   str[BIG_STRING-2] = ' ';
01725   str[BIG_STRING-1] = '\0';
01726 
01727   for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
01728     *ptr2 = *ptr;
01729     if (*ptr == '\t') {
01730       *ptr = ' ';
01731       *ptr2 = ' ';
01732     }
01733     else if (*ptr == '\n') {
01734       *ptr = ' ';
01735       *ptr2 = '\0';
01736       break;
01737     }
01738   }
01739 
01740   /* find the words in the line */
01741 
01742   ptr = str;
01743   while (*ptr != '\0') {
01744 
01745     /* jump over leading spaces */
01746     while (*ptr == ' ')
01747       ptr++;
01748 
01749     /* break if we reach the end */
01750     if (*ptr == '\0')
01751       break;
01752 
01753     /* allocate more room for words if necessary */
01754     if (num_words >= max_words) {
01755       max_words += 10;
01756       words = (char **) realloc (words, sizeof (char *) * max_words);
01757     }
01758 
01759     if (*ptr == '\"') {  /* a quote indidicates that we have a string */
01760 
01761       /* skip over leading quote */
01762       ptr++;
01763 
01764       /* save pointer to beginning of word */
01765       words[num_words++] = ptr;
01766 
01767       /* find trailing quote or end of line */
01768       while (*ptr != '\"' && *ptr != '\0')
01769         ptr++;
01770 
01771       /* replace quote with a null character to mark the end of the word */
01772       /* if we are not already at the end of the line */
01773       if (*ptr != '\0')
01774    *ptr++ = '\0';
01775     }
01776     else {               /* non-string */
01777 
01778       /* save pointer to beginning of word */
01779       words[num_words++] = ptr;
01780 
01781       /* jump over non-spaces */
01782       while (*ptr != ' ')
01783    ptr++;
01784 
01785       /* place a null character here to mark the end of the word */
01786       *ptr++ = '\0';
01787     }
01788   }
01789 
01790   /* return the list of words */
01791   *nwords = num_words;
01792   *orig_line = str_copy;
01793   return (words);
01794 }
01795 
01796 
01797 /******************************************************************************
01798 Return the value of an item, given a pointer to it and its type.
01799 
01800 Entry:
01801   item - pointer to item
01802   type - data type that "item" points to
01803 
01804 Exit:
01805   returns a double-precision float that contains the value of the item
01806 ******************************************************************************/
01807 
01808 double get_item_value(char *item, int type)
01809 {
01810   unsigned char *puchar;
01811   char *pchar;
01812   short int *pshort;
01813   unsigned short int *pushort;
01814   int *pint;
01815   unsigned int *puint;
01816   float *pfloat;
01817   double *pdouble;
01818   int int_value;
01819   unsigned int uint_value;
01820   double double_value;
01821 
01822   switch (type) {
01823     case Int8:
01824       pchar = (char *) item;
01825       int_value = *pchar;
01826       return ((double) int_value);
01827     case Uint8:
01828       puchar = (unsigned char *) item;
01829       int_value = *puchar;
01830       return ((double) int_value);
01831     case Int16:
01832       pshort = (short int *) item;
01833       int_value = *pshort;
01834       return ((double) int_value);
01835     case Uint16:
01836       pushort = (unsigned short int *) item;
01837       int_value = *pushort;
01838       return ((double) int_value);
01839     case Int32:
01840       pint = (int *) item;
01841       int_value = *pint;
01842       return ((double) int_value);
01843     case Uint32:
01844       puint = (unsigned int *) item;
01845       uint_value = *puint;
01846       return ((double) uint_value);
01847     case Float32:
01848       pfloat = (float *) item;
01849       double_value = *pfloat;
01850       return (double_value);
01851     case Float64:
01852       pdouble = (double *) item;
01853       double_value = *pdouble;
01854       return (double_value);
01855     default:
01856       fprintf (stderr, "get_item_value: bad type = %d\n", type);
01857       exit (-1);
01858   }
01859 
01860   return (0.0);  /* never actually gets here */
01861 }
01862 
01863 
01864 /******************************************************************************
01865 Write out an item to a file as raw binary bytes.
01866 
01867 Entry:
01868   fp         - file to write to
01869   int_val    - integer version of item
01870   uint_val   - unsigned integer version of item
01871   double_val - double-precision float version of item
01872   type       - data type to write out
01873 ******************************************************************************/
01874 
01875 void write_binary_item(
01876   FILE *fp,
01877   int int_val,
01878   unsigned int uint_val,
01879   double double_val,
01880   int type
01881 )
01882 {
01883   unsigned char uchar_val;
01884   char char_val;
01885   unsigned short ushort_val;
01886   short short_val;
01887   float float_val;
01888 
01889   switch (type) {
01890     case Int8:
01891       char_val = int_val;
01892       fwrite (&char_val, 1, 1, fp);
01893       break;
01894     case Int16:
01895       short_val = int_val;
01896       fwrite (&short_val, 2, 1, fp);
01897       break;
01898     case Int32:
01899       fwrite (&int_val, 4, 1, fp);
01900       break;
01901     case Uint8:
01902       uchar_val = uint_val;
01903       fwrite (&uchar_val, 1, 1, fp);
01904       break;
01905     case Uint16:
01906       ushort_val = uint_val;
01907       fwrite (&ushort_val, 2, 1, fp);
01908       break;
01909     case Uint32:
01910       fwrite (&uint_val, 4, 1, fp);
01911       break;
01912     case Float32:
01913       float_val = double_val;
01914       fwrite (&float_val, 4, 1, fp);
01915       break;
01916     case Float64:
01917       fwrite (&double_val, 8, 1, fp);
01918       break;
01919     default:
01920       fprintf (stderr, "write_binary_item: bad type = %d\n", type);
01921       exit (-1);
01922   }
01923 }
01924 
01925 
01926 /******************************************************************************
01927 Write out an item to a file as ascii characters.
01928 
01929 Entry:
01930   fp         - file to write to
01931   int_val    - integer version of item
01932   uint_val   - unsigned integer version of item
01933   double_val - double-precision float version of item
01934   type       - data type to write out
01935 ******************************************************************************/
01936 
01937 void write_ascii_item(
01938   FILE *fp,
01939   int int_val,
01940   unsigned int uint_val,
01941   double double_val,
01942   int type
01943 )
01944 {
01945   switch (type) {
01946     case Int8:
01947     case Int16:
01948     case Int32:
01949       fprintf (fp, "%d ", int_val);
01950       break;
01951     case Uint8:
01952     case Uint16:
01953     case Uint32:
01954       fprintf (fp, "%u ", uint_val);
01955       break;
01956     case Float32:
01957     case Float64:
01958       fprintf (fp, "%g ", double_val);
01959       break;
01960     default:
01961       fprintf (stderr, "write_ascii_item: bad type = %d\n", type);
01962       exit (-1);
01963   }
01964 }
01965 
01966 
01967 /******************************************************************************
01968 Get the value of an item that is in memory, and place the result
01969 into an integer, an unsigned integer and a double.
01970 
01971 Entry:
01972   ptr  - pointer to the item
01973   type - data type supposedly in the item
01974 
01975 Exit:
01976   int_val    - integer value
01977   uint_val   - unsigned integer value
01978   double_val - double-precision floating point value
01979 ******************************************************************************/
01980 
01981 void get_stored_item(
01982   void *ptr,
01983   int type,
01984   int *int_val,
01985   unsigned int *uint_val,
01986   double *double_val
01987 )
01988 {
01989   switch (type) {
01990     case Int8:
01991       *int_val = *((char *) ptr);
01992       *uint_val = *int_val;
01993       *double_val = *int_val;
01994       break;
01995     case Uint8:
01996       *uint_val = *((unsigned char *) ptr);
01997       *int_val = *uint_val;
01998       *double_val = *uint_val;
01999       break;
02000     case Int16:
02001       *int_val = *((short int *) ptr);
02002       *uint_val = *int_val;
02003       *double_val = *int_val;
02004       break;
02005     case Uint16:
02006       *uint_val = *((unsigned short int *) ptr);
02007       *int_val = *uint_val;
02008       *double_val = *uint_val;
02009       break;
02010     case Int32:
02011       *int_val = *((int *) ptr);
02012       *uint_val = *int_val;
02013       *double_val = *int_val;
02014       break;
02015     case Uint32:
02016       *uint_val = *((unsigned int *) ptr);
02017       *int_val = *uint_val;
02018       *double_val = *uint_val;
02019       break;
02020     case Float32:
02021       *double_val = *((float *) ptr);
02022       *int_val = *double_val;
02023       *uint_val = *double_val;
02024       break;
02025     case Float64:
02026       *double_val = *((double *) ptr);
02027       *int_val = *double_val;
02028       *uint_val = *double_val;
02029       break;
02030     default:
02031       fprintf (stderr, "get_stored_item: bad type = %d\n", type);
02032       exit (-1);
02033   }
02034 }
02035 
02036 
02037 /******************************************************************************
02038 Get the value of an item from a binary file, and place the result
02039 into an integer, an unsigned integer and a double.
02040 
02041 Entry:
02042   fp   - file to get item from
02043   type - data type supposedly in the word
02044 
02045 Exit:
02046   int_val    - integer value
02047   uint_val   - unsigned integer value
02048   double_val - double-precision floating point value
02049 ******************************************************************************/
02050 
02051 void get_binary_item(
02052   FILE *fp,
02053   int type,
02054   int *int_val,
02055   unsigned int *uint_val,
02056   double *double_val
02057 )
02058 {
02059   char c[8];
02060   void *ptr;
02061 
02062   ptr = (void *) c;
02063 
02064   switch (type) {
02065     case Int8:
02066       fread (ptr, 1, 1, fp);
02067       *int_val = *((char *) ptr);
02068       *uint_val = *int_val;
02069       *double_val = *int_val;
02070       break;
02071     case Uint8:
02072       fread (ptr, 1, 1, fp);
02073       *uint_val = *((unsigned char *) ptr);
02074       *int_val = *uint_val;
02075       *double_val = *uint_val;
02076       break;
02077     case Int16:
02078       fread (ptr, 2, 1, fp);
02079       *int_val = *((short int *) ptr);
02080       *uint_val = *int_val;
02081       *double_val = *int_val;
02082       break;
02083     case Uint16:
02084       fread (ptr, 2, 1, fp);
02085       *uint_val = *((unsigned short int *) ptr);
02086       *int_val = *uint_val;
02087       *double_val = *uint_val;
02088       break;
02089     case Int32:
02090       fread (ptr, 4, 1, fp);
02091       *int_val = *((int *) ptr);
02092       *uint_val = *int_val;
02093       *double_val = *int_val;
02094       break;
02095     case Uint32:
02096       fread (ptr, 4, 1, fp);
02097       *uint_val = *((unsigned int *) ptr);
02098       *int_val = *uint_val;
02099       *double_val = *uint_val;
02100       break;
02101     case Float32:
02102       fread (ptr, 4, 1, fp);
02103       *double_val = *((float *) ptr);
02104       *int_val = *double_val;
02105       *uint_val = *double_val;
02106       break;
02107     case Float64:
02108       fread (ptr, 8, 1, fp);
02109       *double_val = *((double *) ptr);
02110       *int_val = *double_val;
02111       *uint_val = *double_val;
02112       break;
02113     default:
02114       fprintf (stderr, "get_binary_item: bad type = %d\n", type);
02115       exit (-1);
02116   }
02117 }
02118 
02119 
02120 /******************************************************************************
02121 Extract the value of an item from an ascii word, and place the result
02122 into an integer, an unsigned integer and a double.
02123 
02124 Entry:
02125   word - word to extract value from
02126   type - data type supposedly in the word
02127 
02128 Exit:
02129   int_val    - integer value
02130   uint_val   - unsigned integer value
02131   double_val - double-precision floating point value
02132 ******************************************************************************/
02133 
02134 void get_ascii_item(
02135   char *word,
02136   int type,
02137   int *int_val,
02138   unsigned int *uint_val,
02139   double *double_val
02140 )
02141 {
02142   switch (type) {
02143     case Int8:
02144     case Uint8:
02145     case Int16:
02146     case Uint16:
02147     case Int32:
02148       *int_val = atoi (word);
02149       *uint_val = *int_val;
02150       *double_val = *int_val;
02151       break;
02152 
02153     case Uint32:
02154       *uint_val = strtoul (word, (char **) NULL, 10);
02155       *int_val = *uint_val;
02156       *double_val = *uint_val;
02157       break;
02158 
02159     case Float32:
02160     case Float64:
02161       *double_val = atof (word);
02162       *int_val = (int) *double_val;
02163       *uint_val = (unsigned int) *double_val;
02164       break;
02165 
02166     default:
02167       fprintf (stderr, "get_ascii_item: bad type = %d\n", type);
02168       exit (-1);
02169   }
02170 }
02171 
02172 
02173 /******************************************************************************
02174 Store a value into a place being pointed to, guided by a data type.
02175 
02176 Entry:
02177   item       - place to store value
02178   type       - data type
02179   int_val    - integer version of value
02180   uint_val   - unsigned integer version of value
02181   double_val - double version of value
02182 
02183 Exit:
02184   item - pointer to stored value
02185 ******************************************************************************/
02186 
02187 void store_item (
02188   char *item,
02189   int type,
02190   int int_val,
02191   unsigned int uint_val,
02192   double double_val
02193 )
02194 {
02195   unsigned char *puchar;
02196   short int *pshort;
02197   unsigned short int *pushort;
02198   int *pint;
02199   unsigned int *puint;
02200   float *pfloat;
02201   double *pdouble;
02202 
02203   switch (type) {
02204     case Int8:
02205       *item = int_val;
02206       break;
02207     case Uint8:
02208       puchar = (unsigned char *) item;
02209       *puchar = uint_val;
02210       break;
02211     case Int16:
02212       pshort = (short *) item;
02213       *pshort = int_val;
02214       break;
02215     case Uint16:
02216       pushort = (unsigned short *) item;
02217       *pushort = uint_val;
02218       break;
02219     case Int32:
02220       pint = (int *) item;
02221       *pint = int_val;
02222       break;
02223     case Uint32:
02224       puint = (unsigned int *) item;
02225       *puint = uint_val;
02226       break;
02227     case Float32:
02228       pfloat = (float *) item;
02229       *pfloat = double_val;
02230       break;
02231     case Float64:
02232       pdouble = (double *) item;
02233       *pdouble = double_val;
02234       break;
02235     default:
02236       fprintf (stderr, "store_item: bad type = %d\n", type);
02237       exit (-1);
02238   }
02239 }
02240 
02241 
02242 /******************************************************************************
02243 Add an element to a PLY file descriptor.
02244 
02245 Entry:
02246   plyfile - PLY file descriptor
02247   words   - list of words describing the element
02248   nwords  - number of words in the list
02249 ******************************************************************************/
02250 
02251 void add_element (PlyFile *plyfile, char **words, int nwords)
02252 {
02253   PlyElement *elem;
02254 
02255   /* create the new element */
02256   elem = (PlyElement *) myalloc (sizeof (PlyElement));
02257   elem->name = strdup (words[1]);
02258   elem->num = atoi (words[2]);
02259   elem->nprops = 0;
02260 
02261   /* make room for new element in the object's list of elements */
02262   if (plyfile->num_elem_types == 0)
02263     plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
02264   else
02265     plyfile->elems = (PlyElement **) realloc (plyfile->elems,
02266                      sizeof (PlyElement *) * (plyfile->num_elem_types + 1));
02267 
02268   /* add the new element to the object's list */
02269   plyfile->elems[plyfile->num_elem_types] = elem;
02270   plyfile->num_elem_types++;
02271 }
02272 
02273 
02274 /******************************************************************************
02275 Return the type of a property, given the name of the property.
02276 
02277 Entry:
02278   name - name of property type
02279 
02280 Exit:
02281   returns integer code for property, or 0 if not found
02282 ******************************************************************************/
02283 
02284 int get_prop_type(char *type_name)
02285 {
02286   int i;
02287 
02288   /* try to match the type name */
02289   for (i = StartType + 1; i < EndType; i++)
02290     if (equal_strings (type_name, type_names[i]))
02291       return (i);
02292 
02293   /* see if we can match an old type name */
02294   for (i = StartType + 1; i < EndType; i++)
02295     if (equal_strings (type_name, old_type_names[i]))
02296       return (i);
02297 
02298   /* if we get here, we didn't find the type */
02299   return (0);
02300 }
02301 
02302 
02303 /******************************************************************************
02304 Add a property to a PLY file descriptor.
02305 
02306 Entry:
02307   plyfile - PLY file descriptor
02308   words   - list of words describing the property
02309   nwords  - number of words in the list
02310 ******************************************************************************/
02311 
02312 void add_property (PlyFile *plyfile, char **words, int nwords)
02313 {
02314   int prop_type;
02315   int count_type;
02316   PlyProperty *prop;
02317   PlyElement *elem;
02318 
02319   /* create the new property */
02320 
02321   prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
02322 
02323   if (equal_strings (words[1], "list")) {          /* list */
02324     prop->count_external = get_prop_type (words[2]);
02325     prop->external_type = get_prop_type (words[3]);
02326     prop->name = strdup (words[4]);
02327     prop->is_list = PLY_LIST;
02328   }
02329   else if (equal_strings (words[1], "string")) {   /* string */
02330     prop->count_external = Int8;
02331     prop->external_type = Int8;
02332     prop->name = strdup (words[2]);
02333     prop->is_list = PLY_STRING;
02334   }
02335   else {                                           /* scalar */
02336     prop->external_type = get_prop_type (words[1]);
02337     prop->name = strdup (words[2]);
02338     prop->is_list = PLY_SCALAR;
02339   }
02340 
02341   /* add this property to the list of properties of the current element */
02342 
02343   elem = plyfile->elems[plyfile->num_elem_types - 1];
02344 
02345   if (elem->nprops == 0)
02346     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
02347   else
02348     elem->props = (PlyProperty **) realloc (elem->props,
02349                   sizeof (PlyProperty *) * (elem->nprops + 1));
02350 
02351   elem->props[elem->nprops] = prop;
02352   elem->nprops++;
02353 }
02354 
02355 
02356 /******************************************************************************
02357 Add a comment to a PLY file descriptor.
02358 
02359 Entry:
02360   plyfile - PLY file descriptor
02361   line    - line containing comment
02362 ******************************************************************************/
02363 
02364 void add_comment (PlyFile *plyfile, char *line)
02365 {
02366   int i;
02367 
02368   /* skip over "comment" and leading spaces and tabs */
02369   i = 7;
02370   while (line[i] == ' ' || line[i] == '\t')
02371     i++;
02372 
02373   append_comment_ply (plyfile, &line[i]);
02374 }
02375 
02376 
02377 /******************************************************************************
02378 Add a some object information to a PLY file descriptor.
02379 
02380 Entry:
02381   plyfile - PLY file descriptor
02382   line    - line containing text info
02383 ******************************************************************************/
02384 
02385 void add_obj_info (PlyFile *plyfile, char *line)
02386 {
02387   int i;
02388 
02389   /* skip over "obj_info" and leading spaces and tabs */
02390   i = 8;
02391   while (line[i] == ' ' || line[i] == '\t')
02392     i++;
02393 
02394   append_obj_info_ply (plyfile, &line[i]);
02395 }
02396 
02397 
02398 /******************************************************************************
02399 Copy a property.
02400 ******************************************************************************/
02401 
02402 void copy_property(PlyProperty *dest, PlyProperty *src)
02403 {
02404   dest->name = strdup (src->name);
02405   dest->external_type = src->external_type;
02406   dest->internal_type = src->internal_type;
02407   dest->offset = src->offset;
02408 
02409   dest->is_list = src->is_list;
02410   dest->count_external = src->count_external;
02411   dest->count_internal = src->count_internal;
02412   dest->count_offset = src->count_offset;
02413 }
02414 
02415 
02416 /******************************************************************************
02417 Allocate some memory.
02418 
02419 Entry:
02420   size  - amount of memory requested (in bytes)
02421   lnum  - line number from which memory was requested
02422   fname - file name from which memory was requested
02423 ******************************************************************************/
02424 
02425 static char *my_alloc(int size, int lnum, char *fname)
02426 {
02427   char *ptr;
02428 
02429   ptr = (char *) malloc (size);
02430 
02431   if (ptr == 0) {
02432     fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname);
02433   }
02434 
02435   return (ptr);
02436 }
02437 
02438 
02439 /**** NEW STUFF ****/
02440 /**** NEW STUFF ****/
02441 /**** NEW STUFF ****/
02442 /**** NEW STUFF ****/
02443 
02444 
02445 
02446 /******************************************************************************
02447 Given a file pointer, get ready to read PLY data from the file.
02448 
02449 Entry:
02450   fp - the given file pointer
02451 
02452 Exit:
02453   nelems     - number of elements in object
02454   elem_names - list of element names
02455   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
02456 ******************************************************************************/
02457 
02458 PlyFile *read_ply(FILE *fp)
02459 {
02460   PlyFile *ply;
02461   int num_elems;
02462   char **elem_names;
02463 
02464   ply = ply_read (fp, &num_elems, &elem_names);
02465 
02466   return (ply);
02467 }
02468 
02469 
02470 /******************************************************************************
02471 Given a file pointer, get ready to write PLY data to the file.
02472 
02473 Entry:
02474   fp         - the given file pointer
02475   nelems     - number of elements in object
02476   elem_names - list of element names
02477   file_type  - file type, either ascii or binary
02478 
02479 Exit:
02480   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
02481 ******************************************************************************/
02482 
02483 PlyFile *write_ply(
02484   FILE *fp,
02485   int nelems,
02486   char **elem_names,
02487   int file_type
02488 )
02489 {
02490   PlyFile *ply;
02491 
02492   ply = ply_write (fp, nelems, elem_names, file_type);
02493 
02494   return (ply);
02495 }
02496 
02497 
02498 /******************************************************************************
02499 Return a list of the names of the elements in a particular PLY file.
02500 
02501 Entry:
02502   ply - PLY file whose element name list we want
02503 
02504 Exit:
02505   num_elems  - the number of element names in the list
02506   returns the list of names
02507 ******************************************************************************/
02508 
02509 char **get_element_list_ply(PlyFile *ply, int *num_elems)
02510 {
02511   int i;
02512   char **elist;
02513 
02514   /* create the list of element names */
02515 
02516   elist = (char **) myalloc (sizeof (char *) * ply->num_elem_types);
02517   for (i = 0; i < ply->num_elem_types; i++)
02518     elist[i] = strdup (ply->elems[i]->name);
02519 
02520   /* return the number of elements and the list of element names */
02521   *num_elems = ply->num_elem_types;
02522   return (elist);
02523 }
02524 
02525 
02526 /******************************************************************************
02527 Append a comment to a PLY file.
02528 
02529 Entry:
02530   ply     - file to append comment to
02531   comment - the comment to append
02532 ******************************************************************************/
02533 
02534 void append_comment_ply(PlyFile *ply, char *comment)
02535 {
02536   /* (re)allocate space for new comment */
02537   if (ply->num_comments == 0)
02538     ply->comments = (char **) myalloc (sizeof (char *));
02539   else
02540     ply->comments = (char **) realloc (ply->comments,
02541            sizeof (char *) * (ply->num_comments + 1));
02542 
02543   /* add comment to list */
02544   ply->comments[ply->num_comments] = strdup (comment);
02545   ply->num_comments++;
02546 }
02547 
02548 
02549 /******************************************************************************
02550 Copy the comments from one PLY file to another.
02551 
02552 Entry:
02553   out_ply - destination file to copy comments to
02554   in_ply  - the source of the comments
02555 ******************************************************************************/
02556 
02557 void copy_comments_ply(PlyFile *out_ply, PlyFile *in_ply)
02558 {
02559   int i;
02560 
02561   for (i = 0; i < in_ply->num_comments; i++)
02562     append_comment_ply (out_ply, in_ply->comments[i]);
02563 }
02564 
02565 
02566 /******************************************************************************
02567 Append object information (arbitrary text) to a PLY file.
02568 
02569 Entry:
02570   ply      - file to append object info to
02571   obj_info - the object info to append
02572 ******************************************************************************/
02573 
02574 void append_obj_info_ply(PlyFile *ply, char *obj_info)
02575 {
02576   /* (re)allocate space for new info */
02577   if (ply->num_obj_info == 0)
02578     ply->obj_info = (char **) myalloc (sizeof (char *));
02579   else
02580     ply->obj_info = (char **) realloc (ply->obj_info,
02581            sizeof (char *) * (ply->num_obj_info + 1));
02582 
02583   /* add info to list */
02584   ply->obj_info[ply->num_obj_info] = strdup (obj_info);
02585   ply->num_obj_info++;
02586 }
02587 
02588 
02589 /******************************************************************************
02590 Copy the object information from one PLY file to another.
02591 
02592 Entry:
02593   out_ply - destination file to copy object information to
02594   in_ply  - the source of the object information
02595 ******************************************************************************/
02596 
02597 void copy_obj_info_ply(PlyFile *out_ply, PlyFile *in_ply)
02598 {
02599   int i;
02600 
02601   for (i = 0; i < in_ply->num_obj_info; i++)
02602     append_obj_info_ply (out_ply, in_ply->obj_info[i]);
02603 }
02604 
02605 
02606 /******************************************************************************
02607 Close a PLY file.
02608 
02609 Entry:
02610   plyfile - identifier of file to close
02611 ******************************************************************************/
02612 
02613 void close_ply(PlyFile *plyfile)
02614 {
02615   fclose (plyfile->fp);
02616 }
02617 
02618 
02619 /******************************************************************************
02620 Free the memory used by a PLY file.
02621 
02622 Entry:
02623   plyfile - identifier of file
02624 ******************************************************************************/
02625 
02626 void free_ply(PlyFile *plyfile)
02627 {
02628   /* free up memory associated with the PLY file */
02629   free (plyfile);
02630 }
02631 
02632 
02633 /******************************************************************************
02634 Specify the index of the next element to be read in from a PLY file.
02635 
02636 Entry:
02637   ply - file to read from
02638   index - index of the element to be read
02639 
02640 Exit:
02641   elem_count - the number of elements in the file
02642   returns pointer to the name of this next element
02643 ******************************************************************************/
02644 
02645 char *setup_element_read_ply (PlyFile *ply, int index, int *elem_count)
02646 {
02647   PlyElement *elem;
02648 
02649   if (index < 0 || index > ply->num_elem_types) {
02650     fprintf (stderr, "Warning:  No element with index %d\n", index);
02651     return (0);
02652   }
02653 
02654   elem = ply->elems[index];
02655 
02656   /* set this to be the current element */
02657   ply->which_elem = elem;
02658 
02659   /* return the number of such elements in the file and the element's name */
02660   *elem_count = elem->num;
02661   return (elem->name);
02662 }
02663 
02664 
02665 /******************************************************************************
02666 Read one element from the file.  This routine assumes that we're reading
02667 the type of element specified in the last call to the routine
02668 setup_element_read_ply().
02669 
02670 Entry:
02671   plyfile  - file identifier
02672   elem_ptr - pointer to location where the element information should be put
02673 ******************************************************************************/
02674 
02675 void get_element_ply (PlyFile *plyfile, void *elem_ptr)
02676 {
02677   if (plyfile->file_type == PLY_ASCII)
02678     ascii_get_element (plyfile, (char *) elem_ptr);
02679   else
02680     binary_get_element (plyfile, (char *) elem_ptr);
02681 }
02682 
02683 
02684 /******************************************************************************
02685 Specify one of several properties of the current element that is to be
02686 read from a file.  This should be called (usually multiple times) before a
02687 call to the routine get_element_ply().
02688 
02689 Entry:
02690   plyfile - file identifier
02691   prop    - property to add to those that will be returned
02692 ******************************************************************************/
02693 
02694 void setup_property_ply(
02695   PlyFile *plyfile,
02696   PlyProperty *prop
02697 )
02698 {
02699   PlyElement *elem;
02700   PlyProperty *prop_ptr;
02701   int index;
02702 
02703   elem = plyfile->which_elem;
02704 
02705   /* deposit the property information into the element's description */
02706 
02707   prop_ptr = find_property (elem, prop->name, &index);
02708   if (prop_ptr == NULL) {
02709     fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
02710              prop->name, elem->name);
02711     return;
02712   }
02713   prop_ptr->internal_type  = prop->internal_type;
02714   prop_ptr->offset         = prop->offset;
02715   prop_ptr->count_internal = prop->count_internal;
02716   prop_ptr->count_offset   = prop->count_offset;
02717 
02718   /* specify that the user wants this property */
02719   elem->store_prop[index] = STORE_PROP;
02720 }
02721 
02722 
02723 /******************************************************************************
02724 Specify that we want the "other" properties of the current element to be tucked
02725 away within the user's structure.
02726 
02727 Entry:
02728   plyfile - file identifier
02729   offset  - offset to where other_props will be stored inside user's structure
02730 
02731 Exit:
02732   returns pointer to structure containing description of other_props
02733 ******************************************************************************/
02734 
02735 PlyOtherProp *get_other_properties_ply(
02736   PlyFile *plyfile,
02737   int offset
02738 )
02739 {
02740   PlyOtherProp *other;
02741 
02742   other = get_other_properties (plyfile, plyfile->which_elem, offset);
02743   return (other);
02744 }
02745 
02746 
02747 /******************************************************************************
02748 Describe which element is to be written next and state how many of them will
02749 be written.
02750 
02751 Entry:
02752   plyfile   - file identifier
02753   elem_name - name of element that information is being described
02754   nelems    - number of elements of this type to be written
02755 ******************************************************************************/
02756 
02757 void describe_element_ply(
02758   PlyFile *plyfile,
02759   char *elem_name,
02760   int nelems
02761 )
02762 {
02763   int i;
02764   PlyElement *elem;
02765   PlyProperty *prop;
02766 
02767   /* look for appropriate element */
02768   elem = find_element (plyfile, elem_name);
02769   if (elem == NULL) {
02770     fprintf(stderr,"describe_element_ply: can't find element '%s'\n",elem_name);
02771     exit (-1);
02772   }
02773 
02774   elem->num = nelems;
02775 
02776   /* now this element is the current element */
02777   plyfile->which_elem = elem;
02778 }
02779 
02780 
02781 /******************************************************************************
02782 Describe a property of an element.
02783 
02784 Entry:
02785   plyfile   - file identifier
02786   prop      - the new property
02787 ******************************************************************************/
02788 
02789 void describe_property_ply(
02790   PlyFile *plyfile,
02791   PlyProperty *prop
02792 )
02793 {
02794   PlyElement *elem;
02795   PlyProperty *elem_prop;
02796 
02797   elem = plyfile->which_elem;
02798 
02799   /* create room for new property */
02800 
02801   if (elem->nprops == 0) {
02802     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
02803     elem->store_prop = (char *) myalloc (sizeof (char));
02804     elem->nprops = 1;
02805   }
02806   else {
02807     elem->nprops++;
02808     elem->props = (PlyProperty **)
02809                   realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
02810     elem->store_prop = (char *)
02811                   realloc (elem->store_prop, sizeof (char) * elem->nprops);
02812   }
02813 
02814   /* copy the new property */
02815 
02816   elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
02817   elem->props[elem->nprops - 1] = elem_prop;
02818   elem->store_prop[elem->nprops - 1] = NAMED_PROP;
02819   copy_property (elem_prop, prop);
02820 }
02821 
02822 
02823 /******************************************************************************
02824 Describe what the "other" properties are that are to be stored, and where
02825 they are in an element.
02826 ******************************************************************************/
02827 
02828 void describe_other_properties_ply(
02829   PlyFile *plyfile,
02830   PlyOtherProp *other,
02831   int offset
02832 )
02833 {
02834   int i;
02835   PlyElement *elem;
02836   PlyProperty *prop;
02837 
02838   /* look for appropriate element */
02839   elem = find_element (plyfile, other->name);
02840   if (elem == NULL) {
02841     fprintf(stderr, "describe_other_properties_ply: can't find element '%s'\n",
02842             other->name);
02843     return;
02844   }
02845 
02846   /* create room for other properties */
02847 
02848   if (elem->nprops == 0) {
02849     elem->props = (PlyProperty **)
02850                   myalloc (sizeof (PlyProperty *) * other->nprops);
02851     elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops);
02852     elem->nprops = 0;
02853   }
02854   else {
02855     int newsize;
02856     newsize = elem->nprops + other->nprops;
02857     elem->props = (PlyProperty **)
02858                   realloc (elem->props, sizeof (PlyProperty *) * newsize);
02859     elem->store_prop = (char *)
02860                   realloc (elem->store_prop, sizeof (char) * newsize);
02861   }
02862 
02863   /* copy the other properties */
02864 
02865   for (i = 0; i < other->nprops; i++) {
02866     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
02867     copy_property (prop, other->props[i]);
02868     elem->props[elem->nprops] = prop;
02869     elem->store_prop[elem->nprops] = OTHER_PROP;
02870     elem->nprops++;
02871   }
02872 
02873   /* save other info about other properties */
02874   elem->other_size = other->size;
02875   elem->other_offset = offset;
02876 }
02877 
02878 
02879 /******************************************************************************
02880 Pass along a pointer to "other" elements that we want to save in a given
02881 PLY file.  These other elements were presumably read from another PLY file.
02882 
02883 Entry:
02884   plyfile     - file pointer in which to store this other element info
02885   other_elems - info about other elements that we want to store
02886 ******************************************************************************/
02887 
02888 void describe_other_elements_ply (
02889   PlyFile *plyfile,
02890   PlyOtherElems *other_elems
02891 )
02892 {
02893   int i;
02894   OtherElem *other;
02895 
02896   /* ignore this call if there is no other element */
02897   if (other_elems == NULL)
02898     return;
02899 
02900   /* save pointer to this information */
02901   plyfile->other_elems = other_elems;
02902 
02903   /* describe the other properties of this element */
02904 
02905   for (i = 0; i < other_elems->num_elems; i++) {
02906     other = &(other_elems->other_list[i]);
02907     element_count_ply (plyfile, other->elem_name, other->elem_count);
02908     describe_other_properties_ply (plyfile, other->other_props,
02909                                    offsetof(OtherData,other_props));
02910   }
02911 }
02912 
02913 
02914 
02915 /**** Property Propagation Rules ****/
02916 
02917 
02918 typedef struct RuleName {
02919   int code;
02920   char *name;
02921 } RuleName;
02922 
02923 RuleName rule_name_list[] = {
02924   AVERAGE_RULE, "avg",
02925   RANDOM_RULE, "rnd",
02926   MINIMUM_RULE, "max",
02927   MAXIMUM_RULE, "min",
02928   MAJORITY_RULE, "major",
02929   SAME_RULE, "same",
02930   -1, "end_marker",
02931 };
02932 
02933 
02934 
02935 /******************************************************************************
02936 Initialize the property propagation rules for an element.  Default is to
02937 use averaging (AVERAGE_RULE) for creating all new properties.
02938 
02939 Entry:
02940   ply       - PLY object that this is for
02941   elem_name - name of the element that we're making the rules for
02942 
02943 Exit:
02944   returns pointer to the default rules
02945 ******************************************************************************/
02946 
02947 PlyPropRules *init_rule_ply (PlyFile *ply, char *elem_name)
02948 {
02949   int i,j;
02950   PlyElement *elem;
02951   PlyPropRules *rules;
02952   PlyRuleList *list;
02953   int found_prop;
02954 
02955   elem = find_element (ply, elem_name);
02956   if (elem == NULL) {
02957     fprintf (stderr, "init_rule_ply: Can't find element '%s'\n", elem_name);
02958     exit (-1);
02959   }
02960 
02961   rules = (PlyPropRules *) myalloc (sizeof (PlyPropRules));
02962   rules->elem = elem;
02963   rules->rule_list = (int *) myalloc (sizeof(int) * elem->nprops);
02964   rules->max_props = 0;
02965   rules->nprops = 0;
02966 
02967   /* default is to use averaging rule */
02968   for (i = 0; i < elem->nprops; i++)
02969     rules->rule_list[i] = AVERAGE_RULE;
02970 
02971   /* see if there are other rules we should use */
02972 
02973   if (ply->rule_list == NULL)
02974     return (rules);
02975 
02976   /* try to match the element, property and rule name */
02977 
02978   for (list = ply->rule_list; list != NULL; list = list->next) {
02979 
02980     if (!equal_strings (list->element, elem->name))
02981       continue;
02982 
02983     found_prop = 0;
02984 
02985     for (i = 0; i < elem->nprops; i++)
02986       if (equal_strings (list->property, elem->props[i]->name)) {
02987 
02988         found_prop = 1;
02989 
02990         /* look for matching rule name */
02991         for (j = 0; rule_name_list[j].code != -1; j++)
02992           if (equal_strings (list->name, rule_name_list[j].name)) {
02993             rules->rule_list[i] = rule_name_list[j].code;
02994             break;
02995           }
02996       }
02997 
02998     if (!found_prop) {
02999       fprintf (stderr, "Can't find property '%s' for rule '%s'\n",
03000                list->property, list->name);
03001       continue;
03002     }
03003   }
03004 
03005   return (rules);
03006 }
03007 
03008 
03009 /******************************************************************************
03010 Modify a property propagation rule.
03011 
03012 Entry:
03013   rules - rules for the element
03014   prop_name - name of the property whose rule we're modifying
03015   rule_type - type of rule (MAXIMUM_RULE, MINIMUM_RULE, MAJORITY_RULE, etc.)
03016 ******************************************************************************/
03017 
03018 void modify_rule_ply (PlyPropRules *rules, char *prop_name, int rule_type)
03019 {
03020   int i;
03021   PlyElement *elem = rules->elem;
03022 
03023   /* find the property and modify its rule type */
03024 
03025   for (i = 0; i < elem->nprops; i++)
03026     if (equal_strings (elem->props[i]->name, prop_name)) {
03027       rules->rule_list[i] = rule_type;
03028       return;
03029     }
03030 
03031   /* we didn't find the property if we get here */
03032   fprintf (stderr, "modify_rule_ply: Can't find property '%s'\n", prop_name);
03033   exit (-1);
03034 }
03035 
03036 
03037 /******************************************************************************
03038 Begin to create a set of properties from a set of propagation rules.
03039 
03040 Entry:
03041   ply   - PLY object whose rules we're preparing to use
03042   rules - rules for the element
03043 ******************************************************************************/
03044 
03045 void start_props_ply (PlyFile *ply, PlyPropRules *rules)
03046 {
03047   int i;
03048   int count;
03049   PlyElement *elem = rules->elem;
03050 
03051   /* save pointer to the rules in the PLY object */
03052   ply->current_rules = rules;
03053 
03054   /* get ready for new sets of properties to combine */
03055   rules->nprops = 0;
03056 }
03057 
03058 
03059 /******************************************************************************
03060 Remember a set of properties and their weights for creating a new set of
03061 properties.
03062 
03063 Entry:
03064   weight      - weights for this set of properties
03065   other_props - the properties to use
03066 ******************************************************************************/
03067 
03068 void weight_props_ply (PlyFile *ply, float weight, void *other_props)
03069 {
03070   PlyPropRules *rules = ply->current_rules;
03071 
03072   /* allocate space for properties and weights, if necessary */
03073   if (rules->max_props == 0) {
03074     rules->max_props = 6;
03075     rules->props = (void **) myalloc (sizeof (void *) * rules->max_props);
03076     rules->weights = (float *) myalloc (sizeof (float) * rules->max_props);
03077   }
03078   if (rules->nprops == rules->max_props) {
03079     rules->max_props *= 2;
03080     rules->props = (void **) realloc (rules->props,
03081                    sizeof (void *) * rules->max_props);
03082     rules->weights = (float *) realloc (rules->weights,
03083                      sizeof (float) * rules->max_props);
03084   }
03085 
03086   /* remember these new properties and their weights */
03087 
03088   rules->props[rules->nprops] = other_props;
03089   rules->weights[rules->nprops] = weight;
03090   rules->nprops++;
03091 }
03092 
03093 
03094 /******************************************************************************
03095 Return a pointer to a new set of properties that have been created using
03096 a specified set of property combination rules and a given collection of
03097 "other" properties.
03098 
03099 Exit:
03100   returns a pointer to the new properties
03101 ******************************************************************************/
03102 
03103 void *get_new_props_ply(PlyFile *ply)
03104 {
03105   int i,j;
03106   static double *vals;
03107   static int max_vals = 0;
03108   PlyPropRules *rules = ply->current_rules;
03109   PlyElement *elem = rules->elem;
03110   PlyProperty *prop;
03111   char *data;
03112   char *new_data;
03113   void *ptr;
03114   int offset;
03115   int type;
03116   double double_val;
03117   int int_val;
03118   unsigned int uint_val;
03119   int random_pick;
03120 
03121   /* return NULL if we've got no "other" properties */
03122   if (elem->other_size == 0) {
03123     return (NULL);
03124   }
03125 
03126   /* create room for combined other properties */
03127   new_data = (char *) myalloc (sizeof (char) * elem->other_size);
03128 
03129   /* make sure there is enough room to store values we're to combine */
03130 
03131   if (max_vals == 0) {
03132     max_vals = rules->nprops;
03133     vals = (double *) myalloc (sizeof (double) * rules->nprops);
03134   }
03135   if (rules->nprops >= max_vals) {
03136     max_vals = rules->nprops;
03137     vals = (double *) realloc (vals, sizeof (double) * rules->nprops);
03138   }
03139 
03140   /* in case we need a random choice */
03141   random_pick = (int) floor (rules->nprops * drand48());
03142 
03143   /* calculate the combination for each "other" property of the element */
03144 
03145   for (i = 0; i < elem->nprops; i++) {
03146 
03147     /* don't bother with properties we've been asked to store explicitly */
03148     if (elem->store_prop[i])
03149       continue;
03150 
03151     prop = elem->props[i];
03152     offset = prop->offset;
03153     type = prop->external_type;
03154 
03155     /* collect together all the values we're to combine */
03156 
03157     for (j = 0; j < rules->nprops; j++) {
03158       data = (char *) rules->props[j];
03159       ptr = (void *) (data + offset);
03160       get_stored_item ((void *) ptr, type, &int_val, &uint_val, &double_val);
03161       vals[j] = double_val;
03162     }
03163 
03164     /* calculate the combined value */
03165 
03166     switch (rules->rule_list[i]) {
03167       case AVERAGE_RULE: {
03168    double sum = 0;
03169    double weight_sum = 0;
03170    for (j = 0; j < rules->nprops; j++) {
03171      sum += vals[j] * rules->weights[j];
03172      weight_sum += rules->weights[j];
03173    }
03174    double_val = sum / weight_sum;
03175         break;
03176       }
03177       case MINIMUM_RULE: {
03178    double_val = vals[0];
03179    for (j = 1; j < rules->nprops; j++)
03180      if (double_val > vals[j])
03181        double_val = vals[j];
03182         break;
03183       }
03184       case MAXIMUM_RULE: {
03185    double_val = vals[0];
03186    for (j = 1; j < rules->nprops; j++)
03187      if (double_val < vals[j])
03188        double_val = vals[j];
03189         break;
03190       }
03191       case RANDOM_RULE: {
03192    double_val = vals[random_pick];
03193         break;
03194       }
03195       case SAME_RULE: {
03196    double_val = vals[0];
03197    for (j = 1; j < rules->nprops; j++)
03198      if (double_val != vals[j]) {
03199        fprintf (stderr,
03200     "get_new_props_ply: Error combining properties that should be the same.\n");
03201             exit (-1);
03202      }
03203         break;
03204       }
03205       default:
03206         fprintf (stderr, "get_new_props_ply: Bad rule = %d\n",
03207             rules->rule_list[i]);
03208    exit (-1);
03209     }
03210 
03211     /* store the combined value */
03212 
03213     int_val = (int) double_val;
03214     uint_val = (unsigned int) double_val;
03215     ptr = (void *) (new_data + offset);
03216     store_item ((char *) ptr, type, int_val, uint_val, double_val);
03217   }
03218 
03219   return ((void *) new_data);
03220 }
03221 
03222 
03223 /******************************************************************************
03224 Set the list of user-specified property combination rules.
03225 ******************************************************************************/
03226 
03227 void set_prop_rules_ply (PlyFile *ply, PlyRuleList *prop_rules)
03228 {
03229   ply->rule_list = prop_rules;
03230 }
03231 
03232 
03233 /******************************************************************************
03234 Append a property rule to a growing list of user-specified rules.
03235 
03236 Entry:
03237   rule_list - current rule list
03238   name      - name of property combination rule
03239   property  - "element.property" says which property the rule affects
03240 
03241 Exit:
03242   returns pointer to the new rule list
03243 ******************************************************************************/
03244 
03245 PlyRuleList *append_prop_rule (
03246   PlyRuleList *rule_list,
03247   char *name,
03248   char *property
03249 )
03250 {
03251   PlyRuleList *rule;
03252   PlyRuleList *rule_ptr;
03253   char *str,*str2;
03254   char *ptr;
03255 
03256   /* find . */
03257   str = strdup (property);
03258   for (ptr = str; *ptr != '\0' && *ptr != '.'; ptr++) ;
03259 
03260   /* split string at . */
03261   if (*ptr == '.') {
03262     *ptr = '\0';
03263     str2 = ptr + 1;
03264   }
03265   else {
03266     fprintf (stderr, "Can't find property '%s' for rule '%s'\n",
03267              property, name);
03268     return (rule_list);
03269   }
03270 
03271   rule = (PlyRuleList *) malloc (sizeof (PlyRuleList));
03272   rule->name = name;
03273   rule->element = str;
03274   rule->property = str2;
03275   rule->next = NULL;
03276 
03277   /* either start rule list or append to it */
03278 
03279   if (rule_list == NULL)
03280     rule_list = rule;
03281   else {                      /* append new rule to current list */
03282     rule_ptr = rule_list;
03283     while (rule_ptr->next != NULL)
03284       rule_ptr = rule_ptr->next;
03285     rule_ptr->next = rule;
03286   }
03287 
03288   /* return pointer to list */
03289 
03290   return (rule_list);
03291 }
03292 
03293 
03294 /******************************************************************************
03295 See if a name matches the name of any property combination rules.
03296 
03297 Entry:
03298   name - name of rule we're trying to match
03299 
03300 Exit:
03301   returns 1 if we find a match, 0 if not
03302 ******************************************************************************/
03303 
03304 int matches_rule_name (char *name)
03305 {
03306   int i;
03307 
03308   for (i = 0; rule_name_list[i].code != -1; i++)
03309     if (equal_strings (rule_name_list[i].name, name))
03310       return (1);
03311 
03312   return (0);
03313 }
03314 

Generated on Mon Sep 18 11:39:32 2006 for jot by  doxygen 1.4.4