/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1994, by Sun Microsytems, Inc. */ #pragma ident "%Z%%M% %I% %E% SMI" #include "libtnf.h" #define TAG_INDEX(x) (TNF_TAG16_ABS16(x) / sizeof (tnf_ref32_t)) /* * */ static struct taginfo * add_info(TNF *, tnf_ref32_t *); static struct taginfo * init_abstract_info(TNF *, tnf_ref32_t *, struct taginfo *); static struct taginfo * init_derived_info(TNF *, tnf_ref32_t *, struct taginfo *); static struct taginfo * init_scalar_info(TNF *, tnf_ref32_t *, struct taginfo *); static struct taginfo * init_struct_info(TNF *, tnf_ref32_t *, struct taginfo *); static struct taginfo * init_array_info(TNF *, tnf_ref32_t *, struct taginfo *); static void init_slots(TNF *, tnf_ref32_t *, struct taginfo *); /* * Allocate tag table and directory */ tnf_errcode_t _tnf_init_tags(TNF *tnf) { if ((tnf->tag_table = calloc(TAGTABCNT, sizeof (struct taginfo *))) == NULL) return (TNF_ERR_ALLOCFAIL); if ((tnf->tag_directory = calloc(TAGDIRCNT(tnf->directory_size), sizeof (struct taginfo *))) == NULL) return (TNF_ERR_ALLOCFAIL); return (TNF_ERR_NONE); } /* * Deallocate all taginfos and tables associated with TNF handle */ tnf_errcode_t _tnf_fini_tags(TNF *tnf) { int i; struct taginfo *info, *link; /* * free taginfos */ for (i = 0; i < TAGTABCNT; i++) { info = tnf->tag_table[i]; while (info) { /* remember link */ link = info->link; /* free slot information */ if (info->slotinfo) free(info->slotinfo); /* free taginfo */ free(info); /* next in hash chain */ info = link; } } /* * free the tables */ free(tnf->tag_table); tnf->tag_table = NULL; free(tnf->tag_directory); tnf->tag_directory = NULL; return (TNF_ERR_NONE); } /* * Get info for supplied tag */ struct taginfo * _tnf_get_info(TNF *tnf, tnf_ref32_t *tag) { struct taginfo *bucket, *info; bucket = tnf->tag_table[TAGHASH(tnf, tag)]; for (info = bucket; info; info = info->link) if (info->tag == tag) return (info); /* found it */ /* default: not there, create */ return (add_info(tnf, tag)); } /* * Get info for supplied record * Use fast lookup, if possible */ struct taginfo * _tnf_record_info(TNF *tnf, tnf_ref32_t *record) { tnf_ref32_t ref32; tnf_ref16_t tag16; tnf_abs16_t index; struct taginfo *info; ref32 = _GET_INT32(tnf, record); index = 0; if (TNF_REF32_IS_PAIR(ref32)) { tag16 = TNF_REF32_TAG16(ref32); if (TNF_TAG16_IS_ABS(tag16)) index = TAG_INDEX(tag16); } if (index) { if ((info = tnf->tag_directory[index]) != NULL) return (info); else { /* not in directory yet */ info = _tnf_get_info(tnf, _tnf_get_tag(tnf, record)); /* enter into tag directory */ return ((tnf->tag_directory[index] = info)); } } /* default: not referenced via index */ return (_tnf_get_info(tnf, _tnf_get_tag(tnf, record))); } /* * Add a new taginfo for tag */ static struct taginfo * add_info(TNF *tnf, tnf_ref32_t *tag) { struct taginfo *info, *bucket; unsigned hash; tnf_ref32_t *meta; info = (struct taginfo *)calloc(1, sizeof (struct taginfo)); /* Initialize members */ info->tnf = tnf; info->tag = tag; info->name = _tnf_get_name(tnf, tag); info->props = _tnf_get_props(tnf, tag); info->kind = _tnf_get_kind(tnf, tag); info->size = _tnf_get_storage_size(tnf, tag); info->align = _tnf_get_align(tnf, tag); /* Add it to table */ hash = TAGHASH(tnf, tag); bucket = tnf->tag_table[hash]; info->link = bucket; tnf->tag_table[hash] = info; /* Ensure meta info is available */ meta = _tnf_get_tag(tnf, tag); info->meta = _tnf_get_info(tnf, meta); /* * Initialize info * Derived must be first clause due to property inheritance */ if (INFO_DERIVED(info)) return (init_derived_info(tnf, tag, info)); else if (INFO_STRUCT(info)) return (init_struct_info(tnf, tag, info)); else if (INFO_ARRAY(info)) return (init_array_info(tnf, tag, info)); else if (INFO_SCALAR(info)) return (init_scalar_info(tnf, tag, info)); else /* XXX assume abstract type */ return (init_abstract_info(tnf, tag, info)); } /* * Initialize info for an abstract tag */ static struct taginfo * /* ARGSUSED */ init_abstract_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) { if (INFO_SCALAR(info) || INFO_DERIVED(info) || INFO_STRUCT(info) || INFO_ARRAY(info)) _tnf_error(tnf, TNF_ERR_INTERNAL); if (info->size == (size_t)-1) _tnf_error(tnf, TNF_ERR_BADTNF); return (info); } /* * Initialize info for a derived tag */ static struct taginfo * init_derived_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) { tnf_ref32_t *base_tag; if (!INFO_DERIVED(info)) _tnf_error(tnf, TNF_ERR_INTERNAL); /* Ensure ultimate base information is available */ base_tag = _tnf_get_base_tag(tnf, tag); info->base = _tnf_get_info(tnf, base_tag); return (info); } /* * Initialize info for a scalar tag */ static struct taginfo * /* ARGSUSED */ init_scalar_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) { if ((!INFO_SCALAR(info)) || (INFO_DERIVED(info) || INFO_ARRAY(info) || INFO_STRUCT(info))) _tnf_error(tnf, TNF_ERR_INTERNAL); if (info->size == (size_t)-1) _tnf_error(tnf, TNF_ERR_BADTNF); /* XXX alignment already done */ return (info); } /* * Initialize info for a struct tag */ static struct taginfo * init_struct_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) { if ((!INFO_STRUCT(info)) || (INFO_DERIVED(info) || INFO_ARRAY(info) || INFO_SCALAR(info))) _tnf_error(tnf, TNF_ERR_INTERNAL); if (info->size == (size_t)-1) _tnf_error(tnf, TNF_ERR_BADTNF); /* Get slot information */ init_slots(tnf, tag, info); return (info); } /* * Initialize info for an array tag */ static struct taginfo * init_array_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) { tnf_ref32_t *elt_tag; int defeat; if ((!INFO_ARRAY(info)) || (INFO_DERIVED(info) || INFO_STRUCT(info) || INFO_SCALAR(info))) _tnf_error(tnf, TNF_ERR_INTERNAL); /* XXX special-case abstract array tag */ defeat = (strcmp(info->name, TNF_N_ARRAY) == 0); /* Require all arrays to be self-sized records */ if (!(INFO_TAGGED(info) && (info->size == (size_t)-1))) if (!defeat) _tnf_error(tnf, TNF_ERR_BADTNF); /* Store array header size */ info->hdrsize = _tnf_get_header_size(tnf, tag); /* XXX Temporary sanity check */ if (info->hdrsize != sizeof (struct tnf_array_hdr)) if (!defeat) _tnf_error(tnf, TNF_ERR_BADTNF); /* Get slot information */ init_slots(tnf, tag, info); /* Get info for element type */ elt_tag = (tnf_ref32_t *)_tnf_get_slot_typed(tnf, tag, /* LINTED pointer cast may result in improper alignment */ TNF_N_ELEMENT_TYPE); /* XXX tnf_array has element_type == NULL */ info->base = elt_tag ? _tnf_get_info(tnf, elt_tag): NULL; return (info); } /* * Initialize slot information for aggregate tag */ static void init_slots(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) { tnf_ref32_t *slot_types, *slot_names; tnf_ref32_t *types, *names; unsigned count, i, offset; struct slotinfo *slotinfo; slot_types = (tnf_ref32_t *) /* LINTED pointer cast may result in improper alignment */ _tnf_get_slot_typed(tnf, tag, TNF_N_SLOT_TYPES); slot_names = (tnf_ref32_t *) /* LINTED pointer cast may result in improper alignment */ _tnf_get_slot_typed(tnf, tag, TNF_N_SLOT_NAMES); /* abstract tags have no slots */ if (slot_types == TNF_NULL) return; count = _tnf_get_element_count(tnf, slot_types, sizeof (tnf_ref32_t)); /* LINTED pointer cast may result in improper alignment */ types = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_types); names = ((slot_names == TNF_NULL) ? TNF_NULL : /* LINTED pointer cast may result in improper alignment */ (tnf_ref32_t *)_tnf_get_elements(tnf, slot_names)); slotinfo = (struct slotinfo *) calloc(1, sizeof (unsigned) + (count * sizeof (struct slot))); if (slotinfo == (struct slotinfo *)NULL) _tnf_error(tnf, TNF_ERR_ALLOCFAIL); slotinfo->slot_count = count; offset = 0; for (i = 0; i < count; i++) { tnf_ref32_t *type_elt, *name_elt; struct taginfo *elt_info; size_t ref_size, align; /* XXX No checks here for missing tags */ type_elt = _GET_REF32(tnf, &types[i]); name_elt = names ? _GET_REF32(tnf, &names[i]) : TNF_NULL; /* Resolve slot tag into taginfo */ elt_info = _tnf_get_info(tnf, type_elt); slotinfo->slots[i].slot_type = elt_info; slotinfo->slots[i].slot_name = ((name_elt != TNF_NULL) ? _tnf_get_chars(tnf, name_elt) : _tnf_get_name(tnf, type_elt)); /* Get cached reference size */ ref_size = INFO_REF_SIZE(elt_info); /* Get cached alignment */ align = INFO_ALIGN(elt_info); /* XXX */ /* Adjust offset to account for alignment, if needed */ offset = ALIGN(offset, align); slotinfo->slots[i].slot_offset = offset; /* Bump offset by reference size */ offset += ref_size; } info->slotinfo = slotinfo; }