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