Blame DDS.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
//
Packit a4aae4
// jhrg 9/7/94
Packit a4aae4
Packit a4aae4
#include "config.h"
Packit a4aae4
Packit a4aae4
#include <cstdio>
Packit a4aae4
#include <cmath>
Packit a4aae4
#include <sys/types.h>
Packit a4aae4
Packit a4aae4
#ifdef WIN32
Packit a4aae4
#include <io.h>
Packit a4aae4
#include <process.h>
Packit a4aae4
#include <fstream>
Packit a4aae4
#else
Packit a4aae4
#include <unistd.h>    // for alarm and dup
Packit a4aae4
#include <sys/wait.h>
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
#include <iostream>
Packit a4aae4
#include <sstream>
Packit a4aae4
#include <algorithm>
Packit a4aae4
#include <functional>
Packit a4aae4
Packit a4aae4
// #define DODS_DEBUG
Packit a4aae4
//#define DODS_DEBUG2
Packit a4aae4
Packit a4aae4
#include "GNURegex.h"
Packit a4aae4
Packit a4aae4
#include "DAS.h"
Packit a4aae4
#include "Clause.h"
Packit a4aae4
#include "Error.h"
Packit a4aae4
#include "InternalErr.h"
Packit a4aae4
#include "Keywords2.h"
Packit a4aae4
Packit a4aae4
#include "parser.h"
Packit a4aae4
#include "debug.h"
Packit a4aae4
#include "util.h"
Packit a4aae4
Packit a4aae4
#include "Byte.h"
Packit a4aae4
#include "Int16.h"
Packit a4aae4
#include "UInt16.h"
Packit a4aae4
#include "Int32.h"
Packit a4aae4
#include "UInt32.h"
Packit a4aae4
#include "Float32.h"
Packit a4aae4
#include "Float64.h"
Packit a4aae4
#include "Str.h"
Packit a4aae4
#include "Url.h"
Packit a4aae4
#include "Array.h"
Packit a4aae4
#include "Structure.h"
Packit a4aae4
#include "Sequence.h"
Packit a4aae4
#include "Grid.h"
Packit a4aae4
Packit a4aae4
#include "escaping.h"
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * ############################################################################################
Packit a4aae4
 * ############################################################################################
Packit a4aae4
 * ############################################################################################
Packit a4aae4
 * DapXmlNamespaces
Packit a4aae4
 *
Packit a4aae4
 * FIXME Replace all usages of the following variable with calls to DapXmlNamespaces
Packit a4aae4
 * TODO  Replace all usages of the following variable with calls to DapXmlNamespaces
Packit a4aae4
 *
Packit a4aae4
 */
Packit a4aae4
const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
Packit a4aae4
const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
Packit a4aae4
Packit a4aae4
const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
Packit a4aae4
Packit a4aae4
const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
Packit a4aae4
const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
Packit a4aae4
const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
Packit a4aae4
Packit a4aae4
const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
Packit a4aae4
const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
Packit a4aae4
const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
Packit a4aae4
Packit a4aae4
const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
Packit a4aae4
const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
Packit a4aae4
const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
Packit a4aae4
/**
Packit a4aae4
 *
Packit a4aae4
 * DapXmlNamespaces
Packit a4aae4
 * ############################################################################################
Packit a4aae4
 * ############################################################################################
Packit a4aae4
 * ############################################################################################
Packit a4aae4
 */
