BRL-CAD
attributes.c
Go to the documentation of this file.
1 /* A T T R I B U T E S . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2010-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 <string.h>
24 
25 #include "bu/debug.h"
26 #include "raytrace.h"
27 
28 
29 int
31 {
32  const char *cp;
33  const char *ep;
34  int count = 0;
35 #if defined(USE_BINARY_ATTRIBUTES)
36  int bcount = 0; /* for the subset of binary attributes */
37 #endif
38 
39  BU_CK_EXTERNAL(ap);
40 
41  BU_ASSERT_LONG(ap->ext_nbytes, >=, 4);
42 
43  /* First pass -- count number of attributes */
44  cp = (const char *)ap->ext_buf;
45  ep = (const char *)ap->ext_buf+ap->ext_nbytes;
46 
47  /* An empty "name" string (a pair of nul bytes) indicates end of
48  * attribute list (for the original ASCII-valued attributes).
49  */
50  while (*cp != '\0') {
51  if (cp >= ep) {
52  bu_log("db5_import_attributes() ran off end of buffer, database is probably corrupted\n");
53  return -1;
54  }
55  cp += strlen(cp)+1; /* value */
56  cp += strlen(cp)+1; /* next name */
57  count++;
58  }
59 #if defined(USE_BINARY_ATTRIBUTES)
60  /* Do we have binary attributes? If so, they are after the last
61  * ASCII attribute. */
62  if (ep > (cp+1)) {
63  /* Count binary attrs. */
64  /* format is: <ascii name> NULL <binary length [network order, must be decoded]> <bytes...> */
65  size_t abinlen;
66  cp += 2; /* We are now at the first byte of the first binary attribute... */
67  while (cp != ep) {
68  ++bcount
69  cp += strlen(cp)+1; /* name */
70  /* The next value is an unsigned integer of variable width
71  * (a_width: DB5HDR_WIDTHCODE_x) so how do we get its
72  * width? We now have a new member of struct bu_external:
73  * 'unsigned char intwid'. Note that the integer
74  * is in network order and must be properly decoded for
75  * the local architecture.
76  */
77  cp += db5_decode_length(&abinlen, cp, ap->intwid);
78  /* account for the abinlen bytes */
79  cp += abinlen;
80  }
81  /* now cp should be at the end */
82  count += bcount;
83  } else {
84  /* step to the end for the sanity check */
85  ++cp;
86  }
87  /* Ensure we're exactly at the end */
88  BU_ASSERT_PTR(cp, ==, ep);
89 #else
90  /* Ensure we're exactly at the end */
91  BU_ASSERT_PTR(cp+1, ==, ep);
92 #endif
93 
94  /* not really needed for AVS_ADD since bu_avs_add will
95  * incrementally allocate as it needs it. but one alloc is better
96  * than many in case there are many attributes.
97  */
98  bu_avs_init(avs, count, "db5_import_attributes");
99 
100  /* Second pass -- populate attributes. */
101 
102  /* Copy the values from the external buffer instead of using them
103  * directly without copying. This presumes ap will not get free'd
104  * before we're done with the avs.
105  */
106 
107  cp = (const char *)ap->ext_buf;
108  while (*cp != '\0') {
109  const char *name = cp; /* name */
110  cp += strlen(cp)+1; /* value */
111  bu_avs_add(avs, name, cp);
112  cp += strlen(cp)+1; /* next name */
113  }
114 #if defined(USE_BINARY_ATTRIBUTES)
115  /* Do we have binary attributes? If so, they are after the last
116  * ASCII attribute. */
117  if (ep > (cp+1)) {
118  /* Count binary attrs. */
119  /* format is: <ascii name> NULL <binary length [network order, must be decoded]> <bytes...> */
120  size_t abinlen;
121  cp += 2; /* We are now at the first byte of the first binary attribute... */
122  while (cp != ep) {
123  const char *name = cp; /* name */
124  cp += strlen(cp)+1; /* name */
125  cp += db5_decode_length(&abinlen, cp, ap->intwid);
126  /* now decode for the abinlen bytes */
127  decode_binary_attribute(const size_t len, const char *cp)
128  decod
129  cp += abinlen;
130  }
131  /* now cp should be at the end */
132  } else {
133  /* step to the end for the sanity check */
134  ++cp;
135  }
136  /* Ensure we're exactly at the end */
137  BU_ASSERT_PTR(cp, ==, ep);
138 #else
139  BU_ASSERT_PTR(cp+1, ==, ep);
140 #endif
141 
142  BU_ASSERT_LONG(avs->count, <=, avs->max);
143  BU_ASSERT_LONG((size_t)avs->count, ==, (size_t)count);
144 
145  if (bu_debug & BU_DEBUG_AVS) {
146  bu_avs_print(avs, "db5_import_attributes");
147  }
148  return avs->count;
149 }
150 
151 
152 void
154 {
155  size_t need = 0;
156  const struct bu_attribute_value_pair *avpp;
157  char *cp;
158  size_t i;
159  size_t len;
160 
161  BU_CK_AVS(avs);
162  BU_EXTERNAL_INIT(ext);
163 
164  if (avs->count <= 0) {
165  return;
166  }
167 
168  if (bu_debug & BU_DEBUG_AVS) {
169  bu_avs_print(avs, "db5_export_attributes");
170  }
171 
172  /* First pass -- determine how much space is required */
173  need = 0;
174  avpp = avs->avp;
175  for (i = 0; i < avs->count; i++, avpp++) {
176  if (avpp->name) {
177  need += strlen(avpp->name);
178  }
179  need += 1; /* include room for nul byte */
180  if (avpp->value) {
181  need += strlen(avpp->value);
182  }
183  need += 1; /* include room for nul byte */
184  }
185  /* include a final nul byte */
186  need += 1;
187 
188  if (need <= 1) {
189  /* nothing to do */
190  return;
191  }
192 
193  ext->ext_nbytes = need;
194  ext->ext_buf = (uint8_t*)bu_calloc(1, need, "external attributes");
195 
196  /* Second pass -- store in external form */
197  cp = (char *)ext->ext_buf;
198  avpp = avs->avp;
199  for (i = 0; i < avs->count; i++, avpp++) {
200  if (avpp->name) {
201  len = strlen(avpp->name);
202  memcpy(cp, avpp->name, len);
203  cp += len;
204  }
205  *(cp++) = '\0'; /* pad nul byte */
206 
207  if (avpp->value) {
208  len = strlen(avpp->value);
209  memcpy(cp, avpp->value, strlen(avpp->value));
210  cp += len;
211  }
212  *(cp++) = '\0'; /* pad nul byte */
213  }
214  *(cp++) = '\0'; /* final nul byte */
215 
216  /* sanity check */
217  need = cp - ((char *)ext->ext_buf);
218  BU_ASSERT_LONG(need, ==, ext->ext_nbytes);
219 }
220 
221 
222 int
223 db5_replace_attributes(struct directory *dp, struct bu_attribute_value_set *avsp, struct db_i *dbip)
224 {
225  struct bu_external ext;
226  struct db5_raw_internal raw;
227  struct bu_external attr;
228  struct bu_external ext2;
229  int ret;
230 
231  RT_CK_DIR(dp);
232  BU_CK_AVS(avsp);
233  RT_CK_DBI(dbip);
234 
235  if (RT_G_DEBUG&DEBUG_DB) {
236  bu_log("db5_replace_attributes(%s) dbip=%p\n",
237  dp->d_namep, (void *)dbip);
238  bu_avs_print(avsp, "new attributes");
239  }
240 
241  if (dbip->dbi_read_only) {
242  bu_log("db5_replace_attributes(%s): READ-ONLY file\n",
243  dbip->dbi_filename);
244  return -1;
245  }
246 
247  BU_ASSERT_LONG(dbip->dbi_version, ==, 5);
248 
249  if (db_get_external(&ext, dp, dbip) < 0)
250  return -2; /* FAIL */
251 
252  if (db5_get_raw_internal_ptr(&raw, ext.ext_buf) == NULL) {
253  bu_log("db5_replace_attributes(%s): import failure\n",
254  dp->d_namep);
255  bu_free_external(&ext);
256  return -3;
257  }
258 
259  db5_export_attributes(&attr, avsp);
260  BU_EXTERNAL_INIT(&ext2);
261  db5_export_object3(&ext2,
262  raw.h_dli,
263  dp->d_namep,
264  raw.h_name_hidden,
265  &attr,
266  &raw.body,
267  raw.major_type, raw.minor_type,
268  raw.a_zzz, raw.b_zzz);
269 
270  /* Write it */
271  ret = db_put_external5(&ext2, dp, dbip);
272  if (ret < 0) bu_log("db5_replace_attributes(%s): db_put_external5() failure\n",
273  dp->d_namep);
274 
275  bu_free_external(&attr);
276  bu_free_external(&ext2);
277  bu_free_external(&ext); /* 'raw' is now invalid */
278  bu_avs_free(avsp);
279 
280  return ret;
281 }
282 
283 
284 int
285 db5_update_attributes(struct directory *dp, struct bu_attribute_value_set *avsp, struct db_i *dbip)
286 {
287  struct bu_external ext;
288  struct db5_raw_internal raw;
289  struct bu_attribute_value_set old_avs;
290  struct bu_external attr;
291  struct bu_external ext2;
292  int ret;
293 
294  RT_CK_DIR(dp);
295  BU_CK_AVS(avsp);
296  RT_CK_DBI(dbip);
297 
298  if (RT_G_DEBUG&DEBUG_DB) {
299  bu_log("db5_update_attributes(%s) dbip=%p\n",
300  dp->d_namep, (void *)dbip);
301  bu_avs_print(avsp, "new attributes");
302  }
303 
304  if (dbip->dbi_read_only) {
305  bu_log("db5_update_attributes(%s): READ-ONLY file\n",
306  dbip->dbi_filename);
307  return -1;
308  }
309 
310  BU_ASSERT_LONG(dbip->dbi_version, ==, 5);
311 
312  if (db_get_external(&ext, dp, dbip) < 0)
313  return -2; /* FAIL */
314 
315  if (db5_get_raw_internal_ptr(&raw, ext.ext_buf) == NULL) {
316  bu_log("db5_update_attributes(%s): import failure\n",
317  dp->d_namep);
318  bu_free_external(&ext);
319  return -3;
320  }
321 
322  /* db5_import_attributes will allocate space */
323  bu_avs_init_empty(&old_avs);
324 
325  if (raw.attributes.ext_buf) {
326  if (db5_import_attributes(&old_avs, &raw.attributes) < 0) {
327  bu_log("db5_update_attributes(%s): mal-formed attributes in database\n",
328  dp->d_namep);
329  bu_avs_free(&old_avs);
330  bu_free_external(&ext);
331  return -8;
332  }
333  }
334 
335  bu_avs_merge(&old_avs, avsp);
336 
337  db5_export_attributes(&attr, &old_avs);
338  BU_EXTERNAL_INIT(&ext2);
339  db5_export_object3(&ext2,
340  raw.h_dli,
341  dp->d_namep,
342  raw.h_name_hidden,
343  &attr,
344  &raw.body,
345  raw.major_type, raw.minor_type,
346  raw.a_zzz, raw.b_zzz);
347 
348  /* Write it */
349  ret = db_put_external5(&ext2, dp, dbip);
350  if (ret < 0) {
351  bu_log("db5_update_attributes(%s): db_put_external5() failure\n", dp->d_namep);
352  }
353 
354  bu_free_external(&attr);
355  bu_free_external(&ext2);
356  bu_free_external(&ext); /* 'raw' is now invalid */
357  bu_avs_free(&old_avs);
358  bu_avs_free(avsp);
359 
360  return ret;
361 }
362 
363 
364 int
365 db5_update_attribute(const char *obj_name, const char *name, const char *value, struct db_i *dbip)
366 {
367  struct directory *dp;
368  struct bu_attribute_value_set avs;
369 
370  RT_CK_DBI(dbip);
371  if ((dp = db_lookup(dbip, obj_name, LOOKUP_NOISY)) == RT_DIR_NULL)
372  return -1;
373 
374  bu_avs_init(&avs, 2, "db5_update_attribute");
375  bu_avs_add(&avs, name, value);
376 
377  return db5_update_attributes(dp, &avs, dbip);
378 }
379 
380 
381 int db5_update_ident(struct db_i *dbip, const char *title, double local2mm)
382 {
383  struct bu_attribute_value_set avs;
384  struct directory *dp;
385  struct bu_vls units = BU_VLS_INIT_ZERO;
386  int ret;
387  char *old_title = NULL;
388 
389  RT_CK_DBI(dbip);
390 
391  if ((dp = db_lookup(dbip, DB5_GLOBAL_OBJECT_NAME, LOOKUP_QUIET)) == RT_DIR_NULL) {
392  struct bu_external global;
393  unsigned char minor_type=0;
394 
395  bu_log("db5_update_ident() WARNING: %s object is missing, creating new one.\nYou may have lost important global state when you deleted this object.\n",
396  DB5_GLOBAL_OBJECT_NAME);
397 
398  /* OK, make one. It will be empty to start with, updated below. */
399  db5_export_object3(&global,
400  DB5HDR_HFLAGS_DLI_APPLICATION_DATA_OBJECT,
401  DB5_GLOBAL_OBJECT_NAME, DB5HDR_HFLAGS_HIDDEN_OBJECT, NULL, NULL,
402  DB5_MAJORTYPE_ATTRIBUTE_ONLY, 0,
403  DB5_ZZZ_UNCOMPRESSED, DB5_ZZZ_UNCOMPRESSED);
404 
405  dp = db_diradd(dbip, DB5_GLOBAL_OBJECT_NAME, RT_DIR_PHONY_ADDR, 0, 0, (void *)&minor_type);
406  dp->d_major_type = DB5_MAJORTYPE_ATTRIBUTE_ONLY;
407  if (db_put_external(&global, dp, dbip) < 0) {
408  bu_log("db5_update_ident() unable to create replacement %s object!\n", DB5_GLOBAL_OBJECT_NAME);
409  bu_free_external(&global);
410  return -1;
411  }
412  bu_free_external(&global);
413  }
414 
415  bu_vls_printf(&units, "%.25e", local2mm);
416 
417  bu_avs_init(&avs, 4, "db5_update_ident");
418  bu_avs_add(&avs, "title", title);
419  bu_avs_add(&avs, "units", bu_vls_addr(&units));
420 
421  ret = db5_update_attributes(dp, &avs, dbip);
422  bu_vls_free(&units);
423  bu_avs_free(&avs);
424 
425  /* protect from loosing memory and from freeing what we are
426  about to dup */
427  if (dbip->dbi_title) {
428  old_title = dbip->dbi_title;
429  }
430  dbip->dbi_title = bu_strdup(title);
431  if (old_title) {
432  bu_free(old_title, "replaced dbi_title with new");
433  }
434 
435  return ret;
436 }
437 
438 
439 int
440 db5_fwrite_ident(FILE *fp, const char *title, double local2mm)
441 {
442  struct bu_attribute_value_set avs;
443  struct bu_vls units = BU_VLS_INIT_ZERO;
444  struct bu_external out;
445  struct bu_external attr;
446  int result;
447 
448  if (local2mm <= 0) {
449  bu_log("db5_fwrite_ident(%s, %g) local2mm <= 0\n",
450  title, local2mm);
451  return -1;
452  }
453 
454  /* First, write the header object */
455  db5_export_object3(&out, DB5HDR_HFLAGS_DLI_HEADER_OBJECT,
456  NULL, 0, NULL, NULL,
457  DB5_MAJORTYPE_RESERVED, 0,
458  DB5_ZZZ_UNCOMPRESSED, DB5_ZZZ_UNCOMPRESSED);
459 
460  result = bu_fwrite_external(fp, &out);
461  bu_free_external(&out);
462  if (result < 0) {
463  return -1;
464  }
465 
466  /* Second, create the attribute-only object */
467  bu_vls_printf(&units, "%.25e", local2mm);
468 
469  bu_avs_init(&avs, 4, "db5_fwrite_ident");
470  bu_avs_add(&avs, "title", title);
471  bu_avs_add(&avs, "units", bu_vls_addr(&units));
472 
473  db5_export_attributes(&attr, &avs);
474  db5_export_object3(&out, DB5HDR_HFLAGS_DLI_APPLICATION_DATA_OBJECT,
475  DB5_GLOBAL_OBJECT_NAME, DB5HDR_HFLAGS_HIDDEN_OBJECT, &attr, NULL,
476  DB5_MAJORTYPE_ATTRIBUTE_ONLY, 0,
477  DB5_ZZZ_UNCOMPRESSED, DB5_ZZZ_UNCOMPRESSED);
478 
479  result = bu_fwrite_external(fp, &out);
480  bu_free_external(&out);
481  bu_free_external(&attr);
482  bu_avs_free(&avs);
483  bu_vls_free(&units);
484  if (result < 0) {
485  return -1;
486  }
487 
488  return 0;
489 }
490 
491 
492 #if defined(USE_BINARY_ATTRIBUTES)
493 void
494 decode_binary_attribute(const size_t len, const char *cp)
495 {
496 }
497 #endif
498 
499 /*
500  * Local Variables:
501  * tab-width: 8
502  * mode: C
503  * indent-tabs-mode: t
504  * c-file-style: "stroustrup"
505  * End:
506  * ex: shiftwidth=4 tabstop=8
507  */
char * d_namep
pointer to name string
Definition: raytrace.h:859
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
void bu_avs_init_empty(struct bu_attribute_value_set *avp)
Definition: avs.c:36
int db5_update_attributes(struct directory *dp, struct bu_attribute_value_set *avsp, struct db_i *dbip)
Definition: attributes.c:285
void db5_export_attributes(struct bu_external *ext, const struct bu_attribute_value_set *avs)
Definition: attributes.c:153
Definition: clone.c:90
int bu_avs_add(struct bu_attribute_value_set *avp, const char *attribute, const char *value)
Definition: avs.c:78
void bu_avs_merge(struct bu_attribute_value_set *dest, const struct bu_attribute_value_set *src)
Definition: avs.c:154
int bu_fwrite_external(FILE *fp, const struct bu_external *ep)
Definition: parse.c:2368
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
int db5_fwrite_ident(FILE *fp, const char *title, double local2mm)
Definition: attributes.c:440
#define BU_ASSERT_LONG(_lhs, _relation, _rhs)
Definition: defines.h:240
void bu_free_external(struct bu_external *ep)
Header file for the BRL-CAD common definitions.
const char * value
Definition: avs.h:62
int db_put_external5(struct bu_external *ep, struct directory *dp, struct db_i *dbip)
Definition: db5_io.c:744
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
size_t db5_decode_length(size_t *lenp, const unsigned char *cp, int format)
Definition: db5_io.c:94
#define RT_G_DEBUG
Definition: raytrace.h:1718
char * dbi_title
title from IDENT rec
Definition: raytrace.h:809
struct bu_attribute_value_pair * avp
Definition: avs.h:89
int db_get_external(struct bu_external *ep, const struct directory *dp, const struct db_i *dbip)
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
#define RT_CK_DIR(_dp)
Definition: raytrace.h:876
#define LOOKUP_QUIET
Definition: raytrace.h:893
uint8_t * ext_buf
Definition: parse.h:216
#define RT_DIR_PHONY_ADDR
Special marker for d_addr field.
Definition: raytrace.h:879
int db5_replace_attributes(struct directory *dp, struct bu_attribute_value_set *avsp, struct db_i *dbip)
Definition: attributes.c:223
void bu_avs_init(struct bu_attribute_value_set *avp, size_t len, const char *str)
Definition: avs.c:47
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
int db5_import_attributes(struct bu_attribute_value_set *avs, const struct bu_external *ap)
Definition: attributes.c:30
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
int dbi_read_only
!0 => read only file
Definition: raytrace.h:806
#define BU_DEBUG_AVS
Definition: debug.h:65
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
int bu_debug
Definition: globals.c:87
#define DEBUG_DB
5 Database debugging
Definition: raytrace.h:88
#define BU_ASSERT_PTR(_lhs, _relation, _rhs)
Definition: defines.h:227
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
#define RT_DIR_NULL
Definition: raytrace.h:875
#define LOOKUP_NOISY
Definition: raytrace.h:892
#define BU_EXTERNAL_INIT(_p)
Definition: parse.h:229
int dbi_version
PRIVATE: use db_version()
Definition: raytrace.h:824
const char * name
Definition: avs.h:61
int db_put_external(struct bu_external *ep, struct directory *dp, struct db_i *dbip)
Definition: db_io.c:281
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
void bu_avs_print(const struct bu_attribute_value_set *avp, const char *title)
Definition: avs.c:266
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
void db5_export_object3(struct bu_external *out, int dli, const char *name, const unsigned char hidden, const struct bu_external *attrib, const struct bu_external *body, int major, int minor, int a_zzz, int b_zzz)
Definition: db5_io.c:420
size_t ext_nbytes
Definition: parse.h:210
Definition: vls.h:56
char * dbi_filename
file name
Definition: raytrace.h:805
#define BU_CK_AVS(_ap)
Definition: avs.h:97
void bu_avs_free(struct bu_attribute_value_set *avp)
Definition: avs.c:235
int db5_update_attribute(const char *obj_name, const char *name, const char *value, struct db_i *dbip)
Definition: attributes.c:365
#define bu_strdup(s)
Definition: str.h:71