BRL-CAD
db5_scan.c
Go to the documentation of this file.
1 /* D B 5 _ S C A N . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2004-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include "bio.h"
26 
27 
28 #include "bu/parse.h"
29 #include "vmath.h"
30 #include "bn.h"
31 #include "db5.h"
32 #include "raytrace.h"
33 
34 
35 int
37  struct db_i *dbip,
38  void (*handler)(struct db_i *,
39  const struct db5_raw_internal *,
40  off_t addr, void *client_data),
41  void *client_data)
42 {
43  unsigned char header[8];
44  struct db5_raw_internal raw;
45  int got;
46  size_t nrec;
47  off_t addr;
48 
49  RT_CK_DBI(dbip);
50  if (RT_G_DEBUG&DEBUG_DB) bu_log("db5_scan(%p, %lx)\n",
51  (void *)dbip, (long unsigned int)handler);
52 
53  raw.magic = DB5_RAW_INTERNAL_MAGIC;
54  nrec = 0L;
55 
56  /* Fast-path when file is already memory-mapped */
57  if (dbip->dbi_mf) {
58  const unsigned char *cp = (const unsigned char *)dbip->dbi_inmem;
59  off_t eof;
60 
62  eof = (off_t)dbip->dbi_mf->buflen;
63 
64  if (db5_header_is_valid(cp) == 0) {
65  bu_log("db5_scan ERROR: %s is lacking a proper BRL-CAD v5 database header\n", dbip->dbi_filename);
66  goto fatal;
67  }
68  cp += sizeof(header);
69  addr = (off_t)sizeof(header);
70  while (addr < eof) {
71  if ((cp = db5_get_raw_internal_ptr(&raw, cp)) == NULL) {
72  goto fatal;
73  }
74  (*handler)(dbip, &raw, addr, client_data);
75  nrec++;
76  addr += (off_t)raw.object_length;
77  }
78  dbip->dbi_eof = addr;
79  BU_ASSERT_LONG(dbip->dbi_eof, ==, (off_t)dbip->dbi_mf->buflen);
80  } else {
81  /* In a totally portable way, read the database with stdio */
82  rewind(dbip->dbi_fp);
83  if (fread(header, sizeof header, 1, dbip->dbi_fp) != 1 ||
84  db5_header_is_valid(header) == 0) {
85  bu_log("db5_scan ERROR: %s is lacking a proper BRL-CAD v5 database header\n", dbip->dbi_filename);
86  goto fatal;
87  }
88  for (;;) {
89  addr = bu_ftell(dbip->dbi_fp);
90  if ((got = db5_get_raw_internal_fp(&raw, dbip->dbi_fp)) < 0) {
91  if (got == -1) break; /* EOF */
92  goto fatal;
93  }
94  (*handler)(dbip, &raw, addr, client_data);
95  nrec++;
96  if (raw.buf) {
97  bu_free(raw.buf, "raw v5 object");
98  raw.buf = NULL;
99  }
100  }
101  dbip->dbi_eof = bu_ftell(dbip->dbi_fp);
102  rewind(dbip->dbi_fp);
103  }
104 
105  dbip->dbi_nrec = nrec; /* # obj in db, not inc. header */
106  return 0; /* success */
107 
108 fatal:
109  dbip->dbi_read_only = 1; /* Writing could corrupt it worse */
110  return -1; /* fatal error */
111 }
112 
113 
114 struct directory *
116  struct db_i *dbip,
117  const char *name,
118  off_t laddr,
119  unsigned char major_type,
120  unsigned char minor_type,
121  unsigned char name_hidden,
122  size_t object_length,
123  struct bu_attribute_value_set *avs)
124 {
125  struct directory **headp;
126  register struct directory *dp;
127  struct bu_vls local = BU_VLS_INIT_ZERO;
128 
129  RT_CK_DBI(dbip);
130 
131  bu_vls_strcpy(&local, name);
132  if (db_dircheck(dbip, &local, 0, &headp) < 0) {
133  bu_vls_free(&local);
134  return RT_DIR_NULL;
135  }
136 
137  if (rt_uniresource.re_magic == 0)
138  rt_init_resource(&rt_uniresource, 0, NULL);
139 
140  /* Duplicates the guts of db_diradd() */
142  RT_CK_DIR(dp);
143  BU_LIST_INIT(&dp->d_use_hd);
144  RT_DIR_SET_NAMEP(dp, bu_vls_addr(&local)); /* sets d_namep */
145  bu_vls_free(&local);
146  dp->d_un.ptr = NULL;
147  dp->d_addr = laddr;
148  dp->d_major_type = major_type;
149  dp->d_minor_type = minor_type;
150  switch (major_type) {
151  case DB5_MAJORTYPE_BRLCAD:
152  if (minor_type == ID_COMBINATION) {
153 
154  dp->d_flags = RT_DIR_COMB;
155  if (!avs || avs->count == 0) break;
156  /*
157  * check for the "region=" attribute.
158  */
159  if (bu_avs_get(avs, "region") != NULL)
161  } else {
162  dp->d_flags = RT_DIR_SOLID;
163  }
164  break;
165  case DB5_MAJORTYPE_BINARY_UNIF:
166  case DB5_MAJORTYPE_BINARY_MIME:
167  /* XXX Do we want to define extra flags for this? */
168  dp->d_flags = RT_DIR_NON_GEOM;
169  break;
170  case DB5_MAJORTYPE_ATTRIBUTE_ONLY:
171  dp->d_flags = 0;
172  }
173  if (name_hidden)
174  dp->d_flags |= RT_DIR_HIDDEN;
175  dp->d_len = object_length; /* in bytes */
176  BU_LIST_INIT(&dp->d_use_hd);
177  dp->d_animate = NULL;
178  dp->d_nref = 0;
179  dp->d_uses = 0;
180  dp->d_forw = *headp;
181  *headp = dp;
182 
183  return dp;
184 }
185 
186 
187 struct directory *
188 db5_diradd(struct db_i *dbip,
189  const struct db5_raw_internal *rip,
190  off_t laddr,
191  void *client_data)
192 {
193  struct directory **headp;
194  register struct directory *dp;
195  struct bu_vls local = BU_VLS_INIT_ZERO;
196 
197  RT_CK_DBI(dbip);
198 
199  if (client_data && RT_G_DEBUG&DEBUG_DB) {
200  bu_log("WARNING: db5_diradd() received non-NULL client_data\n");
201  }
202 
203  bu_vls_strcpy(&local, (const char *)rip->name.ext_buf);
204  if (db_dircheck(dbip, &local, 0, &headp) < 0) {
205  bu_vls_free(&local);
206  return RT_DIR_NULL;
207  }
208 
209  if (rt_uniresource.re_magic == 0)
210  rt_init_resource(&rt_uniresource, 0, NULL);
211 
212  /* Duplicates the guts of db_diradd() */
213  RT_GET_DIRECTORY(dp, &rt_uniresource); /* allocates a new dir */
214  RT_CK_DIR(dp);
215  BU_LIST_INIT(&dp->d_use_hd);
216  RT_DIR_SET_NAMEP(dp, bu_vls_addr(&local)); /* sets d_namep */
217  bu_vls_free(&local);
218  dp->d_addr = laddr;
219  dp->d_major_type = rip->major_type;
220  dp->d_minor_type = rip->minor_type;
221  switch (rip->major_type) {
222  case DB5_MAJORTYPE_BRLCAD:
223  if (rip->minor_type == ID_COMBINATION) {
224  struct bu_attribute_value_set avs;
225 
226  bu_avs_init_empty(&avs);
227 
228  dp->d_flags = RT_DIR_COMB;
229  if (rip->attributes.ext_nbytes == 0) break;
230  /*
231  * Crack open the attributes to
232  * check for the "region=" attribute.
233  */
234  if (db5_import_attributes(&avs, &rip->attributes) < 0) {
235  bu_log("db5_diradd_handler: Bad attributes on combination '%s'\n",
236  rip->name.ext_buf);
237  break;
238  }
239  if (bu_avs_get(&avs, "region") != NULL)
241  bu_avs_free(&avs);
242  } else {
243  dp->d_flags = RT_DIR_SOLID;
244  }
245  break;
246  case DB5_MAJORTYPE_BINARY_UNIF:
247  case DB5_MAJORTYPE_BINARY_MIME:
248  /* XXX Do we want to define extra flags for this? */
249  dp->d_flags = RT_DIR_NON_GEOM;
250  break;
251  case DB5_MAJORTYPE_ATTRIBUTE_ONLY:
252  dp->d_flags = 0;
253  }
254  if (rip->h_name_hidden)
255  dp->d_flags |= RT_DIR_HIDDEN;
256  dp->d_len = rip->object_length; /* in bytes */
257  BU_LIST_INIT(&dp->d_use_hd);
258  dp->d_animate = NULL;
259  dp->d_nref = 0;
260  dp->d_uses = 0;
261  dp->d_forw = *headp;
262  *headp = dp;
263 
264  return dp;
265 }
266 
267 
268 /*
269  * In support of db5_scan, add a named entry to the directory.
270  */
271 HIDDEN void
273  struct db_i *dbip,
274  const struct db5_raw_internal *rip,
275  off_t laddr,
276  void *client_data) /* unused client_data from db5_scan() */
277 {
278  RT_CK_DBI(dbip);
279 
280  if (rip->h_dli == DB5HDR_HFLAGS_DLI_HEADER_OBJECT) return;
281  if (rip->h_dli == DB5HDR_HFLAGS_DLI_FREE_STORAGE) {
282  /* Record available free storage */
283  rt_memfree(&(dbip->dbi_freep), rip->object_length, laddr);
284  return;
285  }
286 
287  /* If somehow it doesn't have a name, ignore it */
288  if (rip->name.ext_buf == NULL) return;
289 
290  if (RT_G_DEBUG&DEBUG_DB) {
291  bu_log("db5_diradd_handler(dbip=%p, name='%s', addr=%ld, len=%zu)\n",
292  (void *)dbip, rip->name.ext_buf, laddr, rip->object_length);
293  }
294 
295  db5_diradd(dbip, rip, laddr, client_data);
296 
297  return;
298 }
299 
300 int
301 db_dirbuild(struct db_i *dbip)
302 {
303  int version;
304 
305  if (!dbip) {
306  return -1;
307  }
308 
309  RT_CK_DBI(dbip);
310 
311  if (!dbip->dbi_fp) {
312  return -1;
313  }
314 
315  /* First, determine what version database this is */
316  version = db_version(dbip);
317 
318  if (version == 5) {
319  struct directory *dp;
320  struct bu_external ext;
321  struct db5_raw_internal raw;
322  struct bu_attribute_value_set avs;
323  const char *cp;
324 
325  bu_avs_init_empty(&avs);
326 
327  /* File is v5 format */
328  if (db5_scan(dbip, db5_diradd_handler, NULL) < 0) {
329  bu_log("db_dirbuild(%s): db5_scan() failed\n", dbip->dbi_filename);
330  return -1;
331  }
332 
333  /* Need to retrieve _GLOBAL object and obtain title and units */
334  if ((dp = db_lookup(dbip, DB5_GLOBAL_OBJECT_NAME, LOOKUP_NOISY)) == RT_DIR_NULL) {
335  bu_log("db_dirbuild(%s): improper database, no %s object\n",
336  dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME);
337  dbip->dbi_title = bu_strdup(DB5_GLOBAL_OBJECT_NAME);
338  /* Missing _GLOBAL object so create it and set default title and units */
339  db5_update_ident(dbip, "Untitled BRL-CAD Database", 1.0);
340  return 0; /* not a fatal error, user may have deleted it */
341  }
342  BU_EXTERNAL_INIT(&ext);
343  if (db_get_external(&ext, dp, dbip) < 0 ||
344  db5_get_raw_internal_ptr(&raw, ext.ext_buf) == NULL) {
345  bu_log("db_dirbuild(%s): improper database, unable to read %s object\n",
346  dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME);
347  return -1;
348  }
349  if (raw.major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY) {
350  bu_log("db_dirbuild(%s): improper database, %s exists but is not an attribute-only object\n",
351  dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME);
352  dbip->dbi_title = bu_strdup(DB5_GLOBAL_OBJECT_NAME);
353  return 0; /* not a fatal error, need to let user proceed to fix it */
354  }
355 
356  /* Parse out the attributes */
357 
358  if (db5_import_attributes(&avs, &raw.attributes) < 0) {
359  bu_log("db_dirbuild(%s): improper database, corrupted attribute-only %s object\n",
360  dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME);
361  bu_free_external(&ext);
362  return -1; /* this is fatal */
363  }
364  BU_CK_AVS(&avs);
365 
366  /* 1/3: title */
367  if ((cp = bu_avs_get(&avs, "title")) != NULL) {
368  dbip->dbi_title = bu_strdup(cp);
369  } else {
370  dbip->dbi_title = bu_strdup("Untitled BRL-CAD database");
371  }
372 
373  /* 2/3: units */
374  if ((cp = bu_avs_get(&avs, "units")) != NULL) {
375  double dd;
376  if (sscanf(cp, "%lf", &dd) != 1 || NEAR_ZERO(dd, VUNITIZE_TOL)) {
377  bu_log("db_dirbuild(%s): improper database, %s object attribute 'units'=%s is invalid\n",
378  dbip->dbi_filename, DB5_GLOBAL_OBJECT_NAME, cp);
379  /* Not fatal, just stick with default value from db_open() */
380  } else {
381  dbip->dbi_local2base = dd;
382  dbip->dbi_base2local = 1/dd;
383  }
384  }
385 
386  /* 3/3: color table */
387  if ((cp = bu_avs_get(&avs, "regionid_colortable")) != NULL) {
388  /* Import the region-id coloring table */
389  db5_import_color_table((char *)cp);
390  }
391  bu_avs_free(&avs);
392  bu_free_external(&ext); /* not until after done with avs! */
393 
394  return 0; /* ok */
395 
396  } else if (version == 4) {
397  /* things used to be pretty simple with v4 */
398 
399  if (db_scan(dbip, (int (*)(struct db_i *, const char *, off_t, size_t, int, void *))db_diradd, 1, NULL) < 0) {
400  return -1;
401  }
402 
403  return 0; /* ok */
404  }
405 
406  bu_log("ERROR: Cannot build object directory.\n\tFile '%s' does not seem to be in BRL-CAD geometry database format.\n",
407  dbip->dbi_filename);
408 
409  return -1;
410 }
411 
412 
413 int
414 db_version(struct db_i *dbip)
415 {
416  unsigned char header[8];
417 
418  if (!dbip) {
419  return -1;
420  }
421 
422  RT_CK_DBI(dbip);
423 
424  /* already calculated during db_open? */
425  if (dbip->dbi_version != 0)
426  return abs(dbip->dbi_version);
427 
428  if (!dbip->dbi_fp) {
429  return -1;
430  }
431 
432  rewind(dbip->dbi_fp);
433  if (fread(header, sizeof(header), 1, dbip->dbi_fp) != 1) {
434  bu_log("ERROR: file (%s) too short to be a BRL-CAD database\n", dbip->dbi_filename ? dbip->dbi_filename : "unknown");
435  return -1;
436  }
437 
438  if (db5_header_is_valid(header)) {
439  return 5;
440  } else if (header[0] == 'I') {
441  return 4;
442  }
443 
444  return -1;
445 }
446 
447 
448 /*
449  * Local Variables:
450  * mode: C
451  * tab-width: 8
452  * indent-tabs-mode: t
453  * c-file-style: "stroustrup"
454  * End:
455  * ex: shiftwidth=4 tabstop=8
456  */
Definition: vfont.h:53
Definition: raytrace.h:800
unsigned char d_major_type
object major type
Definition: raytrace.h:870
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int db_dircheck(struct db_i *dbip, struct bu_vls *ret_name, int noisy, struct directory ***headp)
Definition: db_lookup.c:105
#define RT_GET_DIRECTORY(_p, _res)
Definition: raytrace.h:924
#define RT_DIR_SET_NAMEP(_dp, _name)
Definition: raytrace.h:901
void bu_avs_init_empty(struct bu_attribute_value_set *avp)
Definition: avs.c:36
off_t bu_ftell(FILE *stream)
Definition: file.c:344
size_t d_len
of db granules used
Definition: raytrace.h:867
long d_nref
times ref'ed by COMBs
Definition: raytrace.h:868
Definition: clone.c:90
const unsigned char * db5_get_raw_internal_ptr(struct db5_raw_internal *rip, const unsigned char *ip)
Definition: db5_io.c:245
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
long d_uses
uses, from instancing
Definition: raytrace.h:866
#define BU_ASSERT_LONG(_lhs, _relation, _rhs)
Definition: defines.h:240
int db_version(struct db_i *dbip)
Definition: db5_scan.c:414
void bu_free_external(struct bu_external *ep)
Header file for the BRL-CAD common definitions.
#define RT_DIR_REGION
region
Definition: raytrace.h:885
#define ID_COMBINATION
Combination Record.
Definition: raytrace.h:499
struct directory * d_forw
link to next dir entry
Definition: raytrace.h:864
#define HIDDEN
Definition: common.h:86
#define DB5_RAW_INTERNAL_MAGIC
Definition: magic.h:201
struct bu_mapped_file * dbi_mf
PRIVATE: Only in read-only mode.
Definition: raytrace.h:822
HIDDEN void db5_diradd_handler(struct db_i *dbip, const struct db5_raw_internal *rip, off_t laddr, void *client_data)
Definition: db5_scan.c:272
const char * bu_avs_get(const struct bu_attribute_value_set *avp, const char *attribute)
Definition: avs.c:172
void rt_init_resource(struct resource *resp, int cpu_num, struct rt_i *rtip)
Definition: prep.c:585
if(share_geom)
Definition: nmg_mod.c:3829
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
unsigned char d_minor_type
object minor type
Definition: raytrace.h:871
uint32_t re_magic
Magic number.
Definition: raytrace.h:1441
size_t dbi_nrec
PRIVATE: # records after db_scan()
Definition: raytrace.h:817
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define RT_G_DEBUG
Definition: raytrace.h:1718
char * dbi_title
title from IDENT rec
Definition: raytrace.h:809
#define RT_DIR_NON_GEOM
object is not geometry (e.g. binary object)
Definition: raytrace.h:887
int db_get_external(struct bu_external *ep, const struct directory *dp, const struct db_i *dbip)
#define RT_CK_DIR(_dp)
Definition: raytrace.h:876
#define RT_DIR_SOLID
this name is a solid
Definition: raytrace.h:883
off_t dbi_eof
PRIVATE: End+1 pos after db_scan()
Definition: raytrace.h:816
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
uint8_t * ext_buf
Definition: parse.h:216
#define BU_CK_MAPPED_FILE(_mf)
Definition: mapped_file.h:101
void * dbi_inmem
PRIVATE: ptr to in-memory copy.
Definition: raytrace.h:820
#define RT_DIR_HIDDEN
object name is hidden
Definition: raytrace.h:886
struct directory * db_diradd5(struct db_i *dbip, const char *name, off_t laddr, unsigned char major_type, unsigned char minor_type, unsigned char name_hidden, size_t object_length, struct bu_attribute_value_set *avs)
Definition: db5_scan.c:115
struct mem_map * dbi_freep
PRIVATE: map of free granules.
Definition: raytrace.h:819
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
FILE * dbi_fp
PRIVATE: object hash table.
Definition: raytrace.h:815
struct bu_list d_use_hd
heads list of uses (struct soltab l2)
Definition: raytrace.h:872
double dbi_base2local
unit conversion factors
Definition: raytrace.h:808
int db5_import_attributes(struct bu_attribute_value_set *avs, const struct bu_external *ap)
Definition: attributes.c:30
void db5_import_color_table(char *cp)
Definition: db5_io.c:996
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
int dbi_read_only
!0 => read only file
Definition: raytrace.h:806
union directory::@8 d_un
struct directory * db_diradd(struct db_i *, const char *name, off_t laddr, size_t len, int flags, void *ptr)
Definition: db_lookup.c:190
#define BU_LIST_INIT(_hp)
Definition: list.h:148
#define RT_DIR_COMB
combination
Definition: raytrace.h:884
#define DEBUG_DB
5 Database debugging
Definition: raytrace.h:88
struct directory * db5_diradd(struct db_i *dbip, const struct db5_raw_internal *rip, off_t laddr, void *client_data)
Definition: db5_scan.c:188
#define RT_DIR_NULL
Definition: raytrace.h:875
#define LOOKUP_NOISY
Definition: raytrace.h:892
#define BU_EXTERNAL_INIT(_p)
Definition: parse.h:229
void * ptr
ptr to in-memory-only obj
Definition: raytrace.h:862
int db_scan(struct db_i *, int(*handler)(struct db_i *, const char *name, off_t addr, size_t nrec, int flags, void *client_data), int do_old_matter, void *client_data)
struct animate * d_animate
link to animation
Definition: raytrace.h:865
int dbi_version
PRIVATE: use db_version()
Definition: raytrace.h:824
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
int db5_get_raw_internal_fp(struct db5_raw_internal *rip, FILE *fp)
Definition: db5_io.c:305
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
double dbi_local2base
local2mm
Definition: raytrace.h:807
int db_dirbuild(struct db_i *dbip)
Definition: db5_scan.c:301
void rt_memfree(struct mem_map **pp, size_t size, off_t addr)
Definition: memalloc.c:228
int db5_update_ident(struct db_i *dbip, const char *title, double local2mm)
Definition: attributes.c:381
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int db5_header_is_valid(const unsigned char *hp)
Definition: db5_io.c:46
int d_flags
flags
Definition: raytrace.h:869
Definition: vls.h:56
char * dbi_filename
file name
Definition: raytrace.h:805
#define BU_CK_AVS(_ap)
Definition: avs.h:97
int db5_scan(struct db_i *dbip, void(*handler)(struct db_i *, const struct db5_raw_internal *, off_t addr, void *client_data), void *client_data)
Definition: db5_scan.c:36
void bu_avs_free(struct bu_attribute_value_set *avp)
Definition: avs.c:235
#define bu_strdup(s)
Definition: str.h:71