Packit a4aae4
Packit a4aae4
Packit a4aae4
Packit a4aae4
using namespace std;
Packit a4aae4
Packit a4aae4
int ddsparse(libdap::parser_arg *arg);
Packit a4aae4
Packit a4aae4
// Glue for the DDS parser defined in dds.lex
Packit a4aae4
void dds_switch_to_buffer(void *new_buffer);
Packit a4aae4
void dds_delete_buffer(void * buffer);
Packit a4aae4
void *dds_buffer(FILE *fp);
Packit a4aae4
Packit a4aae4
namespace libdap {
Packit a4aae4
Packit a4aae4
void
Packit a4aae4
DDS::duplicate(const DDS &dds)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Entering DDS::duplicate... " <
Packit a4aae4
#if 0
Packit a4aae4
    BaseTypeFactory *d_factory;
Packit a4aae4
Packit a4aae4
    string d_name;                // The dataset d_name
Packit a4aae4
    string d_filename;          // File d_name (or other OS identifier) for
Packit a4aae4
    string d_container_name;    // d_name of container structure
Packit a4aae4
    Structure *d_container;     // current container for container d_name
Packit a4aae4
                                // dataset or part of dataset.
Packit a4aae4
Packit a4aae4
    int d_dap_major;            // The protocol major version number
Packit a4aae4
    int d_dap_minor;            // ... and minor version number
Packit a4aae4
    string d_dap_version;       // String version of the protocol
Packit a4aae4
    string d_request_xml_base;
Packit a4aae4
    string d_namespace;
Packit a4aae4
Packit a4aae4
    AttrTable d_attr;           // Global attributes.
Packit a4aae4
Packit a4aae4
    vector<BaseType *> vars;    // Variables at the top level
Packit a4aae4
Packit a4aae4
    int d_timeout;              // alarm time in seconds. If greater than
Packit a4aae4
                                // zero, raise the alarm signal if more than
Packit a4aae4
                                // d_timeout seconds are spent reading data.
Packit a4aae4
    Keywords d_keywords;        // Holds keywords parsed from the CE
Packit a4aae4
Packit a4aae4
    long d_max_response_size;   // In bytes
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    d_factory = dds.d_factory;
Packit a4aae4
Packit a4aae4
    d_name = dds.d_name;
Packit a4aae4
    d_filename = dds.d_filename;
Packit a4aae4
    d_container_name = dds.d_container_name;
Packit a4aae4
    d_container = dds.d_container;
Packit a4aae4
Packit a4aae4
    d_dap_major = dds.d_dap_major;
Packit a4aae4
    d_dap_minor = dds.d_dap_minor;
Packit a4aae4
Packit a4aae4
    d_dap_version = dds.d_dap_version;       // String version of the protocol
Packit a4aae4
    d_request_xml_base = dds.d_request_xml_base;
Packit a4aae4
    d_namespace = dds.d_namespace;
Packit a4aae4
Packit a4aae4
    d_attr = dds.d_attr;
Packit a4aae4
Packit a4aae4
    DDS &dds_tmp = const_cast<DDS &>(dds);
Packit a4aae4
Packit a4aae4
    // copy the things pointed to by the list, not just the pointers
Packit a4aae4
    for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
Packit a4aae4
        add_var(*i); // add_var() dups the BaseType.
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    d_timeout = dds.d_timeout;
Packit a4aae4
Packit a4aae4
    d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
Packit a4aae4
Packit a4aae4
    d_max_response_size = dds.d_max_response_size;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * Make a DDS which uses the given BaseTypeFactory to create variables.
Packit a4aae4
 *
Packit a4aae4
 * @note The default DAP version is 3.2 - this is really DAP2 with a handful
Packit a4aae4
 * of enhancements that our WCS software relies on.
Packit a4aae4
 *
Packit a4aae4
 * @param factory The BaseTypeFactory to use when creating instances of
Packit a4aae4
 * DAP variables. The caller must ensure the factory's lifetime is at least
Packit a4aae4
 * that of the DDS instance.
Packit a4aae4
 * @param name The name of the DDS - usually derived from the name of the
Packit a4aae4
 * pathname or table name of the dataset.
Packit a4aae4
 */
Packit a4aae4
DDS::DDS(BaseTypeFactory *factory, const string &name)
Packit a4aae4
        : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
Packit a4aae4
          d_request_xml_base(""),
Packit a4aae4
          d_timeout(0), d_keywords(), d_max_response_size(0)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Building a DDS for the default version (2.0)" << endl);
Packit a4aae4
Packit a4aae4
    // This method sets a number of values, including those returned by
Packit a4aae4
    // get_protocol_major(), ..., get_namespace().
Packit a4aae4
    set_dap_version("2.0");
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * Make a DDS with the DAP protocol set to a specific value. This method
Packit a4aae4
 * provides an easy way to build DDS objects for use in a server or client
Packit a4aae4
 * that will process DAP4, for example. It's roughly equivalent to calling
Packit a4aae4
 * set_dap_version() after making an instance using
Packit a4aae4
 * DDS::DDS(BaseTypeFactory *, const string &).
Packit a4aae4
 *
Packit a4aae4
 * @param factory The BaseTypeFactory to use when creating instances of
Packit a4aae4
 * DAP variables. The caller must ensure the factory's lifetime is at least
Packit a4aae4
 * that of the DDS instance.
Packit a4aae4
 * @param name The name of the DDS - usually derived from the name of the
Packit a4aae4
 * pathname or table name of the dataset.
Packit a4aae4
 * @param version The DAP version to support. This sets the DAP version, as
Packit a4aae4
 * well as a number of other dependent constants.
Packit a4aae4
 */
Packit a4aae4
DDS::DDS(BaseTypeFactory *factory, const string &name, const string &version)
Packit a4aae4
        : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
Packit a4aae4
          d_request_xml_base(""),
Packit a4aae4
          d_timeout(0), d_keywords(), d_max_response_size(0)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Building a DDS for version: " << version << endl);
Packit a4aae4
Packit a4aae4
    // This method sets a number of values, including those returned by
Packit a4aae4
    // get_protocol_major(), ..., get_namespace().
Packit a4aae4
    set_dap_version(version);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** The DDS copy constructor. */
Packit a4aae4
DDS::DDS(const DDS &rhs) : DapObj()
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
Packit a4aae4
    duplicate(rhs);
Packit a4aae4
    DBG(cerr << " bye." << endl);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
DDS::~DDS()
Packit a4aae4
{
Packit a4aae4
    // delete all the variables in this DDS
Packit a4aae4
    for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
        BaseType *btp = *i ;
Packit a4aae4
        delete btp ; btp = 0;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
DDS &
Packit a4aae4
DDS::operator=(const DDS &rhs)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Entering DDS::operator= ..." << endl);
Packit a4aae4
    if (this == &rhs)
Packit a4aae4
        return *this;
Packit a4aae4
Packit a4aae4
    duplicate(rhs);
Packit a4aae4
Packit a4aae4
    DBG(cerr << " bye." << endl);
Packit a4aae4
    return *this;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * This is the main method used to transfer attributes from a DAS object into a
Packit a4aae4
 * DDS. This uses the BaseType::transfer_attributes() method and the various
Packit a4aae4
 * implementations found here (in the constructors classes) and in handlers.
Packit a4aae4
 *
Packit a4aae4
 * This method uses a deep copy to transfer the attributes, so it is safe to
Packit a4aae4
 * delete the source DAS object passed to this method once it is done.
Packit a4aae4
 *
Packit a4aae4
 * @note To accommodate oddly built DAS objects produced by various handlers,
Packit a4aae4
 * specialize the methods there.
Packit a4aae4
 *
Packit a4aae4
 * @param das Transfer (copy) attributes from this DAS object.
Packit a4aae4
 */
Packit a4aae4
void DDS::transfer_attributes(DAS *das)
Packit a4aae4
{
Packit a4aae4
    // If there is a container set in the DDS then check the container from
Packit a4aae4
    // the DAS. If they are not the same container, then throw an exception
Packit a4aae4
    // (should be working on the same container). If the container does not
Packit a4aae4
    // exist in the DAS, then throw an exception
Packit a4aae4
    if (d_container && das->container_name() != d_container_name)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__,
Packit a4aae4
                "Error transferring attributes: working on a container in dds, but not das");
Packit a4aae4
Packit a4aae4
    // Give each variable a chance to claim its attributes.
Packit a4aae4
    AttrTable *top = das->get_top_level_attributes();
Packit a4aae4
Packit a4aae4
    for (DDS::Vars_iter i = var_begin(), e = var_end(); i != e; i++) {
Packit a4aae4
        (*i)->transfer_attributes(top);
Packit a4aae4
    }
Packit a4aae4
#if 0
Packit a4aae4
    Vars_iter var = var_begin();
Packit a4aae4
    while (var != var_end()) {
Packit a4aae4
        try {
Packit a4aae4
            DBG(cerr << "Processing the attributes for: " << (*var)->d_name() << " a " << (*var)->type_name() << endl);
Packit a4aae4
            (*var)->transfer_attributes(top);
Packit a4aae4
            var++;
Packit a4aae4
        }
Packit a4aae4
        catch (Error &e) {
Packit a4aae4
            DBG(cerr << "Got this exception: " << e.get_error_message() << endl);
Packit a4aae4
            var++;
Packit a4aae4
            throw e;
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
#endif
Packit a4aae4
    // Now we transfer all of the attributes still marked as global to the
Packit a4aae4
    // global container in the DDS.
Packit a4aae4
    for (AttrTable::Attr_iter i = top->attr_begin(), e = top->attr_end(); i != e; ++i) {
Packit a4aae4
        if ((*i)->type == Attr_container && (*i)->attributes->is_global_attribute()) {
Packit a4aae4
            // copy the source container so that the DAS passed in can be
Packit a4aae4
            // deleted after calling this method.
Packit a4aae4
            AttrTable *at = new AttrTable(*(*i)->attributes);
Packit a4aae4
            d_attr.append_container(at, at->get_name());
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
#if 0
Packit a4aae4
    AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
Packit a4aae4
    while (at_cont_p != top_level->attr_end()) {
Packit a4aae4
        // In truth, all of the top level attributes should be containers, but
Packit a4aae4
        // this test handles the abnormal case where somehow someone makes a
Packit a4aae4
        // top level attribute that is not a container by silently dropping it.
Packit a4aae4
        if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) {
Packit a4aae4
            DBG(cerr << (*at_cont_p)->d_name << " is a global attribute." << endl);
Packit a4aae4
            // copy the source container so that the DAS passed in can be
Packit a4aae4
            // deleted after calling this method.
Packit a4aae4
            AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
Packit a4aae4
            d_attr.append_container(at, at->get_name());
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        at_cont_p++;
Packit a4aae4
    }
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get and set the dataset's d_name.  This is the d_name of the dataset
Packit a4aae4
    itself, and is not to be confused with the d_name of the file or
Packit a4aae4
    disk on which it is stored.
Packit a4aae4
Packit a4aae4
    @d_name Dataset Name Accessors */
Packit a4aae4
Packit a4aae4
//@{
Packit a4aae4
Packit a4aae4
/** Returns the dataset's d_name. */
Packit a4aae4
string
Packit a4aae4
DDS::get_dataset_name() const
Packit a4aae4
{
Packit a4aae4
    return d_name;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Sets the dataset d_name. */
Packit a4aae4
void
Packit a4aae4
DDS::set_dataset_name(const string &n)
Packit a4aae4
{
Packit a4aae4
    d_name = n;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
//@}
Packit a4aae4
Packit a4aae4
/** Get the attribute table for the global attributes. */
Packit a4aae4
AttrTable &
Packit a4aae4
DDS::get_attr_table()
Packit a4aae4
{
Packit a4aae4
    return d_attr;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get and set the dataset's filename. This is the physical
Packit a4aae4
    location on a disk where the dataset exists.  The dataset d_name
Packit a4aae4
    is simply a title.
Packit a4aae4
Packit a4aae4
    @d_name File Name Accessor
Packit a4aae4
    @see Dataset Name Accessors */
Packit a4aae4
Packit a4aae4
//@{
Packit a4aae4
/** Gets the dataset file d_name. */
Packit a4aae4
string
Packit a4aae4
DDS::filename() const
Packit a4aae4
{
Packit a4aae4
    return d_filename;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Set the dataset's filename. */
Packit a4aae4
void
Packit a4aae4
DDS::filename(const string &fn)
Packit a4aae4
{
Packit a4aae4
    d_filename = fn;
Packit a4aae4
}
Packit a4aae4
//@}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * @deprecated
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::set_dap_major(int p)
Packit a4aae4
{
Packit a4aae4
    d_dap_major = p;
Packit a4aae4
Packit a4aae4
    // This works because regardless of the order set_dap_major and set_dap_minor
Packit a4aae4
    // are called, once they both are called, the value in the string is
Packit a4aae4
    // correct. I protect against negative numbers because that would be
Packit a4aae4
    // nonsensical.
Packit a4aae4
    if (d_dap_minor >= 0) {
Packit a4aae4
	ostringstream oss;
Packit a4aae4
	oss << d_dap_major << "." << d_dap_minor;
Packit a4aae4
	d_dap_version = oss.str();
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * @deprecated
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::set_dap_minor(int p)
Packit a4aae4
{
Packit a4aae4
    d_dap_minor = p;
Packit a4aae4
Packit a4aae4
    if (d_dap_major >= 0) {
Packit a4aae4
	ostringstream oss;
Packit a4aae4
	oss << d_dap_major << "." << d_dap_minor;
Packit a4aae4
	d_dap_version = oss.str();
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * Given the DAP protocol version, parse that string and set the DDS fields.
Packit a4aae4
 *
Packit a4aae4
 * @param v The version string.
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::set_dap_version(const string &v /* = "2.0" */)
Packit a4aae4
{
Packit a4aae4
    istringstream iss(v);
Packit a4aae4
Packit a4aae4
    int major = -1, minor = -1;
Packit a4aae4
    char dot;
Packit a4aae4
    if (!iss.eof() && !iss.fail())
Packit a4aae4
        iss >> major;
Packit a4aae4
    if (!iss.eof() && !iss.fail())
Packit a4aae4
        iss >> dot;
Packit a4aae4
    if (!iss.eof() && !iss.fail())
Packit a4aae4
        iss >> minor;
Packit a4aae4
Packit a4aae4
    if (major == -1 || minor == -1 or dot != '.')
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
Packit a4aae4
Packit a4aae4
    d_dap_version = v;
Packit a4aae4
Packit a4aae4
    d_dap_major = major;
Packit a4aae4
    d_dap_minor = minor;
Packit a4aae4
Packit a4aae4
    // Now set the related XML constants. These might be overwritten if
Packit a4aae4
    // the DDS instance is being built from a document parse, but if it's
Packit a4aae4
    // being constructed by a server the code to generate the XML document
Packit a4aae4
    // needs these values to match the DAP version information.
Packit a4aae4
    switch (d_dap_major) {
Packit a4aae4
        case 2:
Packit a4aae4
            d_namespace = c_dap20_namespace;
Packit a4aae4
            break;
Packit a4aae4
        case 3:
Packit a4aae4
            d_namespace = c_dap32_namespace;
Packit a4aae4
            break;
Packit a4aae4
        case 4:
Packit a4aae4
            d_namespace = c_dap40_namespace;
Packit a4aae4
            break;
Packit a4aae4
        default:
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Unknown DAP version.");
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Old way to set the DAP version.
Packit a4aae4
 *
Packit a4aae4
 * @note Don't use this - two interfaces to set the version number is overkill
Packit a4aae4
 *
Packit a4aae4
 * @param d The protocol version requested by the client, as a double.
Packit a4aae4
 * @deprecated
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::set_dap_version(double d)
Packit a4aae4
{
Packit a4aae4
    int major = floor(d);
Packit a4aae4
    int minor = (d-major)*10;
Packit a4aae4
Packit a4aae4
    DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
Packit a4aae4
Packit a4aae4
    ostringstream oss;
Packit a4aae4
    oss << major << "." << minor;
Packit a4aae4
Packit a4aae4
    set_dap_version(oss.str());
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get and set the current container. If there are multiple files being
Packit a4aae4
    used to build this DDS, using a container will set a virtual structure
Packit a4aae4
    for the current container.
Packit a4aae4
Packit a4aae4
    @d_name Container Name Accessor
Packit a4aae4
    @see Dataset Name Accessors */
Packit a4aae4
Packit a4aae4
//@{
Packit a4aae4
/** Gets the dataset file d_name. */
Packit a4aae4
string
Packit a4aae4
DDS::container_name()
Packit a4aae4
{
Packit a4aae4
    return d_container_name;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Set the current container d_name and get or create a structure for that
Packit a4aae4
 * d_name. */
Packit a4aae4
void
Packit a4aae4
DDS::container_name(const string &cn)
Packit a4aae4
{
Packit a4aae4
    // we want to search the DDS for the top level structure with the given
Packit a4aae4
    // d_name. Set the container to null so that we don't search some previous
Packit a4aae4
    // container.
Packit a4aae4
    d_container = 0 ;
Packit a4aae4
    if( !cn.empty() )
Packit a4aae4
    {
Packit a4aae4
	d_container = dynamic_cast<Structure *>( var( cn ) ) ;
Packit a4aae4
	if( !d_container )
Packit a4aae4
	{
Packit a4aae4
	    // create a structure for this container. Calling add_var
Packit a4aae4
	    // while_container is null will add the new structure to DDS and
Packit a4aae4
	    // not some sub structure. Adding the new structure makes a copy
Packit a4aae4
	    // of it.  So after adding it, go get it and set d_container.
Packit a4aae4
	    Structure *s = new Structure( cn ) ;
Packit a4aae4
	    add_var( s ) ;
Packit a4aae4
	    delete s ;
Packit a4aae4
	    s = 0 ;
Packit a4aae4
	    d_container = dynamic_cast<Structure *>( var( cn ) ) ;
Packit a4aae4
	}
Packit a4aae4
    }
Packit a4aae4
    d_container_name = cn;
Packit a4aae4
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get the current container structure. */
Packit a4aae4
Structure *
Packit a4aae4
DDS::container()
Packit a4aae4
{
Packit a4aae4
    return d_container ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
//@}
Packit a4aae4
Packit a4aae4
/** Get the size of a response. This method looks at the variables in the DDS
Packit a4aae4
 *  a computes the number of bytes in the response.
Packit a4aae4
 *
Packit a4aae4
 *  @note This version of the method does a poor job with Sequences. A better
Packit a4aae4
 *  implementation would look at row-constraint-based limitations and use them
Packit a4aae4
 *  for size computations. If a row-constraint is missing, return an error.
Packit a4aae4
 *
Packit a4aae4
 *  @param constrained Should the size of the whole DDS be used or should the
Packit a4aae4
 *  current constraint be taken into account?
Packit a4aae4
 */
Packit a4aae4
int
Packit a4aae4
DDS::get_request_size(bool constrained)
Packit a4aae4
{
Packit a4aae4
	int w = 0;
Packit a4aae4
    for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
    	if (constrained) {
Packit a4aae4
    		if ((*i)->send_p())
Packit a4aae4
    			w += (*i)->width(constrained);
Packit a4aae4
    	}
Packit a4aae4
    	else {
Packit a4aae4
    		w += (*i)->width(constrained);
Packit a4aae4
    	}
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    return w;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Adds a copy of the variable to the DDS.
Packit a4aae4
    Using the ptr_duplicate() method, perform a deep copy on the variable
Packit a4aae4
    \e bt and adds the result to this DDS.
Packit a4aae4
    @note The copy will not copy data values.
Packit a4aae4
    @param bt Source variable. */
Packit a4aae4
void DDS::add_var(BaseType *bt) {
Packit a4aae4
    if (!bt)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
Packit a4aae4
#if 0
Packit a4aae4
    if (bt->is_dap4_only_type())
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
Packit a4aae4
#endif
Packit a4aae4
    DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
Packit a4aae4
Packit a4aae4
    BaseType *btp = bt->ptr_duplicate();
Packit a4aae4
    DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
Packit a4aae4
    if (d_container) {
Packit a4aae4
        // Mem leak fix [mjohnson nov 2009]
Packit a4aae4
        // Structure::add_var() creates ANOTHER copy.
Packit a4aae4
        d_container->add_var(bt);
Packit a4aae4
        // So we need to delete btp or else it leaks
Packit a4aae4
        delete btp;
Packit a4aae4
        btp = 0;
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        vars.push_back(btp);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Adds the variable to the DDS.
Packit a4aae4
    @param bt Source variable. */
Packit a4aae4
void
Packit a4aae4
DDS::add_var_nocopy(BaseType *bt)
Packit a4aae4
{
Packit a4aae4
    if (!bt)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
Packit a4aae4
#if 0
Packit a4aae4
    //FIXME There's no longer a DAP2 and DAP4 DDS
Packit a4aae4
    if (bt->is_dap4_only_type())
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
Packit a4aae4
Packit a4aae4
    if (d_container) {
Packit a4aae4
        d_container->add_var_nocopy(bt);
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        vars.push_back(bt);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
Packit a4aae4
/** Remove the named variable from the DDS. This method is not smart about
Packit a4aae4
    looking up names. The variable must exist at the top level of the DDS and
Packit a4aae4
    must match \e exactly the d_name given.
Packit a4aae4
Packit a4aae4
    @note Invalidates any iterators that reference the contents of the DDS.
Packit a4aae4
    @param n The d_name of the variable to remove. */
Packit a4aae4
void
Packit a4aae4
DDS::del_var(const string &n)
Packit a4aae4
{
Packit a4aae4
    if( d_container )
Packit a4aae4
    {
Packit a4aae4
	d_container->del_var( n ) ;
Packit a4aae4
	return ;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
        if ((*i)->name() == n) {
Packit a4aae4
            BaseType *bt = *i ;
Packit a4aae4
            vars.erase(i) ;
Packit a4aae4
            delete bt ; bt = 0;
Packit a4aae4
            return;
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Remove the variable referenced by the iterator and free its storage.
Packit a4aae4
Packit a4aae4
    @note Invalidates any iterators that reference the contents of the DDS.
Packit a4aae4
    @param i The Vars_iter which refers to the variable. */
Packit a4aae4
void
Packit a4aae4
DDS::del_var(Vars_iter i)
Packit a4aae4
{
Packit a4aae4
    if (i != vars.end()) {
Packit a4aae4
        BaseType *bt = *i ;
Packit a4aae4
        vars.erase(i) ;
Packit a4aae4
        delete bt ; bt = 0;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Remove the variables referenced by the range of iterators and free their
Packit a4aae4
    storage.
Packit a4aae4
Packit a4aae4
    @note Invalidates any iterators that reference the contents of the DDS.
Packit a4aae4
    @param i1 The start of the range.
Packit a4aae4
    @param i2 The end of the range. */
Packit a4aae4
void
Packit a4aae4
DDS::del_var(Vars_iter i1, Vars_iter i2)
Packit a4aae4
{
Packit a4aae4
    for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
Packit a4aae4
        BaseType *bt = *i_tmp ;
Packit a4aae4
        delete bt ; bt = 0;
Packit a4aae4
    }
Packit a4aae4
    vars.erase(i1, i2) ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Search for for variable n as above but record all
Packit a4aae4
    compound type variables which ultimately contain n on
Packit a4aae4
    s. This stack can then be used to mark the contained
Packit a4aae4
    compound-type variables as part of the current projection.
Packit a4aae4
Packit a4aae4
    @return A BaseType pointer to the variable n or 0 if n
Packit a4aae4
    could not be found. */
Packit a4aae4
BaseType *
Packit a4aae4
DDS::var(const string &n, BaseType::btp_stack &s)
Packit a4aae4
{
Packit a4aae4
    return var(n, &s);
Packit a4aae4
}
Packit a4aae4
/** @brief Find the variable with the given d_name.
Packit a4aae4
Packit a4aae4
    Returns a pointer to the named variable. If the d_name contains one or
Packit a4aae4
    more field separators then the function looks for a variable whose
Packit a4aae4
    name matches exactly. If the d_name contains no field separators then
Packit a4aae4
    the function looks first in the top level and then in all subsequent
Packit a4aae4
    levels and returns the first occurrence found. In general, this
Packit a4aae4
    function searches constructor types in the order in which they appear
Packit a4aae4
    in the DDS, but there is no requirement that it do so.
Packit a4aae4
Packit a4aae4
    @note If a dataset contains two constructor types which have field names
Packit a4aae4
    that are the same (say point.x and pair.x) you should use fully qualified
Packit a4aae4
    names to get each of those variables.
Packit a4aae4
Packit a4aae4
    @param n The name of the variable to find.
Packit a4aae4
    @param s If given, this value-result parameter holds the path to the
Packit a4aae4
    returned BaseType. Thus, this method can return the FQN for the variable
Packit a4aae4
    \e n.
Packit a4aae4
    @return A BaseType pointer to the variable or null if not found. */
Packit a4aae4
BaseType *
Packit a4aae4
DDS::var(const string &n, BaseType::btp_stack *s)
Packit a4aae4
{
Packit a4aae4
    string name = www2id(n);
Packit a4aae4
    if( d_container )
Packit a4aae4
        return d_container->var( name, false, s ) ;
Packit a4aae4
Packit a4aae4
    BaseType *v = exact_match(name, s);
Packit a4aae4
    if (v)
Packit a4aae4
        return v;
Packit a4aae4
Packit a4aae4
    return leaf_match(name, s);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
BaseType *
Packit a4aae4
DDS::leaf_match(const string &n, BaseType::btp_stack *s)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
Packit a4aae4
Packit a4aae4
    for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
        BaseType *btp = *i;
Packit a4aae4
        DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
Packit a4aae4
        // Look for the d_name in the dataset's top-level
Packit a4aae4
        if (btp->name() == n) {
Packit a4aae4
            DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
Packit a4aae4
            return btp;
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        if (btp->is_constructor_type()) {
Packit a4aae4
            BaseType *found = btp->var(n, false, s);
Packit a4aae4
            if (found) {
Packit a4aae4
                DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
Packit a4aae4
                return found;
Packit a4aae4
            }
Packit a4aae4
        }
Packit a4aae4
#if STRUCTURE_ARRAY_SYNTAX_OLD
Packit a4aae4
        if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
Packit a4aae4
            s->push(btp);
Packit a4aae4
            BaseType *found = btp->var()->var(n, false, s);
Packit a4aae4
            if (found) {
Packit a4aae4
                DBG(cerr << "Found " << n << " in: " << btp->var()->d_name() << endl);
Packit a4aae4
                return found;
Packit a4aae4
            }
Packit a4aae4
        }
Packit a4aae4
#endif
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    return 0;   // It is not here.
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
BaseType *
Packit a4aae4
DDS::exact_match(const string &name, BaseType::btp_stack *s)
Packit a4aae4
{
Packit a4aae4
    for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
        BaseType *btp = *i;
Packit a4aae4
        DBG2(cerr << "Looking for " << d_name << " in: " << btp << endl);
Packit a4aae4
        // Look for the d_name in the current ctor type or the top level
Packit a4aae4
        if (btp->name() == name) {
Packit a4aae4
            DBG2(cerr << "Found " << d_name << " in: " << btp << endl);
Packit a4aae4
            return btp;
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    string::size_type dot_pos = name.find(".");
Packit a4aae4
    if (dot_pos != string::npos) {
Packit a4aae4
        string aggregate = name.substr(0, dot_pos);
Packit a4aae4
        string field = name.substr(dot_pos + 1);
Packit a4aae4
Packit a4aae4
        BaseType *agg_ptr = var(aggregate, s);
Packit a4aae4
        if (agg_ptr) {
Packit a4aae4
            DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
Packit a4aae4
            return agg_ptr->var(field, true, s);
Packit a4aae4
        }
Packit a4aae4
        else
Packit a4aae4
            return 0;  // qualified names must be *fully* qualified
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    return 0;   // It is not here.
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
Packit a4aae4
/** @brief Returns the first variable in the DDS. */
Packit a4aae4
Packit a4aae4
DDS::Vars_iter
Packit a4aae4
DDS::var_begin()
Packit a4aae4
{
Packit a4aae4
    return vars.begin();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
DDS::Vars_riter
Packit a4aae4
DDS::var_rbegin()
Packit a4aae4
{
Packit a4aae4
    return vars.rbegin();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
DDS::Vars_iter
Packit a4aae4
DDS::var_end()
Packit a4aae4
{
Packit a4aae4
    return vars.end() ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
DDS::Vars_riter
Packit a4aae4
DDS::var_rend()
Packit a4aae4
{
Packit a4aae4
    return vars.rend() ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Return the iterator for the \e ith variable.
Packit a4aae4
    @param i the index
Packit a4aae4
    @return The corresponding  Vars_iter */
Packit a4aae4
DDS::Vars_iter
Packit a4aae4
DDS::get_vars_iter(int i)
Packit a4aae4
{
Packit a4aae4
    return vars.begin() + i;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Return the \e ith variable.
Packit a4aae4
    @param i the index
Packit a4aae4
    @return The corresponding variable */
Packit a4aae4
BaseType *
Packit a4aae4
DDS::get_var_index(int i)
Packit a4aae4
{
Packit a4aae4
    return *(vars.begin() + i);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Insert a copy of the BaseType before the position given.
Packit a4aae4
 * @param i The iterator that marks the position
Packit a4aae4
 * @param ptr The BaseType object to copy and insert
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::insert_var(Vars_iter i, BaseType *ptr)
Packit a4aae4
{
Packit a4aae4
#if 0
Packit a4aae4
    if (ptr->is_dap4_only_type())
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
Packit a4aae4
#endif
Packit a4aae4
    vars.insert(i, ptr->ptr_duplicate());
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Insert the BaseType before the position given.
Packit a4aae4
 * @note Does not copy the BaseType object - that caller must not
Packit a4aae4
 * free the inserted object's pointer. This object will, however,
Packit a4aae4
 * delete the pointer when it is deleted.
Packit a4aae4
 * @param i The iterator that marks the position
Packit a4aae4
 * @param ptr The BaseType object to insert
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::insert_var_nocopy(Vars_iter i, BaseType *ptr)
Packit a4aae4
{
Packit a4aae4
#if 0
Packit a4aae4
    if (ptr->is_dap4_only_type())
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
Packit a4aae4
#endif
Packit a4aae4
    vars.insert(i, ptr);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Returns the number of variables in the DDS. */
Packit a4aae4
int
Packit a4aae4
DDS::num_var()
Packit a4aae4
{
Packit a4aae4
    return vars.size();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void
Packit a4aae4
DDS::timeout_on()
Packit a4aae4
{
Packit a4aae4
#if USE_LOCAL_TIMEOUT_SCHEME
Packit a4aae4
#ifndef WIN32
Packit a4aae4
    alarm(d_timeout);
Packit a4aae4
#endif
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void
Packit a4aae4
DDS::timeout_off()
Packit a4aae4
{
Packit a4aae4
#if USE_LOCAL_TIMEOUT_SCHEME
Packit a4aae4
#ifndef WIN32
Packit a4aae4
    // Old behavior commented out. I think it is an error to change the value
Packit a4aae4
    // of d_timeout. The way this will likely be used is to set the timeout
Packit a4aae4
    // value once and then 'turn on' or turn off' that timeout as the situation
Packit a4aae4
    // dictates. The initeded use for the DDS timeout is so that timeouts for
Packit a4aae4
    // data responses will include the CPU resources needed to build the response
Packit a4aae4
    // but not the time spent transmitting the response. This may change when
Packit a4aae4
    // more parallelism is added to the server... These methods are called from
Packit a4aae4
    // BESDapResponseBuilder in bes/dap. jhrg 12/22/15
Packit a4aae4
Packit a4aae4
    // d_timeout = alarm(0);
Packit a4aae4
Packit a4aae4
    alarm(0);
Packit a4aae4
#endif
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void
Packit a4aae4
DDS::set_timeout(int)
Packit a4aae4
{
Packit a4aae4
#if USE_LOCAL_TIMEOUT_SCHEME
Packit a4aae4
    //  Has no effect under win32
Packit a4aae4
    d_timeout = t;
Packit a4aae4
#endif
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
int
Packit a4aae4
DDS::get_timeout()
Packit a4aae4
{
Packit a4aae4
#if USE_LOCAL_TIMEOUT_SCHEME
Packit a4aae4
    //  Has to effect under win32
Packit a4aae4
    return d_timeout;
Packit a4aae4
#endif
Packit a4aae4
    return 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Traverse DDS, set Sequence leaf nodes. */
Packit a4aae4
void
Packit a4aae4
DDS::tag_nested_sequences()
Packit a4aae4
{
Packit a4aae4
    for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
        if ((*i)->type() == dods_sequence_c)
Packit a4aae4
            dynamic_cast<Sequence&>(**i).set_leaf_sequence();
Packit a4aae4
        else if ((*i)->type() == dods_structure_c)
Packit a4aae4
            dynamic_cast<Structure&>(**i).set_leaf_sequence();
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Parse a DDS from a file with the given d_name. */
Packit a4aae4
void
Packit a4aae4
DDS::parse(string fname)
Packit a4aae4
{
Packit a4aae4
    FILE *in = fopen(fname.c_str(), "r");
Packit a4aae4
Packit a4aae4
    if (!in) {
Packit a4aae4
        throw Error(cannot_read_file, "Could not open: " + fname);
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    try {
Packit a4aae4
        parse(in);
Packit a4aae4
        fclose(in);
Packit a4aae4
    }
Packit a4aae4
    catch (Error &e) {
Packit a4aae4
        fclose(in);
Packit a4aae4
        throw ;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
Packit a4aae4
/** @brief Parse a DDS from a file indicated by the input file descriptor. */
Packit a4aae4
void
Packit a4aae4
DDS::parse(int fd)
Packit a4aae4
{
Packit a4aae4
#ifdef WIN32
Packit a4aae4
    int new_fd = _dup(fd);
Packit a4aae4
#else
Packit a4aae4
    int new_fd = dup(fd);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    if (new_fd < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not access file.");
Packit a4aae4
    FILE *in = fdopen(new_fd, "r");
Packit a4aae4
Packit a4aae4
    if (!in) {
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not access file.");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    try {
Packit a4aae4
        parse(in);
Packit a4aae4
        fclose(in);
Packit a4aae4
    }
Packit a4aae4
    catch (Error &e) {
Packit a4aae4
        fclose(in);
Packit a4aae4
        throw ;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Parse a DDS from a file indicated by the input file descriptor.
Packit a4aae4
    Read the persistent representation of a DDS from the FILE *in, parse it
Packit a4aae4
    and create a matching binary object.
Packit a4aae4
    @param in Read the persistent DDS from this FILE*.
Packit a4aae4
    @exception InternalErr Thrown if \c in is null
Packit a4aae4
    @exception Error Thrown if the parse fails. */
Packit a4aae4
void
Packit a4aae4
DDS::parse(FILE *in)
Packit a4aae4
{
Packit a4aae4
    if (!in) {
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Null input stream.");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    void *buffer = dds_buffer(in);
Packit a4aae4
    dds_switch_to_buffer(buffer);
Packit a4aae4
Packit a4aae4
    parser_arg arg(this);
Packit a4aae4
Packit a4aae4
    bool status = ddsparse(&arg) == 0;
Packit a4aae4
Packit a4aae4
    dds_delete_buffer(buffer);
Packit a4aae4
Packit a4aae4
    DBG2(cout << "Status from parser: " << status << endl);
Packit a4aae4
Packit a4aae4
    //  STATUS is the result of the parser function; if a recoverable error
Packit a4aae4
    //  was found it will be true but arg.status() will be false.
Packit a4aae4
    if (!status || !arg.status()) {// Check parse result
Packit a4aae4
        if (arg.error())
Packit a4aae4
            throw *arg.error();
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Print the entire DDS to the specified file. */
Packit a4aae4
void
Packit a4aae4
DDS::print(FILE *out)
Packit a4aae4
{
Packit a4aae4
    ostringstream oss;
Packit a4aae4
    print(oss);
Packit a4aae4
    fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Print the entire DDS to the specified ostream. */
Packit a4aae4
void
Packit a4aae4
DDS::print(ostream &out)
Packit a4aae4
{
Packit a4aae4
    out << "Dataset {\n" ;
Packit a4aae4
Packit a4aae4
    for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
        (*i)->print_decl(out) ;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    out << "} " << id2www(d_name) << ";\n" ;
Packit a4aae4
Packit a4aae4
    return ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * Print the DAP2 DAS object using attribute information recorded
Packit a4aae4
 * this DDS object.
Packit a4aae4
 *
Packit a4aae4
 * @note Uses default indenting of four spaces and does not follow
Packit a4aae4
 * (now deprecated) attribute aliases.
Packit a4aae4
 *
Packit a4aae4
 * @param out Write the DAS here.
Packit a4aae4
 */
Packit a4aae4
static string four_spaces = "    ";
Packit a4aae4
void print_var_das(ostream &out, BaseType *bt, string indent=""){
Packit a4aae4
Packit a4aae4
    AttrTable attr_table = bt->get_attr_table();
Packit a4aae4
    out << indent << add_space_encoding(bt->name()) << " {" << endl;
Packit a4aae4
    attr_table.print(out, indent+four_spaces);
Packit a4aae4
    Constructor *cnstrctr = dynamic_cast < Constructor * >(bt);
Packit a4aae4
    if(cnstrctr) {
Packit a4aae4
        Constructor::Vars_iter i = cnstrctr->var_begin();
Packit a4aae4
        Constructor::Vars_iter e = cnstrctr->var_end();
Packit a4aae4
        for (; i!=e; i++) {
Packit a4aae4
            print_var_das(out,*i,indent+four_spaces);
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
    }
Packit a4aae4
    out << indent << "}" << endl;
Packit a4aae4
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void
Packit a4aae4
DDS::print_das(ostream &out)
Packit a4aae4
{
Packit a4aae4
    string indent("    ");
Packit a4aae4
    out << "Attributes {" << endl ;
Packit a4aae4
    for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
        print_var_das(out, *i, four_spaces);
Packit a4aae4
    }
Packit a4aae4
    // Print the global attributes at the end.
Packit a4aae4
    d_attr.print(out,indent);
Packit a4aae4
    out << "}" << endl ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Print a constrained DDS to the specified file.
Packit a4aae4
Packit a4aae4
    Print those parts (variables) of the DDS structure to OS that
Packit a4aae4
    are marked to be sent after evaluating the constraint
Packit a4aae4
    expression.
Packit a4aae4
Packit a4aae4
    @note This function only works for scalars at the top level.
Packit a4aae4
Packit a4aae4
    @returns true.
Packit a4aae4
*/
Packit a4aae4
void
Packit a4aae4
DDS::print_constrained(FILE *out)
Packit a4aae4
{
Packit a4aae4
    ostringstream oss;
Packit a4aae4
    print_constrained(oss);
Packit a4aae4
    fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Print a constrained DDS to the specified ostream.
Packit a4aae4
Packit a4aae4
    Print those parts (variables) of the DDS structure to OS that
Packit a4aae4
    are marked to be sent after evaluating the constraint
Packit a4aae4
    expression.
Packit a4aae4
Packit a4aae4
    \note This function only works for scalars at the top level.
Packit a4aae4
Packit a4aae4
    @returns true.
Packit a4aae4
*/
Packit a4aae4
void
Packit a4aae4
DDS::print_constrained(ostream &out)
Packit a4aae4
{
Packit a4aae4
    out << "Dataset {\n" ;
Packit a4aae4
Packit a4aae4
    for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
Packit a4aae4
        // for each variable, indent with four spaces, print a trailing
Packit a4aae4
        // semicolon, do not print debugging information, print only
Packit a4aae4
        // variables in the current projection.
Packit a4aae4
        (*i)->print_decl(out, "    ", true, false, true) ;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    out << "} " << id2www(d_name) << ";\n" ;
Packit a4aae4
Packit a4aae4
    return;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Print an XML representation of this DDS. This method is used to generate
Packit a4aae4
    the part of the DDX response. The \c Dataset tag is \e not written by
Packit a4aae4
    this code. The caller of this method must handle writing that and
Packit a4aae4
    including the \c dataBLOB tag.
Packit a4aae4
Packit a4aae4
    @param out Destination.
Packit a4aae4
    @param constrained True if the output should be limited to just those
Packit a4aae4
    variables that are in the projection of the current constraint
Packit a4aae4
    expression.
Packit a4aae4
    @param blob The dataBLOB href.
Packit a4aae4
    @deprecated */
Packit a4aae4
void
Packit a4aae4
DDS::print_xml(FILE *out, bool constrained, const string &blob)
Packit a4aae4
{
Packit a4aae4
    ostringstream oss;
Packit a4aae4
    print_xml_writer(oss, constrained, blob);
Packit a4aae4
    fwrite(oss.str().data(), 1, oss.str().length(), out);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Print an XML representation of this DDS. This method is used to generate
Packit a4aae4
    the part of the DDX response. The \c Dataset tag is \e not written by
Packit a4aae4
    this code. The caller of this method must handle writing that and
Packit a4aae4
    including the \c dataBLOB tag.
Packit a4aae4
Packit a4aae4
    @param out Destination ostream.
Packit a4aae4
    @param constrained True if the output should be limited to just those
Packit a4aae4
    variables that are in the projection of the current constraint
Packit a4aae4
    expression.
Packit a4aae4
    @param blob The dataBLOB href.
Packit a4aae4
    @deprecated */
Packit a4aae4
void
Packit a4aae4
DDS::print_xml(ostream &out, bool constrained, const string &blob)
Packit a4aae4
{
Packit a4aae4
    print_xml_writer(out, constrained, blob);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
class VariablePrintXMLWriter : public unary_function<BaseType *, void>
Packit a4aae4
{
Packit a4aae4
    XMLWriter &d_xml;
Packit a4aae4
    bool d_constrained;
Packit a4aae4
public:
Packit a4aae4
    VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
Packit a4aae4
            : d_xml(xml), d_constrained(constrained)
Packit a4aae4
    {}
Packit a4aae4
    void operator()(BaseType *bt)
Packit a4aae4
    {
Packit a4aae4
        bt->print_xml_writer(d_xml, d_constrained);
Packit a4aae4
    }
Packit a4aae4
};
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * Print the DDX. This code uses the libxml2 'TextWriter' interface; something
Packit a4aae4
 * that seems to be a good compromise between doing it by hand (although more
Packit a4aae4
 * verbose it is also more reliable) and DOM.
Packit a4aae4
 *
Packit a4aae4
 * @note This code handles several different versions of DAP in a fairly
Packit a4aae4
 * crude way. I've broken it up into three different responses: DAP2, DAP3.2
Packit a4aae4
 * and DAP4.
Packit a4aae4
 *
Packit a4aae4
 * @param out Write the XML to this output sink
Packit a4aae4
 * @param constrained True if the only variables to print are those in the
Packit a4aae4
 * current projection. If true, this will also suppress printing attributes.
Packit a4aae4
 * @param blob This is an href (DAP2) or a cid (DAP3.4 and 4). The href
Packit a4aae4
 * points to the binary data; the cid is the M-MIME separator for the binary
Packit a4aae4
 * data.
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
Packit a4aae4
{
Packit a4aae4
    XMLWriter xml("    ");
Packit a4aae4
Packit a4aae4
    // Stamp and repeat for these sections; trying to economize is makes it
Packit a4aae4
    // even more confusing
Packit a4aae4
    if (get_dap_major() >= 4) {
Packit a4aae4
        if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)get_dap_version().c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
Packit a4aae4
Packit a4aae4
        if (!get_request_xml_base().empty()) {
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
Packit a4aae4
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
Packit a4aae4
        }
Packit a4aae4
        if (!get_namespace().empty()) {
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)get_namespace().c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
Packit a4aae4
        if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
Packit a4aae4
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
Packit a4aae4
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
Packit a4aae4
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
Packit a4aae4
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
Packit a4aae4
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
Packit a4aae4
Packit a4aae4
        if (!get_request_xml_base().empty()) {
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
Packit a4aae4
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    else { // dap2
Packit a4aae4
        if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
Packit a4aae4
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
Packit a4aae4
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    // Print the global attributes
Packit a4aae4
    d_attr.print_xml_writer(xml);
Packit a4aae4
Packit a4aae4
    // Print each variable
Packit a4aae4
    for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
Packit a4aae4
Packit a4aae4
    // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
Packit a4aae4
    // the CID of the MIME part that holds the data. For DAP2 (which includes
Packit a4aae4
    // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
Packit a4aae4
    // given.
Packit a4aae4
    if (get_dap_major() >= 4) {
Packit a4aae4
        if (!blob.empty()) {
Packit a4aae4
            if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
Packit a4aae4
            string cid = "cid:" + blob;
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
Packit a4aae4
            if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
Packit a4aae4
        if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
Packit a4aae4
        string cid = "cid:" + blob;
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
Packit a4aae4
        if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
Packit a4aae4
    }
Packit a4aae4
    else { // dap2
Packit a4aae4
        if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
Packit a4aae4
        if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
Packit a4aae4
Packit a4aae4
    out << xml.get_doc();// << ends;// << endl;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * Print the DAP4 DMR object.
Packit a4aae4
 * This method prints the DMR. If the dap version is not >= 4.0, it's an
Packit a4aae4
 * error to call this method.
Packit a4aae4
 *
Packit a4aae4
 * @note Calling methods that print the DDS or DDX when get_dap_major()
Packit a4aae4
 * returns a value >= 4 is undefined. Use this method to get the DAP4
Packit a4aae4
 * metadata response.
Packit a4aae4
 *
Packit a4aae4
 * @param out Write the XML to this stream
Packit a4aae4
 * @param constrained Should the DMR be subject to a constraint?
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::print_dmr(ostream &out, bool constrained)
Packit a4aae4
{
Packit a4aae4
    if (get_dap_major() < 4)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Tried to print a DMR with DAP major version less than 4");
Packit a4aae4
Packit a4aae4
    XMLWriter xml("    ");
Packit a4aae4
Packit a4aae4
    // DAP4 wraps a dataset in a top-level Group element.
Packit a4aae4
    if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
Packit a4aae4
            (const xmlChar*) c_xml_namespace.c_str()) < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
Packit a4aae4
            < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
Packit a4aae4
            (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns",
Packit a4aae4
            (const xmlChar*) get_namespace().c_str()) < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion",
Packit a4aae4
            (const xmlChar*) get_dap_version().c_str()) < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*) get_dmr_version().c_str()) < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
Packit a4aae4
Packit a4aae4
    if (!get_request_xml_base().empty()) {
Packit a4aae4
        if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
Packit a4aae4
                (const xmlChar*) get_request_xml_base().c_str()) < 0)
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d_name.c_str()) < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
Packit a4aae4
Packit a4aae4
    // Print the global attributes
Packit a4aae4
    d_attr.print_xml_writer(xml);
Packit a4aae4
Packit a4aae4
    // Print each variable
Packit a4aae4
    for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
    // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
Packit a4aae4
    // the CID of the MIME part that holds the data. For DAP2 (which includes
Packit a4aae4
    // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
Packit a4aae4
    // given.
Packit a4aae4
    if (get_dap_major() >= 4) {
Packit a4aae4
        if (!blob.empty()) {
Packit a4aae4
            if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
Packit a4aae4
            string cid = "cid:" + blob;
Packit a4aae4
            if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
Packit a4aae4
            if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
                throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    if (xmlTextWriterEndElement(xml.get_writer()) < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
Packit a4aae4
Packit a4aae4
    out << xml.get_doc();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Used by DDS::send() when returning data from a function call.
Packit a4aae4
/** @brief Check the semantics of each of the variables represented in the
Packit a4aae4
    DDS.
Packit a4aae4
Packit a4aae4
    Check the semantics of the DDS describing a complete dataset. If ALL is
Packit a4aae4
    true, check not only the semantics of THIS->TABLE, but also recursively
Packit a4aae4
    all ctor types in the THIS->TABLE. By default, ALL is false since parsing
Packit a4aae4
    a DDS input file runs semantic checks on all variables (but not the
Packit a4aae4
    dataset itself.
Packit a4aae4
Packit a4aae4
    @return TRUE if the conventions for the DDS are not violated, FALSE
Packit a4aae4
    otherwise.
Packit a4aae4
    @param all If true, recursively check the individual members of
Packit a4aae4
    compound variables.
Packit a4aae4
    @see BaseType::check_semantics */
Packit a4aae4
bool
Packit a4aae4
DDS::check_semantics(bool all)
Packit a4aae4
{
Packit a4aae4
    // The dataset must have a d_name
Packit a4aae4
    if (d_name == "") {
Packit a4aae4
        cerr << "A dataset must have a d_name" << endl;
Packit a4aae4
        return false;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    string msg;
Packit a4aae4
    if (!unique_names(vars, d_name, "Dataset", msg))
Packit a4aae4
        return false;
Packit a4aae4
Packit a4aae4
    if (all)
Packit a4aae4
        for (Vars_iter i = vars.begin(); i != vars.end(); i++)
Packit a4aae4
            if (!(*i)->check_semantics(msg, true))
Packit a4aae4
                return false;
Packit a4aae4
Packit a4aae4
    return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Mark the <tt>send_p</tt> flag of the named variable to
Packit a4aae4
    state.
Packit a4aae4
Packit a4aae4
    Mark the named variable by setting its SEND_P flag to STATE (true
Packit a4aae4
    indicates that it is to be sent). Names must be fully qualified.
Packit a4aae4
Packit a4aae4
    @note For aggregate types this sets each part to STATE when STATE is
Packit a4aae4
    True. Thus, if State is True and N is `exp1.test', then both `exp1' and
Packit a4aae4
    `test' have their SEND_P flag set to True. If STATE is False, then the
Packit a4aae4
    SEND_P flag of the `test' is set to False, but `exp1' is left
Packit a4aae4
    unchanged. This means that a single variable can be removed from the
Packit a4aae4
    current projection without removing all the other children of its
Packit a4aae4
    parent. See the mfunc set_send_p().
Packit a4aae4
Packit a4aae4
    @return True if the named variable was found, false otherwise.
Packit a4aae4
Packit a4aae4
    @todo This should throw an exception on error!!!
Packit a4aae4
Packit a4aae4
    @todo These methods that use the btp_stack to keep track of the path from
Packit a4aae4
    the top of a dataset to a particular variable can be rewritten to use the
Packit a4aae4
    parent field instead.
Packit a4aae4
Packit a4aae4
    @todo All the methods that use names to identify variables should have
Packit a4aae4
    counterparts that take BaseType pointers.
Packit a4aae4
*/
Packit a4aae4
bool
Packit a4aae4
DDS::mark(const string &n, bool state)
Packit a4aae4
{
Packit a4aae4
    // TODO use auto_ptr
Packit a4aae4
    BaseType::btp_stack *s = new BaseType::btp_stack;
Packit a4aae4
Packit a4aae4
    DBG2(cerr << "DDS::mark: Looking for " << n << endl);
Packit a4aae4
Packit a4aae4
    BaseType *variable = var(n, s);
Packit a4aae4
    if (!variable) {
Packit a4aae4
        DBG2(cerr << "Could not find variable " << n << endl);
Packit a4aae4
        delete s; s = 0;
Packit a4aae4
        return false;
Packit a4aae4
    }
Packit a4aae4
    variable->set_send_p(state);
Packit a4aae4
Packit a4aae4
    DBG2(cerr << "DDS::mark: Set variable " << variable->d_name()
Packit a4aae4
            << " (a " << variable->type_name() << ")" << endl);
Packit a4aae4
Packit a4aae4
    // Now check the btp_stack and run BaseType::set_send_p for every
Packit a4aae4
    // BaseType pointer on the stack. Using BaseType::set_send_p() will
Packit a4aae4
    // set the property for a Constructor but not its contained variables
Packit a4aae4
    // which preserves the semantics of projecting just one field.
Packit a4aae4
    while (!s->empty()) {
Packit a4aae4
        s->top()->BaseType::set_send_p(state);
Packit a4aae4
Packit a4aae4
        DBG2(cerr << "DDS::mark: Set variable " << s->top()->d_name()
Packit a4aae4
                << " (a " << s->top()->type_name() << ")" << endl);
Packit a4aae4
        // FIXME get_parent() hosed?
Packit a4aae4
#if 1
Packit a4aae4
        string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
Packit a4aae4
        string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
Packit a4aae4
        DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
Packit a4aae4
#endif
Packit a4aae4
        s->pop();
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    delete s ; s = 0;
Packit a4aae4
Packit a4aae4
    return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Mark the member variable <tt>send_p</tt> flags to
Packit a4aae4
    state.
Packit a4aae4
Packit a4aae4
    @return Void
Packit a4aae4
*/
Packit a4aae4
void
Packit a4aae4
DDS::mark_all(bool state)
Packit a4aae4
{
Packit a4aae4
    for (Vars_iter i = vars.begin(); i != vars.end(); i++)
Packit a4aae4
        (*i)->set_send_p(state);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief dumps information about this object
Packit a4aae4
 *
Packit a4aae4
 * Displays the pointer value of this instance and then calls parent dump
Packit a4aae4
 *
Packit a4aae4
 * @param strm C++ i/o stream to dump the information to
Packit a4aae4
 * @return void
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
DDS::dump(ostream &strm) const
Packit a4aae4
{
Packit a4aae4
    strm << DapIndent::LMarg << "DDS::dump - ("
Packit a4aae4
    << (void *)this << ")" << endl ;
Packit a4aae4
    DapIndent::Indent() ;
Packit a4aae4
    strm << DapIndent::LMarg << "d_name: " << d_name << endl ;
Packit a4aae4
    strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
Packit a4aae4
    strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
Packit a4aae4
    strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
Packit a4aae4
    strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
Packit a4aae4
Packit a4aae4
    strm << DapIndent::LMarg << "global attributes:" << endl ;
Packit a4aae4
    DapIndent::Indent() ;
Packit a4aae4
    d_attr.dump(strm) ;
Packit a4aae4
    DapIndent::UnIndent() ;
Packit a4aae4
Packit a4aae4
    if (vars.size()) {
Packit a4aae4
        strm << DapIndent::LMarg << "vars:" << endl ;
Packit a4aae4
        DapIndent::Indent() ;
Packit a4aae4
        Vars_citer i = vars.begin() ;
Packit a4aae4
        Vars_citer ie = vars.end() ;
Packit a4aae4
        for (; i != ie; i++) {
Packit a4aae4
            (*i)->dump(strm) ;
Packit a4aae4
        }
Packit a4aae4
        DapIndent::UnIndent() ;
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        strm << DapIndent::LMarg << "vars: none" << endl ;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    DapIndent::UnIndent() ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
} // namespace libdap