db5_scan.c

Go to the documentation of this file.
00001 /*                      D B 5 _ S C A N . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup db5 */
00023 /*@{*/
00024 /** @file db5_scan.c
00025  *  Scan a v5 database, sending each object off to a handler.
00026  *
00027  *  Author -
00028  *      Michael John Muuss
00029  *
00030  *  Source -
00031  *      The U. S. Army Research Laboratory
00032  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00033  *
00034  */
00035 
00036 #ifndef lint
00037 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/db5_scan.c,v 14.13 2006/09/16 02:04:24 lbutler Exp $ (ARL)";
00038 #endif
00039 
00040 #include "common.h"
00041 
00042 #include <stdio.h>
00043 #ifdef HAVE_STRING_H
00044 #  include <string.h>
00045 #else
00046 #  include <strings.h>
00047 #endif
00048 
00049 #include "machine.h"
00050 #include "bu.h"
00051 #include "vmath.h"
00052 #include "bn.h"
00053 #include "db5.h"
00054 #include "raytrace.h"
00055 
00056 #include "./debug.h"
00057 
00058 
00059 /**
00060  *                      D B 5 _ S C A N
00061  *
00062  * Returns -
00063  *       0      Success
00064  *      -1      Fatal Error
00065  */
00066 int
00067 db5_scan(
00068          struct db_i    *dbip,
00069          void           (*handler)(struct db_i *,
00070                                    const struct db5_raw_internal *,
00071                                    long addr, genptr_t client_data ),
00072          genptr_t       client_data )
00073 {
00074     unsigned char       header[8];
00075     struct db5_raw_internal     raw;
00076     int                 got;
00077     long                        nrec;
00078     long                        addr;
00079 
00080     RT_CK_DBI(dbip);
00081     if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_scan( x%x, x%x )\n", dbip, handler);
00082 
00083     raw.magic = DB5_RAW_INTERNAL_MAGIC;
00084     nrec = 0L;
00085 
00086     /* Fast-path when file is already memory-mapped */
00087     if( dbip->dbi_mf )  {
00088         const unsigned char     *cp = (const unsigned char *)dbip->dbi_inmem;
00089         long    eof;
00090 
00091         BU_CK_MAPPED_FILE(dbip->dbi_mf);
00092         eof = dbip->dbi_mf->buflen;
00093 
00094         if( db5_header_is_valid( cp ) == 0 )  {
00095             bu_log("db5_scan ERROR:  %s is lacking a proper BRL-CAD v5 database header\n", dbip->dbi_filename);
00096             goto fatal;
00097         }
00098         cp += sizeof(header);
00099         addr = sizeof(header);
00100         while( addr < eof )  {
00101             if( (cp = db5_get_raw_internal_ptr( &raw, cp )) == NULL )  {
00102                 goto fatal;
00103             }
00104             (*handler)(dbip, &raw, addr, client_data);
00105             nrec++;
00106             addr += raw.object_length;
00107         }
00108         dbip->dbi_eof = addr;
00109         BU_ASSERT_LONG( dbip->dbi_eof, ==, dbip->dbi_mf->buflen );
00110     }  else  {
00111         /* In a totally portable way, read the database with stdio */
00112         rewind( dbip->dbi_fp );
00113         if( fread( header, sizeof header, 1, dbip->dbi_fp ) != 1  ||
00114             db5_header_is_valid( header ) == 0 )  {
00115             bu_log("db5_scan ERROR:  %s is lacking a proper BRL-CAD v5 database header\n", dbip->dbi_filename);
00116             goto fatal;
00117         }
00118         for(;;)  {
00119             addr = ftell( dbip->dbi_fp );
00120             if( (got = db5_get_raw_internal_fp( &raw, dbip->dbi_fp )) < 0 )  {
00121                 if( got == -1 )  break;         /* EOF */
00122                 goto fatal;
00123             }
00124             (*handler)(dbip, &raw, addr, client_data);
00125             nrec++;
00126             if(raw.buf)  {
00127                 bu_free(raw.buf, "raw v5 object");
00128                 raw.buf = NULL;
00129             }
00130         }
00131         dbip->dbi_eof = ftell( dbip->dbi_fp );
00132         rewind( dbip->dbi_fp );
00133     }
00134 
00135     dbip->dbi_nrec = nrec;              /* # obj in db, not inc. header */
00136     return 0;                   /* success */
00137 
00138  fatal:
00139     dbip->dbi_read_only = 1;    /* Writing would corrupt it worse */
00140     return -1;                  /* fatal error */
00141 }
00142 
00143 
00144 struct directory *
00145 db_diradd5(
00146            struct db_i                          *dbip,
00147            const char                           *name,
00148            long                                 laddr,
00149            unsigned char                        major_type,
00150            unsigned char                        minor_type,
00151            unsigned char                        name_hidden,
00152            long                                 object_length,
00153            struct bu_attribute_value_set        *avs)
00154 {
00155     struct directory **headp;
00156     register struct directory *dp;
00157     struct bu_vls local;
00158 
00159     RT_CK_DBI( dbip );
00160 
00161     bu_vls_init(&local);
00162     bu_vls_strcpy(&local, name);
00163     if (db_dircheck(dbip, &local, 0, &headp) < 0) {
00164         bu_vls_free(&local);
00165         return DIR_NULL;
00166     }
00167 
00168     if( rt_uniresource.re_magic == 0 )
00169         rt_init_resource( &rt_uniresource, 0, NULL );
00170 
00171     /* Duplicates the guts of db_diradd() */
00172     RT_GET_DIRECTORY( dp, &rt_uniresource );
00173     RT_CK_DIR(dp);
00174     BU_LIST_INIT( &dp->d_use_hd );
00175     RT_DIR_SET_NAMEP(dp, bu_vls_addr( &local ));        /* sets d_namep */
00176     bu_vls_free( &local );
00177     dp->d_un.ptr = NULL;
00178     dp->d_un.file_offset = laddr;
00179     dp->d_major_type = major_type;
00180     dp->d_minor_type = minor_type;
00181     switch( major_type )  {
00182         case DB5_MAJORTYPE_BRLCAD:
00183             if( minor_type == ID_COMBINATION )  {
00184 
00185                 dp->d_flags = DIR_COMB;
00186                 if( !avs || avs->count == 0 )  break;
00187                 /*
00188                  *  check for the "region=" attribute.
00189                  */
00190                 if( bu_avs_get( avs, "region" ) != NULL )
00191                     dp->d_flags = DIR_COMB|DIR_REGION;
00192             } else {
00193                 dp->d_flags = DIR_SOLID;
00194             }
00195             break;
00196         case DB5_MAJORTYPE_BINARY_EXPM:
00197         case DB5_MAJORTYPE_BINARY_UNIF:
00198         case DB5_MAJORTYPE_BINARY_MIME:
00199             /* XXX Do we want to define extra flags for this? */
00200             dp->d_flags = DIR_NON_GEOM;
00201             break;
00202         case DB5_MAJORTYPE_ATTRIBUTE_ONLY:
00203             dp->d_flags = 0;
00204     }
00205     if( name_hidden )
00206         dp->d_flags |= DIR_HIDDEN;
00207     dp->d_len = object_length;          /* in bytes */
00208     BU_LIST_INIT( &dp->d_use_hd );
00209     dp->d_animate = NULL;
00210     dp->d_nref = 0;
00211     dp->d_uses = 0;
00212     dp->d_forw = *headp;
00213     *headp = dp;
00214 
00215     return( dp );
00216 }
00217 
00218 
00219 struct directory *
00220 db5_diradd(struct db_i                  *dbip,
00221            const struct db5_raw_internal *rip,
00222            long                         laddr,
00223            genptr_t                     client_data )
00224 {
00225     struct directory **headp;
00226     register struct directory *dp;
00227     struct bu_vls local;
00228 
00229     RT_CK_DBI( dbip );
00230 
00231     bu_vls_init(&local);
00232     bu_vls_strcpy(&local, rip->name.ext_buf);
00233     if (db_dircheck(dbip, &local, 0, &headp) < 0) {
00234         bu_vls_free(&local);
00235         return DIR_NULL;
00236     }
00237 
00238     if( rt_uniresource.re_magic == 0 )
00239         rt_init_resource( &rt_uniresource, 0, NULL );
00240 
00241     /* Duplicates the guts of db_diradd() */
00242     RT_GET_DIRECTORY( dp, &rt_uniresource );
00243     RT_CK_DIR(dp);
00244     BU_LIST_INIT( &dp->d_use_hd );
00245     RT_DIR_SET_NAMEP(dp, bu_vls_addr(&local));  /* sets d_namep */
00246     bu_vls_free(&local);
00247     dp->d_un.file_offset = laddr;
00248     dp->d_major_type = rip->major_type;
00249     dp->d_minor_type = rip->minor_type;
00250     switch( rip->major_type )  {
00251         case DB5_MAJORTYPE_BRLCAD:
00252             if( rip->minor_type == ID_COMBINATION )  {
00253                 struct bu_attribute_value_set   avs;
00254 
00255                 bu_avs_init_empty(&avs);
00256 
00257                 dp->d_flags = DIR_COMB;
00258                 if( rip->attributes.ext_nbytes == 0 )  break;
00259                 /*
00260                  *  Crack open the attributes to
00261                  *  check for the "region=" attribute.
00262                  */
00263                 if( db5_import_attributes( &avs, &rip->attributes ) < 0 )  {
00264                     bu_log("db5_diradd_handler: Bad attributes on combination '%s'\n",
00265                            rip->name);
00266                     break;
00267                 }
00268                 if( bu_avs_get( &avs, "region" ) != NULL )
00269                     dp->d_flags = DIR_COMB|DIR_REGION;
00270                 bu_avs_free( &avs );
00271             } else {
00272                 dp->d_flags = DIR_SOLID;
00273             }
00274             break;
00275         case DB5_MAJORTYPE_BINARY_EXPM:
00276         case DB5_MAJORTYPE_BINARY_UNIF:
00277         case DB5_MAJORTYPE_BINARY_MIME:
00278             /* XXX Do we want to define extra flags for this? */
00279             dp->d_flags = DIR_NON_GEOM;
00280             break;
00281         case DB5_MAJORTYPE_ATTRIBUTE_ONLY:
00282             dp->d_flags = 0;
00283     }
00284     if( rip->h_name_hidden )
00285         dp->d_flags |= DIR_HIDDEN;
00286     dp->d_len = rip->object_length;             /* in bytes */
00287     BU_LIST_INIT( &dp->d_use_hd );
00288     dp->d_animate = NULL;
00289     dp->d_nref = 0;
00290     dp->d_uses = 0;
00291     dp->d_forw = *headp;
00292     *headp = dp;
00293 
00294     return( dp );
00295 }
00296 
00297 
00298 /**
00299  *                      D B 5 _ D I R A D D _ H A N D L E R
00300  *
00301  * In support of db5_scan, add a named entry to the directory.
00302  */
00303 HIDDEN void
00304 db5_diradd_handler(
00305                    struct db_i          *dbip,
00306                    const struct db5_raw_internal *rip,
00307                    long                 laddr,
00308                    genptr_t             client_data )   /* unused client_data from db5_scan() */
00309 {
00310     RT_CK_DBI(dbip);
00311 
00312     if( rip->h_dli == DB5HDR_HFLAGS_DLI_HEADER_OBJECT )  return;
00313     if( rip->h_dli == DB5HDR_HFLAGS_DLI_FREE_STORAGE )  {
00314         /* Record available free storage */
00315         rt_memfree( &(dbip->dbi_freep), rip->object_length, laddr );
00316         return;
00317     }
00318 
00319     /* If somehow it doesn't have a name, ignore it */
00320     if( rip->name.ext_buf == NULL )  return;
00321 
00322     if(RT_G_DEBUG&DEBUG_DB)  {
00323         bu_log("db5_diradd_handler(dbip=x%x, name='%s', addr=x%x, len=%d)\n",
00324                dbip, rip->name, laddr, rip->object_length );
00325     }
00326 
00327     db5_diradd( dbip, rip, laddr, client_data );
00328 
00329     return;
00330 }
00331 
00332 
00333 /**
00334  *                      D B _ D I R B U I L D
00335  *
00336  *  A generic routine to determine the type of the database,
00337  *  (v4 or v5)
00338  *  and to invoke the appropriate db_scan()-like routine to
00339  *  build the in-memory directory.
00340  *
00341  *  It is the caller's responsibility to close the database in case of error.
00342  *
00343  *  Called from rt_dirbuild(), and g_submodel.c
00344  *
00345  *  Returns -
00346  *      0       OK
00347  *      -1      failure
00348  */
00349 int
00350 db_dirbuild( struct db_i *dbip )
00351 {
00352     unsigned char       header[8];
00353 
00354     RT_CK_DBI(dbip);
00355 
00356     /* First, determine what version database this is */
00357     rewind(dbip->dbi_fp);
00358     if( fread( header, sizeof header, 1, dbip->dbi_fp ) != 1  )  {
00359         bu_log("db_dirbuild(%s) ERROR, file too short to be BRL-CAD database\n",
00360                dbip->dbi_filename);
00361         return -1;
00362     }
00363 
00364     if( db5_header_is_valid( header ) )  {
00365         struct directory        *dp;
00366         struct bu_external      ext;
00367         struct db5_raw_internal raw;
00368         struct bu_attribute_value_set   avs;
00369         const char              *cp;
00370 
00371         bu_avs_init_empty(&avs);
00372 
00373         /* File is v5 format */
00374         dbip->dbi_version = 5;
00375         if( db5_scan( dbip, db5_diradd_handler, NULL ) < 0 )  {
00376             bu_log("db_dirbuild(%s): db5_scan() failed\n",
00377                    dbip->dbi_filename);
00378             return -1;
00379         }
00380 
00381         /* Need to retrieve _GLOBAL object and obtain title and units */
00382         if( (dp = db_lookup( dbip, DB5_GLOBAL_OBJECT_NAME, LOOKUP_NOISY )) == DIR_NULL )  {
00383             bu_log("db_dirbuild(%s): improper database, no %s object\n",
00384                    dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME );
00385             dbip->dbi_title = bu_strdup(DB5_GLOBAL_OBJECT_NAME);
00386             /* Missing _GLOBAL object so create it and set default title and units */
00387             db5_update_ident(dbip, "Untitled BRL-CAD Database",1.0);
00388             return 0;   /* not a fatal error, user may have deleted it */
00389         }
00390         BU_INIT_EXTERNAL(&ext);
00391         if( db_get_external( &ext, dp, dbip ) < 0 ||
00392             db5_get_raw_internal_ptr( &raw, ext.ext_buf ) == NULL )  {
00393             bu_log("db_dirbuild(%s): improper database, unable to read %s object\n",
00394                    dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME );
00395             return -1;
00396         }
00397         if( raw.major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY )  {
00398             bu_log("db_dirbuild(%s): improper database, %s exists but is not an attribute-only object\n",
00399                    dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME );
00400             dbip->dbi_title = bu_strdup(DB5_GLOBAL_OBJECT_NAME);
00401             return 0;   /* not a fatal error, need to let user proceed to fix it */
00402         }
00403         if( db5_import_attributes( &avs, &raw.attributes ) < 0 )  {
00404             bu_log("db_dirbuild(%s): improper database, corrupted attribute-only %s object\n",
00405                    dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME );
00406             bu_free_external(&ext);
00407             return -1;  /* this is fatal */
00408         }
00409         BU_CK_AVS( &avs );
00410 
00411         /* Parse out the attributes */
00412         if( (cp = bu_avs_get( &avs, "title" )) != NULL )  {
00413             dbip->dbi_title = bu_strdup( cp );
00414         } else {
00415             dbip->dbi_title = bu_strdup( "Untitled BRL-CAD database" );
00416         }
00417         if( (cp = bu_avs_get( &avs, "units" )) != NULL )  {
00418             double      dd;
00419             if( sscanf( cp, "%lf", &dd ) != 1 ||
00420                 NEAR_ZERO( dd, VUNITIZE_TOL ) )  {
00421                 bu_log("db_dirbuild(%s): improper database, %s object attribute 'units'=%s is invalid\n",
00422                        dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME,
00423                        cp );
00424                 /* Not fatal, just stick with default value from db_open() */
00425             } else {
00426                 dbip->dbi_local2base = dd;
00427                 dbip->dbi_base2local = 1/dd;
00428             }
00429         }
00430         if( (cp = bu_avs_get( &avs, "regionid_colortable")) != NULL )  {
00431             /* Import the region-id coloring table */
00432             db5_import_color_table( (char *)cp);
00433         }
00434         bu_avs_free( &avs );
00435         bu_free_external(&ext); /* not until after done with avs! */
00436         return 0;
00437     }
00438 
00439     /* Make a very simple check for a v4 database */
00440     if( header[0] == 'I' )  {
00441         dbip->dbi_version = 4;
00442         if( db_scan( dbip, (int (*)())db_diradd, 1, NULL ) < 0 )  {
00443             dbip->dbi_version = 0;
00444             return -1;
00445         }
00446         return 0;               /* ok */
00447     }
00448 
00449     bu_log("db_dirbuild(%s) ERROR, file is not in BRL-CAD geometry database format\n",
00450            dbip->dbi_filename);
00451     return -1;
00452 }
00453 
00454 
00455 int
00456 db_get_version(struct db_i *dbip)
00457 {
00458     unsigned char       header[8];
00459 
00460     rewind(dbip->dbi_fp);
00461     if( fread( header, sizeof header, 1, dbip->dbi_fp ) != 1  )  {
00462         bu_log("db_get_version ERROR, file (%s) too short to be BRL-CAD database\n",
00463                dbip->dbi_filename);
00464         return -1;
00465     }
00466 
00467     if( db5_header_is_valid( header ) )
00468         return( 5 );
00469     else if( header[0] == 'I' )
00470         return( 4 );
00471     else
00472         return( -1 );
00473 
00474 }
00475 
00476 /*@}*/
00477 /*
00478  * Local Variables:
00479  * mode: C
00480  * tab-width: 8
00481  * c-basic-offset: 4
00482  * indent-tabs-mode: t
00483  * End:
00484  * ex: shiftwidth=4 tabstop=8
00485  */

Generated on Mon Sep 18 01:24:49 2006 for BRL-CAD by  doxygen 1.4.6