Blame AttrTable.cc

Packit a4aae4
// -*- mode: c++; c-basic-offset:4 -*-
Packit a4aae4
Packit a4aae4
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
Packit a4aae4
// Access Protocol.
Packit a4aae4
Packit a4aae4
// Copyright (c) 2002,2003 OPeNDAP, Inc.
Packit a4aae4
// Author: James Gallagher <jgallagher@opendap.org>
Packit a4aae4
//
Packit a4aae4
// This library is free software; you can redistribute it and/or
Packit a4aae4
// modify it under the terms of the GNU Lesser General Public
Packit a4aae4
// License as published by the Free Software Foundation; either
Packit a4aae4
// version 2.1 of the License, or (at your option) any later version.
Packit a4aae4
//
Packit a4aae4
// This library is distributed in the hope that it will be useful,
Packit a4aae4
// but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a4aae4
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit a4aae4
// Lesser General Public License for more details.
Packit a4aae4
//
Packit a4aae4
// You should have received a copy of the GNU Lesser General Public
Packit a4aae4
// License along with this library; if not, write to the Free Software
Packit a4aae4
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit a4aae4
//
Packit a4aae4
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
Packit a4aae4
Packit a4aae4
// (c) COPYRIGHT URI/MIT 1994-1999
Packit a4aae4
// Please read the full copyright statement in the file COPYRIGHT_URI.
Packit a4aae4
//
Packit a4aae4
// Authors:
Packit a4aae4
//      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
Packit a4aae4
Packit a4aae4
// jhrg 7/29/94
Packit a4aae4
Packit a4aae4
#include "config.h"
Packit a4aae4
Packit a4aae4
#include <cassert>
Packit a4aae4
#include <sstream>
Packit a4aae4
Packit a4aae4
#include "AttrTable.h"
Packit a4aae4
Packit a4aae4
#include "util.h"
Packit a4aae4
#include "escaping.h"
Packit a4aae4
Packit a4aae4
#include "debug.h"
Packit a4aae4
Packit a4aae4
// Should the www2id and id2www functions be used to encode attribute names?
Packit a4aae4
// Probably not... jhrg 11/16/11
Packit a4aae4
#define WWW_ENCODING 0
Packit a4aae4
// See the note for del_attr_table(). That method now deletes the contained
Packit a4aae4
// AttrTable.
Packit a4aae4
#define NEW_DEL_ATTR_TABLE_BEHAVIOR 0
Packit a4aae4
Packit a4aae4
using std::cerr;
Packit a4aae4
using std::string;
Packit a4aae4
using std::endl;
Packit a4aae4
using std::vector;
Packit a4aae4
Packit a4aae4
namespace libdap {
Packit a4aae4
Packit a4aae4
/** Remove %20 space encoding */
Packit a4aae4
string remove_space_encoding(const string &s)
Packit a4aae4
{
Packit a4aae4
    string::size_type pos = s.find("%20");
Packit a4aae4
    if (pos != string::npos) {
Packit a4aae4
        string n = s;
Packit a4aae4
        do {
Packit a4aae4
            n.replace(pos, 3, " ");
Packit a4aae4
            pos = n.find("%20");
Packit a4aae4
        } while (pos != string::npos);
Packit a4aae4
        return n;
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        return s;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Add %20 space encoding. */
Packit a4aae4
string add_space_encoding(const string &s)
Packit a4aae4
{
Packit a4aae4
    string::size_type pos = s.find(" ");
Packit a4aae4
    if (pos != string::npos) {
Packit a4aae4
        string n = s;
Packit a4aae4
        do {
Packit a4aae4
            n.replace(pos, 1, "%20");
Packit a4aae4
            pos = n.find(" ");
Packit a4aae4
        } while (pos != string::npos);
Packit a4aae4
        return n;
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        return s;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Convert an AttrType to it's string representation.
Packit a4aae4
 @param at The Attribute Type.
Packit a4aae4
 @return The type's string representation */
Packit a4aae4
string AttrType_to_String(const AttrType at)
Packit a4aae4
{
Packit a4aae4
    switch (at) {
Packit a4aae4
    case Attr_container:
Packit a4aae4
        return "Container";
Packit a4aae4
    case Attr_byte:
Packit a4aae4
        return "Byte";
Packit a4aae4
    case Attr_int16:
Packit a4aae4
        return "Int16";
Packit a4aae4
    case Attr_uint16:
Packit a4aae4
        return "UInt16";
Packit a4aae4
    case Attr_int32:
Packit a4aae4
        return "Int32";
Packit a4aae4
    case Attr_uint32:
Packit a4aae4
        return "UInt32";
Packit a4aae4
    case Attr_float32:
Packit a4aae4
        return "Float32";
Packit a4aae4
    case Attr_float64:
Packit a4aae4
        return "Float64";
Packit a4aae4
    case Attr_string:
Packit a4aae4
        return "String";
Packit a4aae4
    case Attr_url:
Packit a4aae4
        return "Url";
Packit a4aae4
    case Attr_other_xml:
Packit a4aae4
        return "OtherXML";
Packit a4aae4
    default:
Packit a4aae4
        return "";
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
AttrType String_to_AttrType(const string &s)
Packit a4aae4
{
Packit a4aae4
    string s2 = s;
Packit a4aae4
    downcase(s2);
Packit a4aae4
Packit a4aae4
    if (s2 == "container")
Packit a4aae4
        return Attr_container;
Packit a4aae4
    else if (s2 == "byte")
Packit a4aae4
        return Attr_byte;
Packit a4aae4
    else if (s2 == "int16")
Packit a4aae4
        return Attr_int16;
Packit a4aae4
    else if (s2 == "uint16")
Packit a4aae4
        return Attr_uint16;
Packit a4aae4
    else if (s2 == "int32")
Packit a4aae4
        return Attr_int32;
Packit a4aae4
    else if (s2 == "uint32")
Packit a4aae4
        return Attr_uint32;
Packit a4aae4
    else if (s2 == "float32")
Packit a4aae4
        return Attr_float32;
Packit a4aae4
    else if (s2 == "float64")
Packit a4aae4
        return Attr_float64;
Packit a4aae4
    else if (s2 == "string")
Packit a4aae4
        return Attr_string;
Packit a4aae4
    else if (s2 == "url")
Packit a4aae4
        return Attr_url;
Packit a4aae4
    else if (s2 == "otherxml")
Packit a4aae4
        return Attr_other_xml;
Packit a4aae4
    else
Packit a4aae4
        return Attr_unknown;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Clone the given attribute table in <tt>this</tt>.
Packit a4aae4
 Protected. */
Packit a4aae4
void AttrTable::clone(const AttrTable &at)
Packit a4aae4
{
Packit a4aae4
    d_name = at.d_name;
Packit a4aae4
    d_is_global_attribute = at.d_is_global_attribute;
Packit a4aae4
Packit a4aae4
    // Set the parent to null (no parent, not in container)
Packit a4aae4
    // since using at.d_parent is semantically incorrect
Packit a4aae4
    // and potentially dangerous.
Packit a4aae4
    d_parent = 0;
Packit a4aae4
Packit a4aae4
    Attr_citer i = at.attr_map.begin();
Packit a4aae4
    Attr_citer ie = at.attr_map.end();
Packit a4aae4
    for (; i != ie; ++i) {
Packit a4aae4
        // this deep-copies containers recursively
Packit a4aae4
        entry *e = new entry(*(*i));
Packit a4aae4
        attr_map.push_back(e);
Packit a4aae4
Packit a4aae4
        // If the entry being added was a container,
Packit a4aae4
        // set its parent to this to maintain invariant.
Packit a4aae4
        if (e->type == Attr_container) {
Packit a4aae4
            assert(e->attributes);
Packit a4aae4
            e->attributes->d_parent = this;
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @name Instance management functions */
Packit a4aae4
Packit a4aae4
//@{
Packit a4aae4
AttrTable::AttrTable() :
Packit a4aae4
    DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true)
Packit a4aae4
{
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
AttrTable::AttrTable(const AttrTable &rhs) :
Packit a4aae4
    DapObj()
Packit a4aae4
{
Packit a4aae4
    clone(rhs);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Private
Packit a4aae4
void AttrTable::delete_attr_table()
Packit a4aae4
{
Packit a4aae4
    for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
Packit a4aae4
        delete *i;
Packit a4aae4
    }
Packit a4aae4
    attr_map.clear();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
AttrTable::~AttrTable()
Packit a4aae4
{
Packit a4aae4
    delete_attr_table();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
AttrTable &
Packit a4aae4
AttrTable::operator=(const AttrTable &rhs)
Packit a4aae4
{
Packit a4aae4
    if (this != &rhs) {
Packit a4aae4
        delete_attr_table();
Packit a4aae4
        clone(rhs);
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    return *this;
Packit a4aae4
}
Packit a4aae4
//@}
Packit a4aae4
Packit a4aae4
/** Attributes that are containers count one attribute, as do
Packit a4aae4
 attributes with both scalar and vector values.
Packit a4aae4
 @return The number of entries.
Packit a4aae4
 @brief Get the number of entries in this attribute table.
Packit a4aae4
 */
Packit a4aae4
unsigned int AttrTable::get_size() const
Packit a4aae4
{
Packit a4aae4
    return attr_map.size();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Get the name of this attribute table.
Packit a4aae4
 @return A string containing the name. */
Packit a4aae4
string AttrTable::get_name() const
Packit a4aae4
{
Packit a4aae4
    return d_name;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Set the name of this attribute table.
Packit a4aae4
 @param n The new name of the attribute table. */
Packit a4aae4
void AttrTable::set_name(const string &n)
Packit a4aae4
{
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
    d_name = www2id(n);
Packit a4aae4
#else
Packit a4aae4
    d_name = remove_space_encoding(n);
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
// This was taken from das.y and could be used here to make the 'dods_errors'
Packit a4aae4
// attribute container like the parser used to. Then again, maybe this feature
Packit a4aae4
// was just BS. jhrg (ticket 1469)
Packit a4aae4
static void add_bad_attribute(AttrTable *attr, const string &type, const string &name, const string &value,
Packit a4aae4
        const string &msg) {
Packit a4aae4
    // First, if this bad value is already in a *_dods_errors container,
Packit a4aae4
    // then just add it. This can happen when the server side processes a DAS
Packit a4aae4
    // and then hands it off to a client which does the same.
Packit a4aae4
    // Make a new container. Call it <attr's name>_errors. If that container
Packit a4aae4
    // already exists, use it.
Packit a4aae4
    // Add the attribute.
Packit a4aae4
    // Add the error string to an attribute in the container called
Packit a4aae4
    // `
Packit a4aae4
Packit a4aae4
    if (attr->get_name().find("_dods_errors") != string::npos) {
Packit a4aae4
        attr->append_attr(name, type, value);
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        // I think _dods_errors should be _dap_error. jhrg 11/16/11
Packit a4aae4
        string error_cont_name = attr->get_name() + "_dods_errors";
Packit a4aae4
        AttrTable *error_cont = attr->get_attr_table(error_cont_name);
Packit a4aae4
        if (!error_cont)
Packit a4aae4
        error_cont = attr->append_container(error_cont_name);
Packit a4aae4
Packit a4aae4
        error_cont->append_attr(name, type, value);
Packit a4aae4
Packit a4aae4
#ifndef ATTR_STRING_QUOTE_FIX
Packit a4aae4
        error_cont->append_attr(name + "_dap_explanation", "String", "\"" + msg + "\"");
Packit a4aae4
#else
Packit a4aae4
        error_cont->append_attr(name + "_dap_explanation", "String", msg);
Packit a4aae4
#endif
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
/** If the given name already refers to an attribute, and the attribute has a
Packit a4aae4
 value, the given value is appended to the attribute vector. Calling this
Packit a4aae4
 function repeatedly is the way to append to an attribute vector.
Packit a4aae4
Packit a4aae4
 The function throws an Error if the attribute is a container,
Packit a4aae4
 or if the type of the input value does not match the existing attribute's
Packit a4aae4
 type. Use <tt>append_container()</tt> to add container attributes.
Packit a4aae4
Packit a4aae4
 This method performs a simple search for <tt>name</tt> in this attribute
Packit a4aae4
 table only; sub-tables are not searched and the dot notation is not
Packit a4aae4
 recognized.
Packit a4aae4
Packit a4aae4
 @brief Add an attribute to the table.
Packit a4aae4
 @return Returns the length of the added attribute value.
Packit a4aae4
 @param name The name of the attribute to add or modify.
Packit a4aae4
 @param type The type of the attribute to add or modify.
Packit a4aae4
 @param value The value to add to the attribute table. */
Packit a4aae4
unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Entering AttrTable::append_attr" << endl);
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
    string lname = www2id(name);
Packit a4aae4
#else
Packit a4aae4
    string lname = remove_space_encoding(name);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    Attr_iter iter = simple_find(lname);
Packit a4aae4
Packit a4aae4
    // If the types don't match OR this attribute is a container, calling
Packit a4aae4
    // this mfunc is an error!
Packit a4aae4
    if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
Packit a4aae4
        throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
Packit a4aae4
    if (iter != attr_map.end() && (get_type(iter) == "Container"))
Packit a4aae4
        throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
Packit a4aae4
Packit a4aae4
    if (iter != attr_map.end()) { // Must be a new attribute value; add it.
Packit a4aae4
        (*iter)->attr->push_back(value);
Packit a4aae4
        return (*iter)->attr->size();
Packit a4aae4
    }
Packit a4aae4
    else { // Must be a completely new attribute; add it
Packit a4aae4
        entry *e = new entry;
Packit a4aae4
Packit a4aae4
        e->name = lname;
Packit a4aae4
        e->is_alias = false;
Packit a4aae4
        e->type = String_to_AttrType(type); // Record type using standard names.
Packit a4aae4
        e->attr = new vector<string> ;
Packit a4aae4
        e->attr->push_back(value);
Packit a4aae4
Packit a4aae4
        attr_map.push_back(e);
Packit a4aae4
Packit a4aae4
        return e->attr->size(); // return the length of the attr vector
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** This version of append_attr() takes a vector<string> of values.
Packit a4aae4
 If the given name already refers to an attribute, and the attribute has
Packit a4aae4
 values, append the new values to the existing ones.
Packit a4aae4
Packit a4aae4
 The function throws an Error if the attribute is a container,
Packit a4aae4
 or if the type of the input value does not match the existing attribute's
Packit a4aae4
 type. Use <tt>append_container()</tt> to add container attributes.
Packit a4aae4
Packit a4aae4
 This method performs a simple search for <tt>name</tt> in this attribute
Packit a4aae4
 table only; sub-tables are not searched and the dot notation is not
Packit a4aae4
 recognized.
Packit a4aae4
Packit a4aae4
 @brief Add an attribute to the table.
Packit a4aae4
 @return Returns the length of the added attribute value.
Packit a4aae4
 @param name The name of the attribute to add or modify.
Packit a4aae4
 @param type The type of the attribute to add or modify.
Packit a4aae4
 @param values A vector of values. Note: The vector is COPIED, not stored. */
Packit a4aae4
Packit a4aae4
unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
    string lname = www2id(name);
Packit a4aae4
#else
Packit a4aae4
    string lname = remove_space_encoding(name);
Packit a4aae4
#endif
Packit a4aae4
    Attr_iter iter = simple_find(lname);
Packit a4aae4
Packit a4aae4
    // If the types don't match OR this attribute is a container, calling
Packit a4aae4
    // this mfunc is an error!
Packit a4aae4
    if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
Packit a4aae4
        throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
Packit a4aae4
    if (iter != attr_map.end() && (get_type(iter) == "Container"))
Packit a4aae4
        throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
Packit a4aae4
Packit a4aae4
    if (iter != attr_map.end()) { // Must be new attribute values; add.
Packit a4aae4
        vector<string>::iterator i = values->begin();
Packit a4aae4
        while (i != values->end())
Packit a4aae4
            (*iter)->attr->push_back(*i++);
Packit a4aae4
Packit a4aae4
        return (*iter)->attr->size();
Packit a4aae4
    }
Packit a4aae4
    else { // Must be a completely new attribute; add it
Packit a4aae4
        entry *e = new entry;
Packit a4aae4
Packit a4aae4
        e->name = lname;
Packit a4aae4
        e->is_alias = false;
Packit a4aae4
        e->type = String_to_AttrType(type); // Record type using standard names.
Packit a4aae4
        e->attr = new vector<string> (*values);
Packit a4aae4
Packit a4aae4
        attr_map.push_back(e);
Packit a4aae4
Packit a4aae4
        return e->attr->size(); // return the length of the attr vector
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Create and append an attribute container to this AttrTable. If this
Packit a4aae4
 attribute table already contains an attribute container called
Packit a4aae4
 <tt>name</tt> an exception is thrown. Return a pointer to the new container.
Packit a4aae4
Packit a4aae4
 @brief Add a container to the attribute table.
Packit a4aae4
 @param name The name of the container to create.
Packit a4aae4
 @return A pointer to the new AttrTable object.
Packit a4aae4
 */
Packit a4aae4
Packit a4aae4
AttrTable *
Packit a4aae4
AttrTable::append_container(const string &name)
Packit a4aae4
{
Packit a4aae4
    AttrTable *new_at = new AttrTable;
Packit a4aae4
    AttrTable *ret = NULL;
Packit a4aae4
    try {
Packit a4aae4
        ret = append_container(new_at, name);
Packit a4aae4
    } catch (Error &e) {
Packit a4aae4
        // an error occurred, attribute with that name already exists
Packit a4aae4
        delete new_at;
Packit a4aae4
        new_at = 0;
Packit a4aae4
        throw;
Packit a4aae4
    }
Packit a4aae4
    return ret;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Append a new attribute container to this attribute table. The new
Packit a4aae4
 container is <tt>at</tt> and its name is set to
Packit a4aae4
 <tt>name</tt>. If this attribute
Packit a4aae4
 table already contains an attribute container called
Packit a4aae4
 <tt>name</tt> an exception is thrown.
Packit a4aae4
Packit a4aae4
 @note The value of \e name will override the name of \e at set using the
Packit a4aae4
 set_name() method.
Packit a4aae4
Packit a4aae4
 @brief Add a container to the attribute table.
Packit a4aae4
 @param at A pointer to the new attribute table to append.
Packit a4aae4
 @param name The name of the new attribute table.
Packit a4aae4
 @return A pointer to the new AttrTable object.
Packit a4aae4
 */
Packit a4aae4
AttrTable *
Packit a4aae4
AttrTable::append_container(AttrTable *at, const string &name)
Packit a4aae4
{
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
    string lname = www2id(name);
Packit a4aae4
#else
Packit a4aae4
    string lname = remove_space_encoding(name);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    if (simple_find(name) != attr_end())
Packit a4aae4
        throw Error("There already exists a container called '" + name + "' in this attribute table (" + at->get_name() + "). (1)");
Packit a4aae4
Packit a4aae4
    DBG(cerr << "Setting appended attribute container name to: " << lname << endl);
Packit a4aae4
    at->set_name(lname);
Packit a4aae4
Packit a4aae4
    entry *e = new entry;
Packit a4aae4
    e->name = lname;
Packit a4aae4
    e->is_alias = false;
Packit a4aae4
    e->type = Attr_container;
Packit a4aae4
    e->attributes = at;
Packit a4aae4
Packit a4aae4
    attr_map.push_back(e);
Packit a4aae4
Packit a4aae4
    at->d_parent = this;
Packit a4aae4
Packit a4aae4
    return e->attributes;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Look for an attribute or an attribute container. If used to search
Packit a4aae4
 for an attribute container, this method returns the container's \e
Packit a4aae4
 parent using the value-result parameter \c at and a reference to the
Packit a4aae4
 container using the iterator value-result parameter \c iter. If used
Packit a4aae4
 to search for an attribute, the attribute's container is returned using
Packit a4aae4
 \c at; the attribute itself can be accessed using the iterator \c iter.
Packit a4aae4
Packit a4aae4
 @param target The name (using dot notation) of the attribute or
Packit a4aae4
 container to find.
Packit a4aae4
 @param at A value-result used to return the attribute container in
Packit a4aae4
 which \c target was found. Null if \c target was not found.
Packit a4aae4
 @param iter The iterator which will reference the attribute found.
Packit a4aae4
 Can be used to access \c target from within \c at. References
Packit a4aae4
 dim_end() within \c at if the attribute or container does not exist. */
Packit a4aae4
void AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter)
Packit a4aae4
{
Packit a4aae4
    string::size_type dotpos = target.rfind('.');
Packit a4aae4
    if (dotpos != string::npos) {
Packit a4aae4
        string container = target.substr(0, dotpos);
Packit a4aae4
        string field = target.substr(dotpos + 1);
Packit a4aae4
Packit a4aae4
        *at = find_container(container);
Packit a4aae4
        if (*at) {
Packit a4aae4
            *iter = (*at)->simple_find(field);
Packit a4aae4
        }
Packit a4aae4
        else {
Packit a4aae4
            *iter = attr_map.end();
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        *at = recurrsive_find(target, iter);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** This method scans for attributes using recursion to look inside containers
Packit a4aae4
 even when the name of the attribute is not fully qualified. It starts
Packit a4aae4
 looking in itself and descends into its children depth first. It will find
Packit a4aae4
 attributes and attribute containers.
Packit a4aae4
Packit a4aae4
 @param target Look for the attribute with this name.
Packit a4aae4
 @param location A value-result parameter. This returns an iterator to the
Packit a4aae4
 attribute within the returned AttrTable object
Packit a4aae4
 @return Returns a pointer to the AttrTable which holds \e target, or null
Packit a4aae4
 if \e target is not found. In the latter case, the value of \e location is
Packit a4aae4
 attr_end() for this AttrTable. */
Packit a4aae4
AttrTable *
Packit a4aae4
AttrTable::recurrsive_find(const string &target, Attr_iter *location)
Packit a4aae4
{
Packit a4aae4
    Attr_iter i = attr_begin();
Packit a4aae4
    while (i != attr_end()) {
Packit a4aae4
        if (target == (*i)->name) {
Packit a4aae4
            *location = i;
Packit a4aae4
            return this;
Packit a4aae4
        }
Packit a4aae4
        else if ((*i)->type == Attr_container) {
Packit a4aae4
            AttrTable *at = (*i)->attributes->recurrsive_find(target, location);
Packit a4aae4
            if (at)
Packit a4aae4
                return at;
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        ++i;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    *location = i;
Packit a4aae4
    return 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Made public for callers that want non-recursive find.  [mjohnson 6 oct 09]
Packit a4aae4
/** Look in this AttrTable for the attribute called \c name. If found return
Packit a4aae4
 an Attr_iter which references it, otherwise return the end iterator for
Packit a4aae4
 this AttrTable.
Packit a4aae4
Packit a4aae4
 @param target The name of the attribute.
Packit a4aae4
 @return An Attr_iter which references \c target. */
Packit a4aae4
AttrTable::Attr_iter AttrTable::simple_find(const string &target)
Packit a4aae4
{
Packit a4aae4
    Attr_iter i;
Packit a4aae4
    for (i = attr_map.begin(); i != attr_map.end(); ++i) {
Packit a4aae4
        if (target == (*i)->name) {
Packit a4aae4
            break;
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    return i;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Look in this attribute table for an attribute container named
Packit a4aae4
 <tt>target</tt>. The search starts at this attribute table;
Packit a4aae4
 <tt>target</tt> should
Packit a4aae4
 use the dot notation to name containers held within children of this
Packit a4aae4
 attribute table.
Packit a4aae4
Packit a4aae4
 To search the entire DAS object, make sure to invoke this method from
Packit a4aae4
 that object.
Packit a4aae4
Packit a4aae4
 @brief Find an attribute with a given name.
Packit a4aae4
 @param target The attribute container to find.
Packit a4aae4
 @return A pointer to the attribute table or null if the container
Packit a4aae4
 cannot be found. */
Packit a4aae4
AttrTable *
Packit a4aae4
AttrTable::find_container(const string &target)
Packit a4aae4
{
Packit a4aae4
    string::size_type dotpos = target.find('.');
Packit a4aae4
    if (dotpos != string::npos) {
Packit a4aae4
        string container = target.substr(0, dotpos);
Packit a4aae4
        string field = target.substr(dotpos + 1);
Packit a4aae4
Packit a4aae4
        AttrTable *at = simple_find_container(container);
Packit a4aae4
        return (at) ? at->find_container(field) : 0;
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        return simple_find_container(target);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Made public for callers that want non-recursive find.  [mjohnson 6 oct 09]
Packit a4aae4
AttrTable *
Packit a4aae4
AttrTable::simple_find_container(const string &target)
Packit a4aae4
{
Packit a4aae4
    if (get_name() == target)
Packit a4aae4
        return this;
Packit a4aae4
Packit a4aae4
    for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
Packit a4aae4
        if (is_container(i) && target == (*i)->name) {
Packit a4aae4
            return (*i)->attributes;
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    return 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Each of the following accessors get information using the name of an
Packit a4aae4
 attribute. They perform a simple search for the name in this
Packit a4aae4
 attribute table only; sub-tables are not searched and the dot
Packit a4aae4
 notation is not recognized.
Packit a4aae4
Packit a4aae4
 @name Accessors using an attribute name */
Packit a4aae4
//@{
Packit a4aae4
Packit a4aae4
/** @brief Get an attribute container. */
Packit a4aae4
AttrTable *
Packit a4aae4
AttrTable::get_attr_table(const string &name)
Packit a4aae4
{
Packit a4aae4
    return find_container(name);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Get the type name of an attribute within this attribute table. */
Packit a4aae4
string AttrTable::get_type(const string &name)
Packit a4aae4
{
Packit a4aae4
    Attr_iter p = simple_find(name);
Packit a4aae4
    return (p != attr_map.end()) ? get_type(p) : (string) "";
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Get the type of an attribute.
Packit a4aae4
 @return The <tt>AttrType</tt> value describing the attribute. */
Packit a4aae4
AttrType AttrTable::get_attr_type(const string &name)
Packit a4aae4
{
Packit a4aae4
    Attr_iter p = simple_find(name);
Packit a4aae4
    return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** If the indicated attribute is a container attribute, this function
Packit a4aae4
 returns the number of attributes in its attribute table. If the
Packit a4aae4
 indicated attribute is not a container, the method returns the number
Packit a4aae4
 of values for the attribute (1 for a scalar attribute, N for a vector
Packit a4aae4
 attribute value).
Packit a4aae4
 @brief Get the number of attributes in this container.
Packit a4aae4
 */
Packit a4aae4
unsigned int AttrTable::get_attr_num(const string &name)
Packit a4aae4
{
Packit a4aae4
    Attr_iter iter = simple_find(name);
Packit a4aae4
    return (iter != attr_map.end()) ? get_attr_num(iter) : 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get a pointer to the vector of values associated with the attribute
Packit a4aae4
 referenced by Pix <tt>p</tt> or named <tt>name</tt>.
Packit a4aae4
Packit a4aae4
 Note that all values in an attribute table are stored as string data.
Packit a4aae4
 They may be converted to a more appropriate internal format by the
Packit a4aae4
 calling program.
Packit a4aae4
Packit a4aae4
 @return If the indicated attribute is a container, this function
Packit a4aae4
 returns the null pointer.  Otherwise returns a pointer to the
Packit a4aae4
 the attribute vector value.
Packit a4aae4
 @brief Get a vector-valued attribute.
Packit a4aae4
 */
Packit a4aae4
vector<string> *
Packit a4aae4
AttrTable::get_attr_vector(const string &name)
Packit a4aae4
{
Packit a4aae4
    Attr_iter p = simple_find(name);
Packit a4aae4
    return (p != attr_map.end()) ? get_attr_vector(p) : 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Delete the attribute named <tt>name</tt>. If <tt>i</tt> is given, and
Packit a4aae4
 the attribute has a vector value, delete the <tt>i</tt>$^th$
Packit a4aae4
 element of the vector.
Packit a4aae4
Packit a4aae4
 You can use this function to delete container attributes, although
Packit a4aae4
 the <tt>i</tt> parameter has no meaning for that operation.
Packit a4aae4
Packit a4aae4
 @brief Deletes an attribute.
Packit a4aae4
 @param name The name of the attribute to delete.  This can be an
Packit a4aae4
 attribute of any type, including containers. However, this method
Packit a4aae4
 looks only in this attribute table and does not recognize the dot
Packit a4aae4
 notation.
Packit a4aae4
 @param i If the named attribute is a vector, and <tt>i</tt> is
Packit a4aae4
 non-negative, the i-th entry in the vector is deleted, and the
Packit a4aae4
 array is repacked.  If <tt>i</tt> equals -1 (the default), the
Packit a4aae4
 entire attribute is deleted. */
Packit a4aae4
void AttrTable::del_attr(const string &name, int i)
Packit a4aae4
{
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
    string lname = www2id(name);
Packit a4aae4
#else
Packit a4aae4
    string lname = remove_space_encoding(name);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    Attr_iter iter = simple_find(lname);
Packit a4aae4
    if (iter != attr_map.end()) {
Packit a4aae4
        if (i == -1) { // Delete the whole attribute
Packit a4aae4
            entry *e = *iter;
Packit a4aae4
            attr_map.erase(iter);
Packit a4aae4
            delete e;
Packit a4aae4
            e = 0;
Packit a4aae4
        }
Packit a4aae4
        else { // Delete one element from attribute array
Packit a4aae4
            // Don't try to delete elements from the vector of values if the
Packit a4aae4
            // map is a container!
Packit a4aae4
            if ((*iter)->type == Attr_container)
Packit a4aae4
                return;
Packit a4aae4
Packit a4aae4
            vector<string> *sxp = (*iter)->attr;
Packit a4aae4
Packit a4aae4
            assert(i >= 0 && i < (int) sxp->size());
Packit a4aae4
            sxp->erase(sxp->begin() + i); // rm the element
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
//@} Accessors using an attribute name
Packit a4aae4
Packit a4aae4
/** @name get information using an iterator */
Packit a4aae4
//@{
Packit a4aae4
/** Get an iterator to the first entry in this attribute table.
Packit a4aae4
 @return Attr_iter; references the end of the array if empty list. */
Packit a4aae4
AttrTable::Attr_iter AttrTable::attr_begin()
Packit a4aae4
{
Packit a4aae4
    return attr_map.begin();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get an iterator to the end attribute table. Does not point to
Packit a4aae4
 the last attribute in the table
Packit a4aae4
 @return Attr_iter */
Packit a4aae4
AttrTable::Attr_iter AttrTable::attr_end()
Packit a4aae4
{
Packit a4aae4
    return attr_map.end();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Given an index \c i, return the \c Attr_iter to the corresponding
Packit a4aae4
 element. This method provides a way to use all the methods that take an
Packit a4aae4
 \c Attr_iter using a simple integer index. Use the get_attr_num() or
Packit a4aae4
 get_size() methods to determine how many items the AttrTable contains.
Packit a4aae4
Packit a4aae4
 @param i The index
Packit a4aae4
 @return The corresponding Attr_iter
Packit a4aae4
 @see get_attr_num, get_size */
Packit a4aae4
AttrTable::Attr_iter AttrTable::get_attr_iter(int i)
Packit a4aae4
{
Packit a4aae4
    return attr_map.begin() + i;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Returns the name of the attribute referenced by \e iter. */
Packit a4aae4
string AttrTable::get_name(Attr_iter iter)
Packit a4aae4
{
Packit a4aae4
    assert(iter != attr_map.end());
Packit a4aae4
Packit a4aae4
    return (*iter)->name;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Returns true if the attribute referenced by \e i is a container. */
Packit a4aae4
bool AttrTable::is_container(Attr_iter i)
Packit a4aae4
{
Packit a4aae4
    return (*i)->type == Attr_container;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get the attribute container referenced by \e iter. If no
Packit a4aae4
 such container exists, then return a reference to the end of the
Packit a4aae4
 table.
Packit a4aae4
 @param iter Reference to a table contained by this object.
Packit a4aae4
 @return The child attribute table. */
Packit a4aae4
AttrTable *
Packit a4aae4
AttrTable::get_attr_table(Attr_iter iter)
Packit a4aae4
{
Packit a4aae4
    assert(iter != attr_map.end());
Packit a4aae4
    return (*iter)->type == Attr_container ? (*iter)->attributes : 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Delete the iterator.  Since AttrTable stores pointers to AttrTable
Packit a4aae4
 objects, the caller should be sure to delete the AttrTable itself.
Packit a4aae4
 The caller will gain control of the AttrTable* located at
Packit a4aae4
 get_attr_table(iter) prior to this call.
Packit a4aae4
Packit a4aae4
 @note The original semantics of this methods were odd. The caller was
Packit a4aae4
 responsible for deleting the AttrTable, but if they did that before calling
Packit a4aae4
 this, then memory corruption would happen (because this code accesses a
Packit a4aae4
 field of the table). If the caller did not delete the table, memory leaked.
Packit a4aae4
 The only correct way to call the method was to grab the pointer, call this
Packit a4aae4
 and then delete the pointer. I added a call to delete the contained
Packit a4aae4
 AttrTable pointer, which changes the behavior of this, but probably in a
Packit a4aae4
 way that will fix leaks in existing code. This change can be reverted by
Packit a4aae4
 setting NEW_DEL_ATTR_TABLE_BEHAVIOR to false. jhrg 4/26/13
Packit a4aae4
Packit a4aae4
 @note calling this method invalidates the iterator \e iter.
Packit a4aae4
 @param iter points to the entry to be deleted.
Packit a4aae4
 @return The Attr_iter for the element following \e iter */
Packit a4aae4
AttrTable::Attr_iter AttrTable::del_attr_table(Attr_iter iter)
Packit a4aae4
{
Packit a4aae4
    if ((*iter)->type != Attr_container)
Packit a4aae4
        return ++iter;
Packit a4aae4
Packit a4aae4
    // the caller intends to delete/reuse the contained AttrTable,
Packit a4aae4
    // so zero it out so it doesn't get deleted before we delete the entry
Packit a4aae4
    // [mjohnson]
Packit a4aae4
    struct entry *e = *iter;
Packit a4aae4
    // container no longer has a parent.
Packit a4aae4
    if (e->attributes) {
Packit a4aae4
        e->attributes->d_parent = 0;
Packit a4aae4
Packit a4aae4
#if NEW_DEL_ATTR_TABLE_BEHAVIOR
Packit a4aae4
        delete e->attributes;
Packit a4aae4
#endif
Packit a4aae4
        e->attributes = 0;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    delete e;
Packit a4aae4
Packit a4aae4
    return attr_map.erase(iter);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get the type name of an attribute referenced by \e iter.
Packit a4aae4
 @param iter Reference to the Attribute.
Packit a4aae4
 @return A string with the name of this attribute datatype. */
Packit a4aae4
string AttrTable::get_type(Attr_iter iter)
Packit a4aae4
{
Packit a4aae4
    assert(iter != attr_map.end());
Packit a4aae4
    return AttrType_to_String((*iter)->type);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get the type of the attribute referenced by \e iter.
Packit a4aae4
 @param iter
Packit a4aae4
 @return The datatype of this attribute in an instance of AttrType. */
Packit a4aae4
AttrType AttrTable::get_attr_type(Attr_iter iter)
Packit a4aae4
{
Packit a4aae4
    return (*iter)->type;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** If the attribute referenced by \e iter is a container attribute, this
Packit a4aae4
 method returns the number of attributes in its attribute table.
Packit a4aae4
 If the indicated attribute is not a container, the method returns the
Packit a4aae4
 number of values for the attribute (1 for a scalar attribute, N for a
Packit a4aae4
 vector attribute value).
Packit a4aae4
 @param iter Reference to an attribute
Packit a4aae4
 @return The number of elements in the attribute. */
Packit a4aae4
unsigned int AttrTable::get_attr_num(Attr_iter iter)
Packit a4aae4
{
Packit a4aae4
    assert(iter != attr_map.end());
Packit a4aae4
    return ((*iter)->type == Attr_container) ? (*iter)->attributes->get_size() : (*iter)->attr->size();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Returns the value of an attribute. If the attribute has a vector
Packit a4aae4
 value, you can indicate which is the desired value with the index
Packit a4aae4
 argument, \e i. If the argument is omitted, the first value is
Packit a4aae4
 returned. If the attribute has only a single value, the index
Packit a4aae4
 argument is ignored. If \e i is greater than the number of
Packit a4aae4
 elements in the attribute, an error is produced.
Packit a4aae4
Packit a4aae4
 All values in an attribute table are stored as string data. They may
Packit a4aae4
 be converted to a more appropriate internal format by the calling
Packit a4aae4
 program.
Packit a4aae4
Packit a4aae4
 @param iter Reference to an attribute
Packit a4aae4
 @param i The attribute value index, zero-based. Default value: 0
Packit a4aae4
 @return If the indicated attribute is a container, this function
Packit a4aae4
 returns the string ``None''. If using a name to refer to the attribute
Packit a4aae4
 and the named attribute does not exist, return the empty string. */
Packit a4aae4
string AttrTable::get_attr(Attr_iter iter, unsigned int i)
Packit a4aae4
{
Packit a4aae4
    assert(iter != attr_map.end());
Packit a4aae4
Packit a4aae4
    return (*iter)->type == Attr_container ? (string) "None" : (*(*iter)->attr)[i];
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
string AttrTable::get_attr(const string &name, unsigned int i)
Packit a4aae4
{
Packit a4aae4
    Attr_iter p = simple_find(name);
Packit a4aae4
    return (p != attr_map.end()) ? get_attr(p, i) : (string) "";
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Returns a pointer to the vector of values associated with the
Packit a4aae4
 attribute referenced by iterator \e iter.
Packit a4aae4
Packit a4aae4
 Note that all values in an attribute table are stored as string data.
Packit a4aae4
 They may be converted to a more appropriate internal format by the
Packit a4aae4
 calling program.
Packit a4aae4
Packit a4aae4
 @param iter Reference to the Attribute.
Packit a4aae4
 @return If the indicated attribute is a container, this function
Packit a4aae4
 returns the null pointer.  Otherwise returns a pointer to the
Packit a4aae4
 the attribute vector value. */
Packit a4aae4
vector<string> *
Packit a4aae4
AttrTable::get_attr_vector(Attr_iter iter)
Packit a4aae4
{
Packit a4aae4
    assert(iter != attr_map.end());
Packit a4aae4
    return (*iter)->type != Attr_container ? (*iter)->attr : 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
bool AttrTable::is_global_attribute(Attr_iter iter)
Packit a4aae4
{
Packit a4aae4
    assert(iter != attr_map.end());
Packit a4aae4
    if ((*iter)->type == Attr_container)
Packit a4aae4
        return (*iter)->attributes->is_global_attribute();
Packit a4aae4
    else
Packit a4aae4
        return (*iter)->is_global;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void AttrTable::set_is_global_attribute(Attr_iter iter, bool ga)
Packit a4aae4
{
Packit a4aae4
    assert(iter != attr_map.end());
Packit a4aae4
    if ((*iter)->type == Attr_container)
Packit a4aae4
        (*iter)->attributes->set_is_global_attribute(ga);
Packit a4aae4
    else
Packit a4aae4
        (*iter)->is_global = ga;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
//@} Accessors that use an iterator
Packit a4aae4
Packit a4aae4
// Alias an attribute table. The alias should be added to this object.
Packit a4aae4
/** @brief Add an alias to a container held by this attribute table.
Packit a4aae4
 @param name The name of the alias. May not use dot notation.
Packit a4aae4
 @param src The existing attribute container to alias.
Packit a4aae4
 @exception Error if an attribute, container or alias called
Packit a4aae4
 <tt>name</tt> already exists in this attribute table. */
Packit a4aae4
void AttrTable::add_container_alias(const string &name, AttrTable *src)
Packit a4aae4
{
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
    string lname = www2id(name);
Packit a4aae4
#else
Packit a4aae4
    string lname = remove_space_encoding(name);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    if (simple_find(lname) != attr_end())
Packit a4aae4
        throw Error(string("There already exists a container called `") + name + string("in this attribute table. (2)"));
Packit a4aae4
Packit a4aae4
    entry *e = new entry;
Packit a4aae4
    e->name = lname;
Packit a4aae4
    e->is_alias = true;
Packit a4aae4
    e->aliased_to = src->get_name();
Packit a4aae4
    e->type = Attr_container;
Packit a4aae4
Packit a4aae4
    e->attributes = src;
Packit a4aae4
Packit a4aae4
    attr_map.push_back(e);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Assume \e source names an attribute value in some container. Add an alias
Packit a4aae4
 \e name for that value in this object.
Packit a4aae4
Packit a4aae4
 @brief Add an alias for an attribute.
Packit a4aae4
Packit a4aae4
 @param das
Packit a4aae4
 @param name The name of the alias. May not use dot notation.
Packit a4aae4
 @param source The name of the attribute to alias. May use dot
Packit a4aae4
 notation.
Packit a4aae4
 @exception Error if the attribute table already contains an
Packit a4aae4
 attribute, container or alias called <tt>name</tt> or if an
Packit a4aae4
 attribute called <tt>source</tt> does not exist. */
Packit a4aae4
void AttrTable::add_value_alias(AttrTable *das, const string &name, const string &source)
Packit a4aae4
{
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
    string lname = www2id(name);
Packit a4aae4
#else
Packit a4aae4
    string lname = remove_space_encoding(name);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
    string lsource = www2id(source);
Packit a4aae4
#else
Packit a4aae4
    string lsource = remove_space_encoding(source);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    // find the container that holds source and its (sources's) iterator
Packit a4aae4
    // within that container. Search at the uppermost level of the attribute
Packit a4aae4
    // object to find values defined `above' the current container.
Packit a4aae4
    AttrTable *at;
Packit a4aae4
    Attr_iter iter;
Packit a4aae4
    das->find(lsource, &at, &iter);
Packit a4aae4
Packit a4aae4
    // If source is not found by looking at the topmost level, look in the
Packit a4aae4
    // current table (i.e., alias z x where x is in the current container
Packit a4aae4
    // won't be found by looking for `x' at the top level). See test case 26
Packit a4aae4
    // in das-testsuite.
Packit a4aae4
    if (!at || (iter == at->attr_end()) || !*iter) {
Packit a4aae4
        find(lsource, &at, &iter);
Packit a4aae4
        if (!at || (iter == at->attr_end()) || !*iter)
Packit a4aae4
            throw Error(string("Could not find the attribute `") + source + string("' in the attribute object."));
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    // If we've got a value to alias and it's being added at the top level of
Packit a4aae4
    // the DAS, that's an error.
Packit a4aae4
    if (at && !at->is_container(iter) && this == das)
Packit a4aae4
        throw Error(
Packit a4aae4
                string(
Packit a4aae4
                        "A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS."));
Packit a4aae4
Packit a4aae4
    if (simple_find(lname) != attr_end())
Packit a4aae4
        throw Error(string("There already exists a container called `") + name + string("in this attribute table. (3)"));
Packit a4aae4
Packit a4aae4
    entry *e = new entry;
Packit a4aae4
    e->name = lname;
Packit a4aae4
    e->is_alias = true;
Packit a4aae4
    e->aliased_to = lsource;
Packit a4aae4
    e->type = get_attr_type(iter);
Packit a4aae4
    if (at && e->type == Attr_container)
Packit a4aae4
        e->attributes = at->get_attr_table(iter);
Packit a4aae4
    else
Packit a4aae4
        e->attr = (*iter)->attr;
Packit a4aae4
Packit a4aae4
    attr_map.push_back(e);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Deprecated
Packit a4aae4
/** Once an alias is
Packit a4aae4
 inserted into an attribute table, reading the attributes for
Packit a4aae4
 alias will return those stored for name.
Packit a4aae4
Packit a4aae4
 Two forms for this function exist: one searches for name
Packit a4aae4
 in the AttrTable referenced by at while the other uses
Packit a4aae4
 <tt>this</tt>. You can use <tt>DAS::get_attr_table()</tt> to
Packit a4aae4
 get the attribute table for an arbitrary name.
Packit a4aae4
Packit a4aae4
 @brief Adds an alias to the set of attributes.
Packit a4aae4
 @see get_attr_table
Packit a4aae4
 @deprecated The current alias design is flawed. It is impossible to map
Packit a4aae4
 this onto the XML implementation where the DAS and DDS information are
Packit a4aae4
 combined in one object.
Packit a4aae4
 @param alias The alias to insert into the attribute table.
Packit a4aae4
 @param name The name of the already-existing attribute to which
Packit a4aae4
 the alias will refer.
Packit a4aae4
 @param at An attribute table in which to insert the alias. */
Packit a4aae4
bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name)
Packit a4aae4
{
Packit a4aae4
    add_value_alias(at, alias, name);
Packit a4aae4
    return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @deprecated The current alias design is flawed. It is impossible to map
Packit a4aae4
 this onto the XML implementation where the DAS and DDS information are
Packit a4aae4
 combined in one object.
Packit a4aae4
Packit a4aae4
 @param alias The alias to insert into the attribute table.
Packit a4aae4
 @param name The name of the already-existing attribute to which
Packit a4aae4
 the alias will refer. */
Packit a4aae4
bool AttrTable::attr_alias(const string &alias, const string &name)
Packit a4aae4
{
Packit a4aae4
    return attr_alias(alias, this, name);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Erase the entire attribute table. This returns an AttrTable to the empty
Packit a4aae4
 state that's the same as the object generated by the null constructor.
Packit a4aae4
 @brief Erase the attribute table. */
Packit a4aae4
void AttrTable::erase()
Packit a4aae4
{
Packit a4aae4
    for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
Packit a4aae4
        delete *i;
Packit a4aae4
        *i = 0;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    attr_map.erase(attr_map.begin(), attr_map.end());
Packit a4aae4
Packit a4aae4
    d_name = "";
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
const string double_quote = "\"";
Packit a4aae4
Packit a4aae4
// This is here as a result of the problem described in ticket #1163 where
Packit a4aae4
// the data handlers are adding quotes to string attributes so the DAS will
Packit a4aae4
// be printed correctly. But that has the affect of adding the quotes to the
Packit a4aae4
// attribute's _value_ not just it's print representation. As part of the fix
Packit a4aae4
// I made the code here add the quotes if the handlers are fixed (but not if
Packit a4aae4
// handlers are still adding them). The other part of 1163 is to fix all of
Packit a4aae4
// the handlers... What this fix means is that attributes whose values really
Packit a4aae4
// do contain bracketing quotes might be misunderstood, since we're assuming
Packit a4aae4
// those quotes were added by the handlers as a hack to get the output
Packit a4aae4
// formatting correct for the DAS. jhrg 7/30/08
Packit a4aae4
Packit a4aae4
static void write_string_attribute_for_das(ostream &out, const string &value, const string &term)
Packit a4aae4
{
Packit a4aae4
    if (is_quoted(value))
Packit a4aae4
        out << value << term;
Packit a4aae4
    else
Packit a4aae4
        out << double_quote << value << double_quote << term;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
static void
Packit a4aae4
write_string_attribute_for_das(FILE *out, const string &value, const string &term)
Packit a4aae4
{
Packit a4aae4
    if (is_quoted(value))
Packit a4aae4
    fprintf(out, "%s%s", value.c_str(), term.c_str());
Packit a4aae4
    else
Packit a4aae4
    fprintf(out, "\"%s\"%s", value.c_str(), term.c_str());
Packit a4aae4
}
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
// Special treatment for XML: Make sure to escape double quotes when XML is
Packit a4aae4
// printed in a DAS.
Packit a4aae4
static void write_xml_attribute_for_das(ostream &out, const string &value, const string &term)
Packit a4aae4
{
Packit a4aae4
    if (is_quoted(value))
Packit a4aae4
        out << escape_double_quotes(value) << term;
Packit a4aae4
    else
Packit a4aae4
        out << double_quote << escape_double_quotes(value) << double_quote << term;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
static void
Packit a4aae4
write_xml_attribute_for_das(FILE *out, const string &value, const string &term)
Packit a4aae4
{
Packit a4aae4
    if (is_quoted(value))
Packit a4aae4
    fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str());
Packit a4aae4
    else
Packit a4aae4
    fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str());
Packit a4aae4
}
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
/** A simple printer that does nothing fancy with aliases.
Packit a4aae4
 Protected. */
Packit a4aae4
void AttrTable::simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
Packit a4aae4
{
Packit a4aae4
    ostringstream oss;
Packit a4aae4
    simple_print(oss, pad, i, dereference);
Packit a4aae4
    fwrite(oss.str().data(), 1, oss.str().length(), out);
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
    switch ((*i)->type) {
Packit a4aae4
        case Attr_container:
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
        fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str());
Packit a4aae4
#else
Packit a4aae4
        fprintf(out, "%s%s {\n", pad.c_str(), get_name(i).c_str());
Packit a4aae4
#endif
Packit a4aae4
        (*i)->attributes->print(out, pad + "    ", dereference);
Packit a4aae4
Packit a4aae4
        fprintf(out, "%s}\n", pad.c_str());
Packit a4aae4
        break;
Packit a4aae4
Packit a4aae4
        case Attr_string: {
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
            fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
Packit a4aae4
#else
Packit a4aae4
            fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
Packit a4aae4
#endif
Packit a4aae4
            vector<string> *sxp = (*i)->attr;
Packit a4aae4
            vector<string>::iterator last = sxp->end() - 1;
Packit a4aae4
            for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
Packit a4aae4
                write_string_attribute_for_das(out, *i, ", ");
Packit a4aae4
            }
Packit a4aae4
            write_string_attribute_for_das(out, *last, ";\n");
Packit a4aae4
        }
Packit a4aae4
        break;
Packit a4aae4
Packit a4aae4
        case Attr_other_xml: {
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
            fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
Packit a4aae4
#else
Packit a4aae4
            fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
Packit a4aae4
#endif
Packit a4aae4
            vector<string> *sxp = (*i)->attr;
Packit a4aae4
            vector<string>::iterator last = sxp->end() - 1;
Packit a4aae4
            for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
Packit a4aae4
                write_xml_attribute_for_das(out, *i, ", ");
Packit a4aae4
            }
Packit a4aae4
            write_xml_attribute_for_das(out, *last, ";\n");
Packit a4aae4
        }
Packit a4aae4
        break;
Packit a4aae4
Packit a4aae4
        default: {
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
            fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
Packit a4aae4
#else
Packit a4aae4
            fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
            vector<string> *sxp = (*i)->attr;
Packit a4aae4
            vector<string>::iterator last = sxp->end() - 1;
Packit a4aae4
            for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
Packit a4aae4
                fprintf(out, "%s%s", (*i).c_str(), ", ");
Packit a4aae4
            }
Packit a4aae4
            fprintf(out, "%s%s", (*last).c_str(), ";\n");
Packit a4aae4
        }
Packit a4aae4
        break;
Packit a4aae4
    }
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** A simple printer that does nothing fancy with aliases.
Packit a4aae4
 Protected. */
Packit a4aae4
void AttrTable::simple_print(ostream &out, string pad, Attr_iter i, bool dereference)
Packit a4aae4
{
Packit a4aae4
    switch ((*i)->type) {
Packit a4aae4
    case Attr_container:
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
        out << pad << id2www(get_name(i)) << " {\n";
Packit a4aae4
#else
Packit a4aae4
        out << pad << add_space_encoding(get_name(i)) << " {\n";
Packit a4aae4
#endif
Packit a4aae4
        (*i)->attributes->print(out, pad + "    ", dereference);
Packit a4aae4
        out << pad << "}\n";
Packit a4aae4
        break;
Packit a4aae4
Packit a4aae4
    case Attr_string: {
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
        out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
Packit a4aae4
#else
Packit a4aae4
        out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
Packit a4aae4
#endif
Packit a4aae4
        vector<string> *sxp = (*i)->attr;
Packit a4aae4
        vector<string>::iterator last = sxp->end() - 1;
Packit a4aae4
        for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
Packit a4aae4
            write_string_attribute_for_das(out, *i, ", ");
Packit a4aae4
        }
Packit a4aae4
        write_string_attribute_for_das(out, *last, ";\n");
Packit a4aae4
    }
Packit a4aae4
        break;
Packit a4aae4
Packit a4aae4
    case Attr_other_xml: {
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
        out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
Packit a4aae4
#else
Packit a4aae4
        out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
Packit a4aae4
#endif
Packit a4aae4
        vector<string> *sxp = (*i)->attr;
Packit a4aae4
        vector<string>::iterator last = sxp->end() - 1;
Packit a4aae4
        for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
Packit a4aae4
            write_xml_attribute_for_das(out, *i, ", ");
Packit a4aae4
        }
Packit a4aae4
        write_xml_attribute_for_das(out, *last, ";\n");
Packit a4aae4
    }
Packit a4aae4
        break;
Packit a4aae4
Packit a4aae4
    default: {
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
        out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
Packit a4aae4
#else
Packit a4aae4
        out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
Packit a4aae4
#endif
Packit a4aae4
        vector<string> *sxp = (*i)->attr;
Packit a4aae4
        vector<string>::iterator last = sxp->end() - 1;
Packit a4aae4
        for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
Packit a4aae4
            out << *i << ", ";
Packit a4aae4
        }
Packit a4aae4
        out << *last << ";\n";
Packit a4aae4
    }
Packit a4aae4
        break;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Prints an ASCII representation of the attribute table to the
Packit a4aae4
 indicated FILE pointer. The \c pad argument is prefixed to each
Packit a4aae4
 line of the output to provide control of indentation.
Packit a4aae4
Packit a4aae4
 @brief Prints the attribute table.
Packit a4aae4
 @param out Print to the given output FILE.
Packit a4aae4
 @param pad Indent elements of a table using this string of spaces. By
Packit a4aae4
 default this is a string of four spaces
Packit a4aae4
 @param dereference If true, follow aliases. Default is false. */
Packit a4aae4
Packit a4aae4
void AttrTable::print(FILE *out, string pad, bool dereference)
Packit a4aae4
{
Packit a4aae4
    ostringstream oss;
Packit a4aae4
    print(oss, pad, dereference);
Packit a4aae4
    fwrite(oss.str().data(), 1, oss.str().length(), out);
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
    for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
Packit a4aae4
        if ((*i)->is_alias) {
Packit a4aae4
            if (dereference) {
Packit a4aae4
                simple_print(out, pad, i, dereference);
Packit a4aae4
            }
Packit a4aae4
            else {
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
                fprintf(out, "%sAlias %s %s;\n",
Packit a4aae4
                        pad.c_str(),
Packit a4aae4
                        id2www(get_name(i)).c_str(),
Packit a4aae4
                        id2www((*i)->aliased_to).c_str());
Packit a4aae4
#else
Packit a4aae4
                fprintf(out, "%sAlias %s %s;\n",
Packit a4aae4
                        pad.c_str(), add_space_encoding(get_name(i)).c_str(), add_space_encoding((*i)->aliased_to).c_str());
Packit a4aae4
Packit a4aae4
#endif
Packit a4aae4
            }
Packit a4aae4
        }
Packit a4aae4
        else {
Packit a4aae4
            simple_print(out, pad, i, dereference);
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Prints an ASCII representation of the attribute table to the
Packit a4aae4
 indicated output stream. The \c pad argument is prefixed to each
Packit a4aae4
 line of the output to provide control of indentation.
Packit a4aae4
Packit a4aae4
 @brief Prints the attribute table.
Packit a4aae4
 @param out Print to the given output stream.
Packit a4aae4
 @param pad Indent elements of a table using this string of spaces. By
Packit a4aae4
 default this is a string of four spaces
Packit a4aae4
 @param dereference If true, follow aliases. Default is false. */
Packit a4aae4
Packit a4aae4
void AttrTable::print(ostream &out, string pad, bool dereference)
Packit a4aae4
{
Packit a4aae4
    for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
Packit a4aae4
        if ((*i)->is_alias) {
Packit a4aae4
            if (dereference) {
Packit a4aae4
                simple_print(out, pad, i, dereference);
Packit a4aae4
            }
Packit a4aae4
            else {
Packit a4aae4
#if WWW_ENCODING
Packit a4aae4
                out << pad << "Alias " << id2www(get_name(i))
Packit a4aae4
                << " " << id2www((*i)->aliased_to) << ";\n";
Packit a4aae4
#else
Packit a4aae4
                out << pad << "Alias " << add_space_encoding(get_name(i)) << " "
Packit a4aae4
                        << add_space_encoding((*i)->aliased_to) << ";\n";
Packit a4aae4
#endif
Packit a4aae4
            }
Packit a4aae4
        }
Packit a4aae4
        else {
Packit a4aae4
            simple_print(out, pad, i, dereference);
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Print the attribute table in XML.
Packit a4aae4
 @param out Destination
Packit a4aae4
 @param pad Indent lines of text/xml this much. Default is four spaces.
Packit a4aae4
 @param constrained Not used
Packit a4aae4
 @deprecated */
Packit a4aae4
void AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/)
Packit a4aae4
{
Packit a4aae4
    XMLWriter xml(pad);
Packit a4aae4
    print_xml_writer(xml);
Packit a4aae4
    fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
Packit a4aae4
Packit a4aae4
#if OLD_XML_MOETHODS
Packit a4aae4
    ostringstream oss;
Packit a4aae4
    print_xml(oss, pad);
Packit a4aae4
    fwrite(oss.str().data(), 1, oss.str().length(), out);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
    // Why this works: AttrTable is really a hacked class that used to
Packit a4aae4
    // implement a single-level set of attributes. Containers
Packit a4aae4
    // were added several years later by dropping in the 'entry' structure.
Packit a4aae4
    // It's not a class in its own right; instead accessors from AttrTable
Packit a4aae4
    // are used to access information from entry. So... the loop below
Packit a4aae4
    // actually iterates over the entries of *this* (which is an instance of
Packit a4aae4
    // AttrTable). A container is an entry whose sole value is an AttrTable
Packit a4aae4
    // instance. 05/19/03 jhrg
Packit a4aae4
    for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
Packit a4aae4
        if ((*i)->is_alias) {
Packit a4aae4
            fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n",
Packit a4aae4
                    pad.c_str(), id2xml(get_name(i)).c_str(),
Packit a4aae4
                    (*i)->aliased_to.c_str());
Packit a4aae4
Packit a4aae4
        }
Packit a4aae4
        else if (is_container(i)) {
Packit a4aae4
            fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
Packit a4aae4
                    pad.c_str(), id2xml(get_name(i)).c_str(),
Packit a4aae4
                    get_type(i).c_str());
Packit a4aae4
Packit a4aae4
            get_attr_table(i)->print_xml(out, pad + "    "/*, constrained*/);
Packit a4aae4
Packit a4aae4
            fprintf(out, "%s</Attribute>\n", pad.c_str());
Packit a4aae4
        }
Packit a4aae4
        else {
Packit a4aae4
            fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
Packit a4aae4
                    pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str());
Packit a4aae4
Packit a4aae4
            string value_pad = pad + "    ";
Packit a4aae4
            // Special handling for the OtherXML attribute type - don't escape
Packit a4aae4
            // the XML and don't include the <value> element. Note that there
Packit a4aae4
            // cannot be an vector of XML things as can be with the other types.
Packit a4aae4
            if (get_attr_type(i) == Attr_other_xml) {
Packit a4aae4
                if (get_attr_num(i) != 1)
Packit a4aae4
                throw Error("OtherXML attributes cannot be vector-valued.");
Packit a4aae4
                fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str());
Packit a4aae4
            }
Packit a4aae4
            else {
Packit a4aae4
                for (unsigned j = 0; j < get_attr_num(i); ++j) {
Packit a4aae4
                    fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(),
Packit a4aae4
                            id2xml(get_attr(i, j)).c_str());
Packit a4aae4
                }
Packit a4aae4
            }
Packit a4aae4
            fprintf(out, "%s</Attribute>\n", pad.c_str());
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * @deprecated
Packit a4aae4
 */
Packit a4aae4
void AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/)
Packit a4aae4
{
Packit a4aae4
    XMLWriter xml(pad);
Packit a4aae4
    print_xml_writer(xml);
Packit a4aae4
    out << xml.get_doc();
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
    for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
Packit a4aae4
        if ((*i)->is_alias) {
Packit a4aae4
            out << pad << "
Packit a4aae4
            << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n";
Packit a4aae4
Packit a4aae4
        }
Packit a4aae4
        else if (is_container(i)) {
Packit a4aae4
            out << pad << "
Packit a4aae4
            << "\" type=\"" << get_type(i) << "\">\n";
Packit a4aae4
Packit a4aae4
            get_attr_table(i)->print_xml(out, pad + "    "/*, constrained*/);
Packit a4aae4
Packit a4aae4
            out << pad << "</Attribute>\n";
Packit a4aae4
        }
Packit a4aae4
        else {
Packit a4aae4
            out << pad << "
Packit a4aae4
            << "\" type=\"" << get_type(i) << "\">\n";
Packit a4aae4
Packit a4aae4
            string value_pad = pad + "    ";
Packit a4aae4
            if (get_attr_type(i) == Attr_other_xml) {
Packit a4aae4
                if (get_attr_num(i) != 1)
Packit a4aae4
                throw Error("OtherXML attributes cannot be vector-valued.");
Packit a4aae4
                out << value_pad << get_attr(i, 0) << "\n";
Packit a4aae4
            }
Packit a4aae4
            else {
Packit a4aae4
                string value_pad = pad + "    ";
Packit a4aae4
                for (unsigned j = 0; j < get_attr_num(i); ++j) {
Packit a4aae4
                    out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n";
Packit a4aae4
                }
Packit a4aae4
            }
Packit a4aae4
            out << pad << "</Attribute>\n";
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Print the attribute table in XML.
Packit a4aae4
 @param out Destination stream
Packit a4aae4
 @param pad Indent lines of text/xml this much. Default is four spaces.
Packit a4aae4
 @param constrained Not used */
Packit a4aae4
void AttrTable::print_xml_writer(XMLWriter &xml)
Packit a4aae4
{
Packit a4aae4
    for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
Packit a4aae4
        if ((*i)->is_alias) {
Packit a4aae4
            if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Alias") < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write Alias element");
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
Packit a4aae4
                    (const xmlChar*) get_name(i).c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "Attribute",
Packit a4aae4
                    (const xmlChar*) (*i)->aliased_to.c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
            if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not end Alias element");
Packit a4aae4
        }
Packit a4aae4
        else if (is_container(i)) {
Packit a4aae4
            if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
Packit a4aae4
                    (const xmlChar*) get_name(i).c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
Packit a4aae4
                    (const xmlChar*) get_type(i).c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
Packit a4aae4
            get_attr_table(i)->print_xml_writer(xml);
Packit a4aae4
Packit a4aae4
            if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
Packit a4aae4
        }
Packit a4aae4
        else {
Packit a4aae4
            if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
Packit a4aae4
                    (const xmlChar*) get_name(i).c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
Packit a4aae4
                    (const xmlChar*) get_type(i).c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
Packit a4aae4
            if (get_attr_type(i) == Attr_other_xml) {
Packit a4aae4
                if (get_attr_num(i) != 1)
Packit a4aae4
                    throw Error("OtherXML attributes cannot be vector-valued.");
Packit a4aae4
                // Replaced xmltextWriterWriteString with xmlTextWriterWriteRaw to keep the
Packit a4aae4
                // libxml2 code from escaping the xml (which was breaking all of the inferencing
Packit a4aae4
                // code. jhrg
Packit a4aae4
                if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) get_attr(i, 0).c_str()) < 0)
Packit a4aae4
                    throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
Packit a4aae4
            }
Packit a4aae4
            else {
Packit a4aae4
                for (unsigned j = 0; j < get_attr_num(i); ++j) {
Packit a4aae4
                    if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "value") < 0)
Packit a4aae4
                        throw InternalErr(__FILE__, __LINE__, "Could not write value element");
Packit a4aae4
Packit a4aae4
                    if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) get_attr(i, j).c_str()) < 0)
Packit a4aae4
                        throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
Packit a4aae4
Packit a4aae4
                    if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
                        throw InternalErr(__FILE__, __LINE__, "Could not end value element");
Packit a4aae4
                }
Packit a4aae4
            }
Packit a4aae4
            if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Write the DAP4 XML representation for this attribute table. This
Packit a4aae4
 * method is used to build the DAP4 DMR response object.
Packit a4aae4
 *
Packit a4aae4
 * @param xml An XMLWriter that will do the serialization
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
AttrTable::print_dap4(XMLWriter &xml)
Packit a4aae4
{
Packit a4aae4
    print_xml_writer(xml);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief dumps information about this object
Packit a4aae4
 *
Packit a4aae4
 * Displays the pointer value of this instance and all attributes stored
Packit a4aae4
 *
Packit a4aae4
 * @param strm C++ i/o stream to dump the information to
Packit a4aae4
 * @return void
Packit a4aae4
 */
Packit a4aae4
void AttrTable::dump(ostream &strm) const
Packit a4aae4
{
Packit a4aae4
    strm << DapIndent::LMarg << "AttrTable::dump - (" << (void *) this << ")" << endl;
Packit a4aae4
    DapIndent::Indent();
Packit a4aae4
    strm << DapIndent::LMarg << "table name: " << d_name << endl;
Packit a4aae4
    if (attr_map.size()) {
Packit a4aae4
        strm << DapIndent::LMarg << "attributes: " << endl;
Packit a4aae4
        DapIndent::Indent();
Packit a4aae4
        Attr_citer i = attr_map.begin();
Packit a4aae4
        Attr_citer ie = attr_map.end();
Packit a4aae4
        for (; i != ie; ++i) {
Packit a4aae4
            entry *e = (*i);
Packit a4aae4
            string type = AttrType_to_String(e->type);
Packit a4aae4
            if (e->is_alias) {
Packit a4aae4
                strm << DapIndent::LMarg << "alias: " << e->name << " aliased to: " << e->aliased_to << endl;
Packit a4aae4
            }
Packit a4aae4
            else if (e->type == Attr_container) {
Packit a4aae4
                strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
Packit a4aae4
                DapIndent::Indent();
Packit a4aae4
                e->attributes->dump(strm);
Packit a4aae4
                DapIndent::UnIndent();
Packit a4aae4
            }
Packit a4aae4
            else {
Packit a4aae4
                strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
Packit a4aae4
                DapIndent::Indent();
Packit a4aae4
                strm << DapIndent::LMarg;
Packit a4aae4
                vector<string>::const_iterator iter = e->attr->begin();
Packit a4aae4
                vector<string>::const_iterator last = e->attr->end() - 1;
Packit a4aae4
                for (; iter != last; ++iter) {
Packit a4aae4
                    strm << (*iter) << ", ";
Packit a4aae4
                }
Packit a4aae4
                strm << (*(e->attr->end() - 1)) << endl;
Packit a4aae4
                DapIndent::UnIndent();
Packit a4aae4
            }
Packit a4aae4
        }
Packit a4aae4
        DapIndent::UnIndent();
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        strm << DapIndent::LMarg << "attributes: empty" << endl;
Packit a4aae4
    }
Packit a4aae4
    if (d_parent) {
Packit a4aae4
        strm << DapIndent::LMarg << "parent table:" << d_name << ":" << (void *) d_parent << endl;
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        strm << DapIndent::LMarg << "parent table: none" << d_name << endl;
Packit a4aae4
    }
Packit a4aae4
    DapIndent::UnIndent();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
} // namespace libdap
Packit a4aae4