/*
* Copyright (c) 2002, The Tendra Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Crown Copyright (c) 1997
*
* This TenDRA(r) Computer Program is subject to Copyright
* owned by the United Kingdom Secretary of State for Defence
* acting through the Defence Evaluation and Research Agency
* (DERA). It is made available to Recipients with a
* royalty-free licence for its use, reproduction, transfer
* to other parties and amendment for any purpose not excluding
* product development provided that any such use et cetera
* shall be deemed to be acceptance of the following conditions:-
*
* (1) Its Recipients shall ensure that this Notice is
* reproduced upon any copies or amended versions of it;
*
* (2) Any amended version of it shall be clearly marked to
* show both the nature of and the organisation responsible
* for the relevant amendment or amendments;
*
* (3) Its onward transfer from a recipient to another
* party shall be deemed to be that party's acceptance of
* these conditions;
*
* (4) DERA gives no warranty or assurance as to its
* quality or suitability for any purpose and DERA accepts
* no liability whatsoever in relation to any use to which
* it may be put.
*
* $TenDRA: tendra/src/tools/tld/capsule.c,v 1.14 2005/11/04 13:49:55 stefanf Exp $
*/
/*** capsule.c --- TDF capsule ADT.
*
** Author: Steve Folkes
*
*** Commentary:
*
* This file implements the TDF capsule routines used by the TDF linker.
*
*** Change Log:*/
/****************************************************************************/
#include
#include "capsule.h"
#include "debug.h"
#include "dstring.h"
#include "exception.h"
#include "msgcat.h"
#include "istream.h"
#include "name-key.h"
#include "library.h"
#include "syntax.h"
#include "tdf.h"
#include "unit-entry.h"
#include "solve-cycles.h"
/*--------------------------------------------------------------------------*/
typedef struct UnitSetListEntryT {
struct UnitSetListEntryT *next;
NStringT name;
} UnitSetListEntryT, *UnitSetListEntryP;
typedef struct UnitSetT {
NStringT name;
UnitEntryP entry;
} UnitSetT, *UnitSetP;
typedef struct ShapeDataT {
ShapeEntryP entry;
unsigned num_ids;
unsigned *id_maps;
} ShapeDataT, *ShapeDataP;
typedef struct NameDataT {
NameEntryP *names_vec;
unsigned num_names;
} NameDataT, *NameDataP;
/*--------------------------------------------------------------------------*/
#define NUM_DEFAULT_UNIT_SETS (12)
/*--------------------------------------------------------------------------*/
static char *capsule_default_unit_set_names [NUM_DEFAULT_UNIT_SETS] = {
"tld",
"tld2",
"versions",
"tokdec",
"tokdef",
"aldef",
"diagtype",
"tagdec",
"diagdef",
"dgcompunit",
"tagdef",
"linkinfo"
};
static UnitSetT capsule_default_unit_sets [NUM_DEFAULT_UNIT_SETS];
static unsigned capsule_num_unit_sets;
static UnitSetP capsule_unit_sets = NIL (UnitSetP);
static unsigned capsule_tld_index = 0;
static unsigned capsule_tld2_index = 1;
static unsigned capsule_unit_length;
static unsigned capsule_unit_offset;
static ExceptionP XX_capsule_error = EXCEPTION ("error in TDF capsule");
static unsigned capsule_major_version = 0;
static unsigned capsule_minor_version = 0;
/*--------------------------------------------------------------------------*/
static void
capsule_setup_defaults(void)
{
if (capsule_unit_sets == NIL (UnitSetP)) {
unsigned i;
for (i = 0; i < NUM_DEFAULT_UNIT_SETS; i ++) {
nstring_copy_cstring (&(capsule_default_unit_sets [i].name),
capsule_default_unit_set_names [i]);
}
capsule_num_unit_sets = NUM_DEFAULT_UNIT_SETS;
capsule_unit_sets = capsule_default_unit_sets;
}
}
static void
capsule_setup(UnitTableP units)
{
static BoolT need_setup = TRUE;
if (need_setup) {
unsigned i;
capsule_setup_defaults ();
for (i = 0; i < capsule_num_unit_sets; i ++) {
NStringP name = &(capsule_unit_sets [i].name);
UnitEntryP entry;
entry = unit_table_add (units, name, i);
capsule_unit_sets [i].entry = entry;
debug_info_u_name (name);
}
need_setup = FALSE;
}
}
static BoolT
capsule_read_unit_set_name(IStreamP istream, DStringP dstring)
{
char c;
do {
if (!istream_read_char (istream, &c)) {
return (FALSE);
}
} while (syntax_is_white_space (c));
if (c != '"') {
MSG_unit_set_expected_quote (istream);
UNREACHED;
}
dstring_init (dstring);
while (istream_read_char (istream, &c)) {
if (c == '"') {
return (TRUE);
} else if (c == '\\') {
switch (istream_read_escaped_char (istream, &c)) EXHAUSTIVE {
case ISTREAM_STAT_READ_CHAR:
dstring_append_char (dstring, c);
break;
case ISTREAM_STAT_NO_CHAR:
break;
case ISTREAM_STAT_SYNTAX_ERROR:
MSG_unit_set_illegal_escape (istream);
UNREACHED;
}
} else {
dstring_append_char (dstring, c);
}
}
MSG_unit_set_eof_in_name (istream);
UNREACHED;
}
static void
capsule_check_unit_sets(IStreamP istream)
{
static BoolT inited = FALSE;
static NStringT tld;
static NStringT tld2;
BoolT tld_found = FALSE;
unsigned i;
if (!inited) {
nstring_copy_cstring (&tld, "tld");
nstring_copy_cstring (&tld2, "tld2");
inited = TRUE;
}
capsule_tld_index = UINT_MAX;
capsule_tld2_index = UINT_MAX;
for (i = 0; i < capsule_num_unit_sets; i ++) {
NStringP name = &(capsule_unit_sets [i].name);
unsigned j;
for (j = 0; j < i; j ++) {
if (nstring_equal (name, &(capsule_unit_sets [j].name))) {
MSG_unit_set_duplicate_name (istream_name (istream), name);
UNREACHED;
}
}
if (nstring_equal (name, &tld)) {
capsule_tld_index = i;
tld_found = TRUE;
} else if (nstring_equal (name, &tld2)) {
capsule_tld2_index = i;
}
}
if (!tld_found) {
MSG_unit_set_no_tld_name (istream_name (istream));
UNREACHED;
}
}
static void
capsule_read_unit_set_file_1(IStreamP istream)
{
UnitSetListEntryP head = NIL (UnitSetListEntryP);
UnitSetListEntryP *tail = &head;
unsigned num_unit_sets = 0;
UnitSetListEntryP entry;
UnitSetP unit_sets;
unsigned i;
for (;;) {
DStringT dstring;
if (!capsule_read_unit_set_name (istream, &dstring)) {
goto done;
}
entry = ALLOCATE (UnitSetListEntryT);
entry->next = NIL (UnitSetListEntryP);
dstring_to_nstring (&dstring, &(entry->name));
*tail = entry;
tail = &(entry->next);
dstring_destroy (&dstring);
num_unit_sets ++;
}
done:
unit_sets = ALLOCATE_VECTOR (UnitSetT, num_unit_sets);
i = 0;
entry = head;
while (entry) {
UnitSetListEntryP tmp = entry->next;
nstring_assign (&(unit_sets [i].name), &(entry->name));
DEALLOCATE (entry);
entry = tmp;
i ++;
}
capsule_num_unit_sets = num_unit_sets;
capsule_unit_sets = unit_sets;
capsule_check_unit_sets (istream);
}
/*--------------------------------------------------------------------------*/
static TDFReaderP
capsule_reader(CapsuleP capsule)
{
ASSERT (capsule->type == CT_INPUT);
return (&(capsule->u.reader));
}
static TDFWriterP
capsule_writer(CapsuleP capsule)
{
ASSERT (capsule->type == CT_OUTPUT);
return (&(capsule->u.writer));
}
static NStringP
capsule_magic(void)
{
static NStringT const_magic;
static BoolT inited = FALSE;
if (!inited) {
nstring_copy_cstring (&const_magic, "TDFC");
inited = TRUE;
}
return (&const_magic);
}
/*--------------------------------------------------------------------------*/
static void
capsule_read_header(CapsuleP capsule)
{
TDFReaderP reader = capsule_reader (capsule);
NStringP const_magic = capsule_magic ();
NStringT magic;
unsigned major;
unsigned minor;
nstring_init_length (&magic, (unsigned) 4);
tdf_read_bytes (reader, &magic);
if (!nstring_equal (&magic, const_magic)) {
MSG_capsule_bad_magic (capsule, &magic, const_magic);
THROW (XX_capsule_error);
UNREACHED;
}
nstring_destroy (&magic);
major = tdf_read_int (reader);
minor = tdf_read_int (reader);
debug_info_r_versions (major, minor);
if (major < 4) {
MSG_capsule_bad_version (capsule, major);
THROW (XX_capsule_error);
UNREACHED;
} else if (capsule_major_version == 0) {
capsule_major_version = major;
capsule_minor_version = minor;
} else if (capsule_major_version != major) {
MSG_capsule_version_mismatch (capsule, capsule_major_version, major);
THROW (XX_capsule_error);
UNREACHED;
} else if (capsule_minor_version < minor) {
capsule_minor_version = minor;
}
tdf_read_align (reader);
}
static UnitEntryP *
capsule_read_unit_set_names(CapsuleP capsule, UnitTableP units,
unsigned *num_unit_sets_ref)
{
TDFReaderP reader = capsule_reader (capsule);
unsigned num_unit_sets = tdf_read_int (reader);
UnitEntryP *units_vec = ALLOCATE_VECTOR (UnitEntryP, num_unit_sets);
UnitEntryP tld_entry = capsule_unit_sets [capsule_tld_index].entry;
UnitEntryP tld2_entry = ((capsule_tld2_index == UINT_MAX) ?
NIL (UnitEntryP) :
capsule_unit_sets [capsule_tld2_index].entry);
BoolT has_tld_unit = FALSE;
unsigned i;
debug_info_r_start_unit_decs (num_unit_sets);
for (i = 0; i < num_unit_sets; i ++) {
NStringT nstring;
UnitEntryP entry;
tdf_read_string (reader, &nstring);
if ((entry = unit_table_get (units, &nstring)) != NIL (UnitEntryP)) {
unsigned order = unit_entry_order (entry);
unsigned j;
for (j = 0; j < i; j ++) {
if (entry == units_vec [j]) {
MSG_duplicate_unit_set_name (capsule, &nstring);
THROW (XX_capsule_error);
UNREACHED;
} else if (order < unit_entry_order (units_vec [j])) {
MSG_out_of_order_unit_set_name (capsule, &nstring);
THROW (XX_capsule_error);
UNREACHED;
}
}
if (entry == tld2_entry) {
MSG_tld2_unit_set_type_obsolete (capsule);
}
if ((entry == tld_entry) || (entry == tld2_entry)) {
if (has_tld_unit) {
MSG_extra_tld_unit_set (capsule);
THROW (XX_capsule_error);
UNREACHED;
}
has_tld_unit = TRUE;
}
units_vec [i] = entry;
} else {
MSG_unknown_unit_set_name (capsule, &nstring);
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_unit_dec (&nstring);
nstring_destroy (&nstring);
}
if (!has_tld_unit) {
MSG_missing_tld_unit_set (tdf_reader_name (reader));
}
*num_unit_sets_ref = num_unit_sets;
return (units_vec);
}
static ShapeDataP
capsule_read_shapes(CapsuleP capsule, ShapeTableP shapes,
unsigned *num_shapes_ref)
{
TDFReaderP reader = capsule_reader (capsule);
unsigned num_shapes = tdf_read_int (reader);
ShapeDataP shapes_vec = ALLOCATE_VECTOR (ShapeDataT, num_shapes);
unsigned i;
debug_info_r_start_shapes (num_shapes);
for (i = 0; i < num_shapes; i ++) {
NStringT nstring;
unsigned num_ids;
ShapeEntryP entry;
unsigned j;
tdf_read_string (reader, &nstring);
num_ids = tdf_read_int (reader);
entry = shape_table_add (shapes, &nstring);
for (j = 0; j < i; j ++) {
if (entry == shapes_vec [j].entry) {
MSG_duplicate_shape_name (capsule, &nstring);
THROW (XX_capsule_error);
UNREACHED;
}
}
debug_info_r_shape (&nstring, num_ids);
nstring_destroy (&nstring);
shapes_vec [i].entry = entry;
shapes_vec [i].num_ids = num_ids;
shapes_vec [i].id_maps = ALLOCATE_VECTOR (unsigned, num_ids);
for (j = 0; j < num_ids; j ++) {
shapes_vec [i].id_maps [j] = UINT_MAX;
}
}
*num_shapes_ref = num_shapes;
return (shapes_vec);
}
static NameEntryP *
capsule_read_external_names_1(CapsuleP capsule, ShapeDataP shape,
unsigned *num_ref)
{
TDFReaderP reader = capsule_reader (capsule);
unsigned num_this_shape = tdf_read_int (reader);
ShapeEntryP entry = shape->entry;
NStringP key = shape_entry_key (entry);
NameTableP table = shape_entry_name_table (entry);
unsigned num_ids = shape->num_ids;
unsigned *id_maps = shape->id_maps;
NameEntryP *names_vec = ALLOCATE_VECTOR (NameEntryP, num_this_shape);
unsigned i;
debug_info_r_start_shape_names (key, num_this_shape);
for (i = 0; i < num_this_shape; i ++) {
unsigned id = tdf_read_int (reader);
NameKeyT name;
NameEntryP name_entry;
tdf_read_name (reader, &name);
if (id >= num_ids) {
MSG_name_id_out_of_range (capsule, key, &name, id, num_ids);
THROW (XX_capsule_error);
UNREACHED;
}
name_entry = name_table_add (table, &name, entry);
if (id_maps [id] != UINT_MAX) {
MSG_name_id_used_multiple_times (capsule, key, &name, id);
THROW (XX_capsule_error);
UNREACHED;
}
names_vec [i] = name_entry;
id_maps [id] = name_entry_id (name_entry);
debug_info_r_name (&name, id, id_maps [id],
name_entry_key (name_entry));
name_key_destroy (&name);
}
*num_ref = num_this_shape;
return (names_vec);
}
static NameDataP
capsule_read_external_names(CapsuleP capsule, unsigned num_shapes,
ShapeDataP shapes_vec)
{
TDFReaderP reader = capsule_reader (capsule);
NameDataT *names_vec_vec;
unsigned num_names;
unsigned i;
if ((num_names = tdf_read_int (reader)) != num_shapes) {
MSG_shape_and_name_count_mismatch (capsule, num_shapes, num_names);
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_start_names (num_names);
names_vec_vec = ALLOCATE_VECTOR (NameDataT, num_names);
for (i = 0; i < num_names; i ++) {
ShapeDataP shape = &(shapes_vec [i]);
NameEntryP *names_vec;
unsigned num_this_shape;
names_vec = capsule_read_external_names_1 (capsule, shape,
&num_this_shape);
names_vec_vec [i].names_vec = names_vec;
names_vec_vec [i].num_names = num_this_shape;
}
return (names_vec_vec);
}
/*--------------------------------------------------------------------------*/
static unsigned
capsule_get_token_index(ShapeTableP shapes, unsigned num_shapes,
ShapeDataP shapes_vec)
{
ShapeEntryP token_entry = shape_table_get_token_entry (shapes);
unsigned i;
for (i = 0; i < num_shapes; i ++) {
if (shapes_vec [i].entry == token_entry) {
return (i);
}
}
return (UINT_MAX);
}
static unsigned
capsule_get_tag_index(ShapeTableP shapes, unsigned num_shapes,
ShapeDataP shapes_vec)
{
ShapeEntryP tag_entry = shape_table_get_tag_entry (shapes);
unsigned i;
for (i = 0; i < num_shapes; i ++) {
if (shapes_vec [i].entry == tag_entry) {
return (i);
}
}
return (UINT_MAX);
}
static void
capsule_read_usage(CapsuleP capsule, NameDataP entry, BoolT need_dec,
BoolT no_mult, NStringP shape_key)
{
TDFReaderP reader = capsule_reader (capsule);
unsigned num_names = entry->num_names;
NameEntryP *names_vec = entry->names_vec;
unsigned i;
debug_info_r_start_usages (shape_key, num_names);
for (i = 0; i < num_names; i ++) {
unsigned use = tdf_read_int (reader);
NameEntryP name_entry = names_vec [i];
unsigned name_use = name_entry_get_use (name_entry);
NameKeyP key = name_entry_key (name_entry);
if (use & ~(U_USED | U_DECD | U_DEFD | U_MULT)) {
MSG_bad_usage (capsule, shape_key, key, use);
THROW (XX_capsule_error);
UNREACHED;
} else if (no_mult && (use & U_MULT)) {
MSG_illegally_multiply_defined (capsule, shape_key, key);
THROW (XX_capsule_error);
UNREACHED;
} else if (need_dec &&
(((use & (U_DEFD | U_DECD)) == U_DEFD) ||
((use & (U_MULT | U_DECD)) == U_MULT))) {
MSG_defined_but_not_declared (capsule, shape_key, key);
THROW (XX_capsule_error);
UNREACHED;
}
if ((use & U_DEFD) && (name_use & U_DEFD)) {
CapsuleP definition = name_entry_get_definition (name_entry);
char *prev_name = capsule_name (definition);
MSG_multiply_defined (capsule, shape_key, key, prev_name);
} else if ((use & U_MULT) && (name_use & U_MULT) &&
(!(use & U_DEFD)) && (!(name_use & U_DEFD))) {
name_entry_set_definition (name_entry, NIL (CapsuleP));
} else if ((use & U_DEFD) ||
((use & U_MULT) && (!(name_use & (U_MULT | U_DEFD))))) {
name_entry_set_definition (name_entry, capsule);
}
debug_info_r_usage (use, name_use, key);
name_entry_merge_use (name_entry, use);
}
}
static void
capsule_read_tld_type_0_unit(CapsuleP capsule, ShapeTableP shapes,
unsigned num_shapes, ShapeDataP shapes_vec, NameDataP names_vec_vec)
{
unsigned i;
i = capsule_get_token_index (shapes, num_shapes, shapes_vec);
if (i != UINT_MAX) {
NStringP key = shape_entry_key (shapes_vec [i].entry);
capsule_read_usage (capsule, &(names_vec_vec [i]), FALSE, TRUE, key);
}
i = capsule_get_tag_index (shapes, num_shapes, shapes_vec);
if (i != UINT_MAX) {
NStringP key = shape_entry_key (shapes_vec [i].entry);
capsule_read_usage (capsule, &(names_vec_vec [i]), TRUE, FALSE, key);
}
}
static void
capsule_read_tld_type_1_unit(CapsuleP capsule, ShapeTableP shapes,
unsigned num_shapes, ShapeDataP shapes_vec, NameDataP names_vec_vec)
{
unsigned i;
unsigned token = capsule_get_token_index (shapes, num_shapes, shapes_vec);
unsigned tag = capsule_get_tag_index (shapes, num_shapes, shapes_vec);
for (i = 0; i < num_shapes; i ++) {
NStringP key = shape_entry_key (shapes_vec [i].entry);
capsule_read_usage (capsule, &(names_vec_vec [i]), i == tag,
i == token, key);
}
}
/*--------------------------------------------------------------------------*/
typedef void (*UnitTypeProcP)(CapsuleP, ShapeTableP, unsigned, ShapeDataP, NameDataP);
static UnitTypeProcP capsule_type_jump_table [] = {
capsule_read_tld_type_0_unit,
capsule_read_tld_type_1_unit
};
#define CAPSULE_TYPE_JUMP_TABLE_SIZE \
((unsigned) (sizeof (capsule_type_jump_table) / \
sizeof (UnitTypeProcP)))
/*--------------------------------------------------------------------------*/
static void
capsule_read_tld_unit_header(CapsuleP capsule, NStringP unit_set)
{
TDFReaderP reader = capsule_reader (capsule);
if (tdf_read_int (reader) != 1) {
MSG_too_many_tld_units (capsule);
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_start_units (unit_set, (unsigned) 1);
debug_info_r_start_unit (unit_set, (unsigned) 1, (unsigned) 1);
if (tdf_read_int (reader) != 0) {
MSG_too_many_tld_unit_counts (capsule);
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_start_counts ((unsigned) 0);
if (tdf_read_int (reader) != 0) {
MSG_too_many_tld_unit_mappings (capsule);
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_start_maps ((unsigned) 0);
capsule_unit_length = tdf_read_int (reader);
debug_info_r_unit_body (capsule_unit_length);
tdf_read_align (reader);
capsule_unit_offset = tdf_reader_byte (reader);
}
static void
capsule_read_tld_unit_trailer(CapsuleP capsule)
{
TDFReaderP reader = capsule_reader (capsule);
unsigned offset = tdf_reader_byte (reader);
unsigned correct = (capsule_unit_offset + capsule_unit_length);
tdf_read_align (reader);
if (correct != offset) {
MSG_tld_unit_wrong_size (capsule, correct, offset);
THROW (XX_capsule_error);
UNREACHED;
}
}
static void
capsule_read_tld2_units(CapsuleP capsule, ShapeTableP shapes,
unsigned num_shapes, ShapeDataP shapes_vec, NameDataP names_vec_vec)
{
UnitEntryP tld2_entry = capsule_unit_sets [capsule_tld2_index].entry;
NStringP key = unit_entry_key (tld2_entry);
ASSERT (capsule_tld2_index != UINT_MAX);
capsule_read_tld_unit_header (capsule, key);
debug_info_r_tld_version ((unsigned) 0);
capsule_read_tld_type_0_unit (capsule, shapes, num_shapes, shapes_vec,
names_vec_vec);
capsule_read_tld_unit_trailer (capsule);
}
static void
capsule_read_tld_units(CapsuleP capsule, ShapeTableP shapes,
unsigned num_shapes, ShapeDataP shapes_vec, NameDataP names_vec_vec)
{
TDFReaderP reader = capsule_reader (capsule);
UnitEntryP tld_entry = capsule_unit_sets [capsule_tld_index].entry;
NStringP key = unit_entry_key (tld_entry);
unsigned unit_type;
capsule_read_tld_unit_header (capsule, key);
unit_type = tdf_read_int (reader);
if (unit_type >= CAPSULE_TYPE_JUMP_TABLE_SIZE) {
MSG_unknown_tld_unit_type (capsule, unit_type);
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_tld_version (unit_type);
(*(capsule_type_jump_table [unit_type])) (capsule, shapes, num_shapes,
shapes_vec, names_vec_vec);
capsule_read_tld_unit_trailer (capsule);
}
static MapEntryP *
capsule_read_unit_counts(CapsuleP capsule, unsigned num_shapes,
ShapeDataP shapes_vec, unsigned num_counts, UnitEntryP unit_entry,
UnitP unit, unsigned unit_num)
{
if ((num_counts != 0) && (num_counts != num_shapes)) {
MSG_unit_count_num_mismatch (capsule, num_counts, num_shapes, unit_num,
unit_entry_key (unit_entry));
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_start_counts (num_counts);
if (num_counts != 0) {
TDFReaderP reader = capsule_reader (capsule);
MapTableP table = unit_map_table (unit);
MapEntryP *entries = ALLOCATE_VECTOR (MapEntryP, num_counts);
unsigned i;
for (i = 0; i < num_counts; i ++) {
unsigned count = tdf_read_int (reader);
NStringP key = shape_entry_key (shapes_vec [i].entry);
MapEntryP entry = map_table_add (table, key, count);
debug_info_r_count (count, key);
entries [i] = entry;
}
return (entries);
} else {
return (NIL (MapEntryP *));
}
}
static void
capsule_read_unit_maps(CapsuleP capsule, unsigned num_counts,
ShapeDataP shapes_vec, UnitEntryP unit_entry, unsigned unit_num,
MapEntryP *entries)
{
TDFReaderP reader = capsule_reader (capsule);
unsigned num_link_shapes = tdf_read_int (reader);
unsigned i;
if (num_link_shapes != num_counts) {
MSG_unit_mapping_num_mismatch (capsule, num_link_shapes, num_counts,
unit_num, unit_entry_key (unit_entry));
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_start_maps (num_link_shapes);
for (i = 0; i < num_link_shapes; i ++) {
unsigned num_links = tdf_read_int (reader);
ShapeEntryP shape_entry = (shapes_vec [i].entry);
NStringP key = shape_entry_key (shape_entry);
unsigned j;
map_entry_set_num_links (entries [i], num_links);
debug_info_r_start_shape_maps (key, num_links);
for (j = 0; j < num_links; j ++) {
unsigned internal = tdf_read_int (reader);
unsigned external = tdf_read_int (reader);
unsigned num_ids = shapes_vec [i].num_ids;
unsigned *id_maps = shapes_vec [i].id_maps;
if (external >= num_ids) {
MSG_id_out_of_range (capsule, external, num_ids, key, unit_num,
unit_entry_key (unit_entry));
THROW (XX_capsule_error);
UNREACHED;
}
if (id_maps [external] == UINT_MAX) {
unsigned id = shape_entry_next_id (shape_entry);
id_maps [external] = id;
}
debug_info_r_map (internal, external, id_maps [external]);
external = id_maps [external];
map_entry_set_link (entries [i], j, internal, external);
}
}
}
static void
capsule_read_unit(CapsuleP capsule, unsigned num_shapes, ShapeDataP shapes_vec,
UnitEntryP unit_entry, unsigned unit_num)
{
TDFReaderP reader = capsule_reader (capsule);
unsigned num_counts = tdf_read_int (reader);
UnitP unit = unit_entry_add_unit (unit_entry, num_counts);
MapEntryP *entries;
unsigned size;
NStringT nstring;
entries = capsule_read_unit_counts (capsule, num_shapes, shapes_vec,
num_counts, unit_entry, unit,
unit_num);
capsule_read_unit_maps (capsule, num_counts, shapes_vec, unit_entry,
unit_num, entries);
size = tdf_read_int (reader);
debug_info_r_unit_body (size);
nstring_init_length (&nstring, size);
tdf_read_bytes (reader, &nstring);
unit_set_contents (unit, &nstring);
DEALLOCATE (entries);
}
static void
capsule_read_units(CapsuleP capsule, unsigned num_shapes,
ShapeDataP shapes_vec, UnitEntryP unit_entry)
{
TDFReaderP reader = capsule_reader (capsule);
unsigned num_units = tdf_read_int (reader);
unsigned i;
debug_info_r_start_units (unit_entry_key (unit_entry), num_units);
for (i = 0; i < num_units; i ++) {
debug_info_r_start_unit (unit_entry_key (unit_entry), i + 1,
num_units);
capsule_read_unit (capsule, num_shapes, shapes_vec,
unit_entry, i);
}
}
static void
capsule_read_unit_sets(CapsuleP capsule, unsigned num_unit_sets,
UnitEntryP *units_vec, ShapeTableP shapes, unsigned num_shapes,
ShapeDataP shapes_vec, NameDataP names_vec_vec)
{
TDFReaderP reader = capsule_reader (capsule);
UnitEntryP tld_entry = capsule_unit_sets [capsule_tld_index].entry;
UnitEntryP tld2_entry = ((capsule_tld2_index == UINT_MAX) ?
NIL (UnitEntryP) :
capsule_unit_sets [capsule_tld2_index].entry);
unsigned num_units;
unsigned i;
if ((num_units = tdf_read_int (reader)) != num_unit_sets) {
MSG_unit_set_count_mismatch (capsule, num_unit_sets, num_units);
THROW (XX_capsule_error);
UNREACHED;
}
debug_info_r_start_unit_sets (num_units);
for (i = 0; i < num_units; i ++) {
if (units_vec [i] == tld_entry) {
capsule_read_tld_units (capsule, shapes, num_shapes, shapes_vec,
names_vec_vec);
} else if (units_vec [i] == tld2_entry) {
capsule_read_tld2_units (capsule, shapes, num_shapes, shapes_vec,
names_vec_vec);
} else {
capsule_read_units (capsule, num_shapes, shapes_vec,
units_vec [i]);
}
}
}
/*--------------------------------------------------------------------------*/
static void
capsule_write_header(CapsuleP capsule)
{
TDFWriterP writer = capsule_writer (capsule);
NStringP const_magic = capsule_magic ();
tdf_write_bytes (writer, const_magic);
ASSERT (capsule_major_version >= 4);
tdf_write_int (writer, capsule_major_version);
tdf_write_int (writer, capsule_minor_version);
debug_info_w_versions (capsule_major_version, capsule_minor_version);
tdf_write_align (writer);
}
/*--------------------------------------------------------------------------*/
void
capsule_read_unit_set_file(char *name)
{
IStreamT istream;
ASSERT (capsule_unit_sets == NIL (UnitSetP));
if (!istream_open (&istream, name)) {
MSG_cant_open_unit_set_file (name);
UNREACHED;
}
capsule_read_unit_set_file_1 (&istream);
istream_close (&istream);
}
CapsuleP
capsule_create_stream_input(char *name)
{
CapsuleP capsule = ALLOCATE (CapsuleT);
capsule->type = CT_INPUT;
if (!tdf_reader_open (capsule_reader (capsule), name)) {
DEALLOCATE (capsule);
return (NIL (CapsuleP));
}
capsule->name = name;
capsule->complete = FALSE;
return (capsule);
}
CapsuleP
capsule_create_string_input(char *name, NStringP contents)
{
CapsuleP capsule = ALLOCATE (CapsuleT);
capsule->type = CT_INPUT;
tdf_reader_open_string (capsule_reader (capsule), name, contents);
capsule->name = name;
capsule->complete = FALSE;
return (capsule);
}
CapsuleP
capsule_create_stream_output(char *name)
{
CapsuleP capsule = ALLOCATE (CapsuleT);
capsule->type = CT_OUTPUT;
if (!tdf_writer_open (capsule_writer (capsule), name)) {
DEALLOCATE (capsule);
return (NIL (CapsuleP));
}
capsule->name = name;
return (capsule);
}
char *
capsule_name(CapsuleP capsule)
{
return (capsule->name);
}
unsigned
capsule_byte(CapsuleP capsule)
{
return (tdf_reader_byte (capsule_reader (capsule)));
}
void
capsule_read(CapsuleP capsule, UnitTableP units, ShapeTableP shapes)
{
ASSERT (capsule->type == CT_INPUT);
capsule_setup (units);
HANDLE {
UnitEntryP *units_vec;
unsigned num_unit_sets;
ShapeDataP shapes_vec;
unsigned num_shapes;
NameDataP names_vec_vec;
unsigned i;
debug_info_r_start_capsule (capsule_name (capsule));
capsule_read_header (capsule);
units_vec = capsule_read_unit_set_names (capsule, units,
&num_unit_sets);
shapes_vec = capsule_read_shapes (capsule, shapes, &num_shapes);
names_vec_vec = capsule_read_external_names (capsule, num_shapes,
shapes_vec);
capsule_read_unit_sets (capsule, num_unit_sets, units_vec, shapes,
num_shapes, shapes_vec, names_vec_vec);
tdf_read_eof (capsule_reader (capsule));
debug_info_r_end_capsule ();
DEALLOCATE (units_vec);
for (i = 0; i < num_shapes; i ++) {
DEALLOCATE (shapes_vec [i].id_maps);
DEALLOCATE (names_vec_vec [i].names_vec);
}
DEALLOCATE (shapes_vec);
DEALLOCATE (names_vec_vec);
capsule->complete = TRUE;
} WITH {
ExceptionP exception = EXCEPTION_EXCEPTION ();
debug_info_r_abort_capsule ();
if ((exception != XX_capsule_error) &&
(exception != XX_tdf_read_error)) {
RETHROW ();
}
} END_HANDLE
}
void
capsule_store_contents(CapsuleP capsule)
{
if (capsule->complete) {
TDFReaderP reader = capsule_reader (capsule);
unsigned length = tdf_reader_byte (reader);
nstring_init_length (&(capsule->contents), length);
tdf_reader_rewind (reader);
tdf_read_bytes (reader, &(capsule->contents));
tdf_read_eof (reader);
}
}
NStringP
capsule_contents(CapsuleP capsule)
{
return (&(capsule->contents));
}
void
capsule_set_index(CapsuleP capsule, unsigned i)
{
capsule->capsule_index = i;
}
unsigned
capsule_get_index(CapsuleP capsule)
{
return (capsule->capsule_index);
}
void
capsule_write(CapsuleP capsule, UnitTableP units, ShapeTableP shapes)
{
TDFWriterP writer = capsule_writer (capsule);
UnitEntryP tld_entry = capsule_unit_sets [capsule_tld_index].entry;
unsigned num_shapes = 0;
UnitSetClosureT unit_set_closure;
unsigned i;
debug_info_w_start_capsule (capsule_name (capsule));
capsule_write_header (capsule);
unit_set_closure.num_unit_sets = 1;
unit_set_closure.shapes = shapes;
unit_table_iter (units, unit_entry_do_count, (void *) &unit_set_closure);
debug_info_w_start_unit_decs (unit_set_closure.num_unit_sets);
tdf_write_int (writer, unit_set_closure.num_unit_sets);
for (i = 0; i < capsule_num_unit_sets; i ++) {
UnitEntryP entry = capsule_unit_sets [i].entry;
unit_entry_write_unit_set (entry, tld_entry, writer);
}
shape_table_iter (shapes, shape_entry_do_count, (void *) &num_shapes);
debug_info_w_start_shapes (num_shapes);
tdf_write_int (writer, num_shapes);
shape_table_iter (shapes, shape_entry_write_shape, (void *) writer);
debug_info_w_start_names (num_shapes);
tdf_write_int (writer, num_shapes);
shape_table_iter (shapes, shape_entry_write_externs, (void *) writer);
debug_info_w_start_unit_sets (unit_set_closure.num_unit_sets);
tdf_write_int (writer, unit_set_closure.num_unit_sets);
for (i = 0; i < capsule_num_unit_sets; i ++) {
UnitEntryP entry = capsule_unit_sets [i].entry;
if (entry == tld_entry) {
unit_entry_write_tld_unit (entry, shapes, writer);
} else {
unit_entry_write_units (entry, shapes, num_shapes, writer);
}
}
debug_info_w_end_capsule ();
}
void
capsule_close(CapsuleP capsule)
{
switch (capsule->type) EXHAUSTIVE {
case CT_INPUT:
tdf_reader_close (capsule_reader (capsule));
break;
case CT_OUTPUT:
tdf_writer_close (capsule_writer (capsule));
break;
}
}
unsigned
capsule_get_major_version(void)
{
return (capsule_major_version);
}
void
capsule_set_major_version(unsigned major)
{
capsule_major_version = major;
}
unsigned
capsule_get_minor_version(void)
{
return (capsule_minor_version);
}