DDS.cc
// -*- mode: c++; c-basic-offset:4 -*-
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.
// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
// (c) COPYRIGHT URI/MIT 1994-1999
// Please read the full copyright statement in the file COPYRIGHT_URI.
//
// Authors:
// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
//
// jhrg 9/7/94
#include "config.h"
#include <cstdio>
#include <cmath>
#include <sys/types.h>
#ifdef WIN32
#include <io.h>
#include <process.h>
#include <fstream>
#else
#include <unistd.h> // for alarm and dup
#include <sys/wait.h>
#endif
#include <iostream>
#include <sstream>
#include <algorithm>
#include <functional>
// #define DODS_DEBUG
//#define DODS_DEBUG2
#include "GNURegex.h"
#include "DAS.h"
#include "Clause.h"
#include "Error.h"
#include "InternalErr.h"
#include "Keywords2.h"
#include "parser.h"
#include "debug.h"
#include "util.h"
#include "Byte.h"
#include "Int16.h"
#include "UInt16.h"
#include "Int32.h"
#include "UInt32.h"
#include "Float32.h"
#include "Float64.h"
#include "Str.h"
#include "Url.h"
#include "Array.h"
#include "Structure.h"
#include "Sequence.h"
#include "Grid.h"
#include "escaping.h"
const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
using namespace std;
int ddsparse(libdap::parser_arg *arg);
// Glue for the DDS parser defined in dds.lex
void dds_switch_to_buffer(void *new_buffer);
void dds_delete_buffer(void * buffer);
void *dds_buffer(FILE *fp);
namespace libdap {
void
DDS::duplicate(const DDS &dds)
{
DBG(cerr << "Entering DDS::duplicate... " <<endl);
#if 0
BaseTypeFactory *d_factory;
string d_name; // The dataset d_name
string d_filename; // File d_name (or other OS identifier) for
string d_container_name; // d_name of container structure
Structure *d_container; // current container for container d_name
// dataset or part of dataset.
int d_dap_major; // The protocol major version number
int d_dap_minor; // ... and minor version number
string d_dap_version; // String version of the protocol
string d_request_xml_base;
string d_namespace;
AttrTable d_attr; // Global attributes.
vector<BaseType *> vars; // Variables at the top level
int d_timeout; // alarm time in seconds. If greater than
// zero, raise the alarm signal if more than
// d_timeout seconds are spent reading data.
Keywords d_keywords; // Holds keywords parsed from the CE
long d_max_response_size; // In bytes
#endif
d_factory = dds.d_factory;
d_name = dds.d_name;
d_filename = dds.d_filename;
d_container_name = dds.d_container_name;
d_container = dds.d_container;
d_dap_major = dds.d_dap_major;
d_dap_minor = dds.d_dap_minor;
d_dap_version = dds.d_dap_version; // String version of the protocol
d_request_xml_base = dds.d_request_xml_base;
d_namespace = dds.d_namespace;
d_attr = dds.d_attr;
DDS &dds_tmp = const_cast<DDS &>(dds);
// copy the things pointed to by the list, not just the pointers
for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
add_var(*i); // add_var() dups the BaseType.
}
d_timeout = dds.d_timeout;
d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
d_max_response_size = dds.d_max_response_size;
}
DDS::DDS(BaseTypeFactory *factory, const string &name)
: d_factory(factory), d_name(name), d_container_name(""), d_container(0),
d_request_xml_base(""),
d_timeout(0), d_keywords(), d_max_response_size(0)
{
DBG(cerr << "Building a DDS for the default version (2.0)" << endl);
// This method sets a number of values, including those returned by
// get_protocol_major(), ..., get_namespace().
set_dap_version("2.0");
}
DDS::DDS(BaseTypeFactory *factory, const string &name, const string &version)
: d_factory(factory), d_name(name), d_container_name(""), d_container(0),
d_request_xml_base(""),
d_timeout(0), d_keywords(), d_max_response_size(0)
{
DBG(cerr << "Building a DDS for version: " << version << endl);
// This method sets a number of values, including those returned by
// get_protocol_major(), ..., get_namespace().
set_dap_version(version);
}
DDS::DDS(const DDS &rhs) : DapObj()
{
DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
duplicate(rhs);
DBG(cerr << " bye." << endl);
}
DDS::~DDS()
{
// delete all the variables in this DDS
for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
BaseType *btp = *i ;
delete btp ; btp = 0;
}
}
DDS &
DDS::operator=(const DDS &rhs)
{
DBG(cerr << "Entering DDS::operator= ..." << endl);
if (this == &rhs)
return *this;
duplicate(rhs);
DBG(cerr << " bye." << endl);
return *this;
}
void DDS::transfer_attributes(DAS *das)
{
// If there is a container set in the DDS then check the container from
// the DAS. If they are not the same container, then throw an exception
// (should be working on the same container). If the container does not
// exist in the DAS, then throw an exception
if (d_container && das->container_name() != d_container_name)
throw InternalErr(__FILE__, __LINE__,
"Error transferring attributes: working on a container in dds, but not das");
// Give each variable a chance to claim its attributes.
AttrTable *top = das->get_top_level_attributes();
for (DDS::Vars_iter i = var_begin(), e = var_end(); i != e; i++) {
(*i)->transfer_attributes(top);
}
#if 0
Vars_iter var = var_begin();
while (var != var_end()) {
try {
DBG(cerr << "Processing the attributes for: " << (*var)->d_name() << " a " << (*var)->type_name() << endl);
(*var)->transfer_attributes(top);
var++;
}
catch (Error &e) {
DBG(cerr << "Got this exception: " << e.get_error_message() << endl);
var++;
throw e;
}
}
#endif
// Now we transfer all of the attributes still marked as global to the
// global container in the DDS.
for (AttrTable::Attr_iter i = top->attr_begin(), e = top->attr_end(); i != e; ++i) {
if ((*i)->type == Attr_container && (*i)->attributes->is_global_attribute()) {
// copy the source container so that the DAS passed in can be
// deleted after calling this method.
AttrTable *at = new AttrTable(*(*i)->attributes);
d_attr.append_container(at, at->get_name());
}
}
#if 0
AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
while (at_cont_p != top_level->attr_end()) {
// In truth, all of the top level attributes should be containers, but
// this test handles the abnormal case where somehow someone makes a
// top level attribute that is not a container by silently dropping it.
if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) {
DBG(cerr << (*at_cont_p)->d_name << " is a global attribute." << endl);
// copy the source container so that the DAS passed in can be
// deleted after calling this method.
AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
d_attr.append_container(at, at->get_name());
}
at_cont_p++;
}
#endif
}
string
DDS::get_dataset_name() const
{
return d_name;
}
void
DDS::set_dataset_name(const string &n)
{
d_name = n;
}
AttrTable &
DDS::get_attr_table()
{
return d_attr;
}
string
DDS::filename() const
{
return d_filename;
}
void
DDS::filename(const string &fn)
{
d_filename = fn;
}
void
DDS::set_dap_major(int p)
{
d_dap_major = p;
// This works because regardless of the order set_dap_major and set_dap_minor
// are called, once they both are called, the value in the string is
// correct. I protect against negative numbers because that would be
// nonsensical.
if (d_dap_minor >= 0) {
ostringstream oss;
oss << d_dap_major << "." << d_dap_minor;
d_dap_version = oss.str();
}
}
void
DDS::set_dap_minor(int p)
{
d_dap_minor = p;
if (d_dap_major >= 0) {
ostringstream oss;
oss << d_dap_major << "." << d_dap_minor;
d_dap_version = oss.str();
}
}
void
DDS::set_dap_version(const string &v /* = "2.0" */)
{
istringstream iss(v);
int major = -1, minor = -1;
char dot;
if (!iss.eof() && !iss.fail())
iss >> major;
if (!iss.eof() && !iss.fail())
iss >> dot;
if (!iss.eof() && !iss.fail())
iss >> minor;
if (major == -1 || minor == -1 or dot != '.')
throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
d_dap_version = v;
d_dap_major = major;
d_dap_minor = minor;
// Now set the related XML constants. These might be overwritten if
// the DDS instance is being built from a document parse, but if it's
// being constructed by a server the code to generate the XML document
// needs these values to match the DAP version information.
switch (d_dap_major) {
case 2:
d_namespace = c_dap20_namespace;
break;
case 3:
d_namespace = c_dap32_namespace;
break;
case 4:
d_namespace = c_dap40_namespace;
break;
default:
throw InternalErr(__FILE__, __LINE__, "Unknown DAP version.");
}
}
void
DDS::set_dap_version(double d)
{
int major = floor(d);
int minor = (d-major)*10;
DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
ostringstream oss;
oss << major << "." << minor;
set_dap_version(oss.str());
}
string
DDS::container_name()
{
return d_container_name;
}
void
DDS::container_name(const string &cn)
{
// we want to search the DDS for the top level structure with the given
// d_name. Set the container to null so that we don't search some previous
// container.
d_container = 0 ;
if( !cn.empty() )
{
d_container = dynamic_cast<Structure *>( var( cn ) ) ;
if( !d_container )
{
// create a structure for this container. Calling add_var
// while_container is null will add the new structure to DDS and
// not some sub structure. Adding the new structure makes a copy
// of it. So after adding it, go get it and set d_container.
Structure *s = new Structure( cn ) ;
add_var( s ) ;
delete s ;
s = 0 ;
d_container = dynamic_cast<Structure *>( var( cn ) ) ;
}
}
d_container_name = cn;
}
Structure *
DDS::container()
{
return d_container ;
}
int
DDS::get_request_size(bool constrained)
{
int w = 0;
for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
if (constrained) {
if ((*i)->send_p())
w += (*i)->width(constrained);
}
else {
w += (*i)->width(constrained);
}
}
return w;
}
void DDS::add_var(BaseType *bt) {
if (!bt)
throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
#if 0
if (bt->is_dap4_only_type())
throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
#endif
DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
BaseType *btp = bt->ptr_duplicate();
DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
if (d_container) {
// Mem leak fix [mjohnson nov 2009]
// Structure::add_var() creates ANOTHER copy.
d_container->add_var(bt);
// So we need to delete btp or else it leaks
delete btp;
btp = 0;
}
else {
vars.push_back(btp);
}
}
void
DDS::add_var_nocopy(BaseType *bt)
{
if (!bt)
throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
#if 0
//FIXME There's no longer a DAP2 and DAP4 DDS
if (bt->is_dap4_only_type())
throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
#endif
DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
if (d_container) {
d_container->add_var_nocopy(bt);
}
else {
vars.push_back(bt);
}
}
void
DDS::del_var(const string &n)
{
if( d_container )
{
d_container->del_var( n ) ;
return ;
}
for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
if ((*i)->name() == n) {
BaseType *bt = *i ;
vars.erase(i) ;
delete bt ; bt = 0;
return;
}
}
}
void
DDS::del_var(Vars_iter i)
{
if (i != vars.end()) {
BaseType *bt = *i ;
vars.erase(i) ;
delete bt ; bt = 0;
}
}
void
DDS::del_var(Vars_iter i1, Vars_iter i2)
{
for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
BaseType *bt = *i_tmp ;
delete bt ; bt = 0;
}
vars.erase(i1, i2) ;
}
BaseType *
DDS::var(const string &n, BaseType::btp_stack &s)
{
return var(n, &s);
}
BaseType *
DDS::var(const string &n, BaseType::btp_stack *s)
{
string name = www2id(n);
if( d_container )
return d_container->var( name, false, s ) ;
BaseType *v = exact_match(name, s);
if (v)
return v;
return leaf_match(name, s);
}
BaseType *
DDS::leaf_match(const string &n, BaseType::btp_stack *s)
{
DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
BaseType *btp = *i;
DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
// Look for the d_name in the dataset's top-level
if (btp->name() == n) {
DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
return btp;
}
if (btp->is_constructor_type()) {
BaseType *found = btp->var(n, false, s);
if (found) {
DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
return found;
}
}
#if STRUCTURE_ARRAY_SYNTAX_OLD
if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
s->push(btp);
BaseType *found = btp->var()->var(n, false, s);
if (found) {
DBG(cerr << "Found " << n << " in: " << btp->var()->d_name() << endl);
return found;
}
}
#endif
}
return 0; // It is not here.
}
BaseType *
DDS::exact_match(const string &name, BaseType::btp_stack *s)
{
for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
BaseType *btp = *i;
DBG2(cerr << "Looking for " << d_name << " in: " << btp << endl);
// Look for the d_name in the current ctor type or the top level
if (btp->name() == name) {
DBG2(cerr << "Found " << d_name << " in: " << btp << endl);
return btp;
}
}
string::size_type dot_pos = name.find(".");
if (dot_pos != string::npos) {
string aggregate = name.substr(0, dot_pos);
string field = name.substr(dot_pos + 1);
BaseType *agg_ptr = var(aggregate, s);
if (agg_ptr) {
DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
return agg_ptr->var(field, true, s);
}
else
return 0; // qualified names must be *fully* qualified
}
return 0; // It is not here.
}
DDS::Vars_iter
DDS::var_begin()
{
return vars.begin();
}
DDS::Vars_riter
DDS::var_rbegin()
{
return vars.rbegin();
}
DDS::Vars_iter
DDS::var_end()
{
return vars.end() ;
}
DDS::Vars_riter
DDS::var_rend()
{
return vars.rend() ;
}
DDS::Vars_iter
DDS::get_vars_iter(int i)
{
return vars.begin() + i;
}
BaseType *
DDS::get_var_index(int i)
{
return *(vars.begin() + i);
}
void
DDS::insert_var(Vars_iter i, BaseType *ptr)
{
#if 0
if (ptr->is_dap4_only_type())
throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
#endif
vars.insert(i, ptr->ptr_duplicate());
}
void
DDS::insert_var_nocopy(Vars_iter i, BaseType *ptr)
{
#if 0
if (ptr->is_dap4_only_type())
throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
#endif
vars.insert(i, ptr);
}
int
DDS::num_var()
{
return vars.size();
}
void
DDS::timeout_on()
{
#if USE_LOCAL_TIMEOUT_SCHEME
#ifndef WIN32
alarm(d_timeout);
#endif
#endif
}
void
DDS::timeout_off()
{
#if USE_LOCAL_TIMEOUT_SCHEME
#ifndef WIN32
// Old behavior commented out. I think it is an error to change the value
// of d_timeout. The way this will likely be used is to set the timeout
// value once and then 'turn on' or turn off' that timeout as the situation
// dictates. The initeded use for the DDS timeout is so that timeouts for
// data responses will include the CPU resources needed to build the response
// but not the time spent transmitting the response. This may change when
// more parallelism is added to the server... These methods are called from
// BESDapResponseBuilder in bes/dap. jhrg 12/22/15
// d_timeout = alarm(0);
alarm(0);
#endif
#endif
}
void
DDS::set_timeout(int)
{
#if USE_LOCAL_TIMEOUT_SCHEME
// Has no effect under win32
d_timeout = t;
#endif
}
int
DDS::get_timeout()
{
#if USE_LOCAL_TIMEOUT_SCHEME
// Has to effect under win32
return d_timeout;
#endif
return 0;
}
void
DDS::tag_nested_sequences()
{
for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
if ((*i)->type() == dods_sequence_c)
dynamic_cast<Sequence&>(**i).set_leaf_sequence();
else if ((*i)->type() == dods_structure_c)
dynamic_cast<Structure&>(**i).set_leaf_sequence();
}
}
void
DDS::parse(string fname)
{
FILE *in = fopen(fname.c_str(), "r");
if (!in) {
throw Error(cannot_read_file, "Could not open: " + fname);
}
try {
parse(in);
fclose(in);
}
catch (Error &e) {
fclose(in);
throw ;
}
}
void
DDS::parse(int fd)
{
#ifdef WIN32
int new_fd = _dup(fd);
#else
int new_fd = dup(fd);
#endif
if (new_fd < 0)
throw InternalErr(__FILE__, __LINE__, "Could not access file.");
FILE *in = fdopen(new_fd, "r");
if (!in) {
throw InternalErr(__FILE__, __LINE__, "Could not access file.");
}
try {
parse(in);
fclose(in);
}
catch (Error &e) {
fclose(in);
throw ;
}
}
void
DDS::parse(FILE *in)
{
if (!in) {
throw InternalErr(__FILE__, __LINE__, "Null input stream.");
}
void *buffer = dds_buffer(in);
dds_switch_to_buffer(buffer);
parser_arg arg(this);
bool status = ddsparse(&arg) == 0;
dds_delete_buffer(buffer);
DBG2(cout << "Status from parser: " << status << endl);
// STATUS is the result of the parser function; if a recoverable error
// was found it will be true but arg.status() will be false.
if (!status || !arg.status()) {// Check parse result
if (arg.error())
throw *arg.error();
}
}
void
DDS::print(FILE *out)
{
ostringstream oss;
print(oss);
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
}
void
DDS::print(ostream &out)
{
out << "Dataset {\n" ;
for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
(*i)->print_decl(out) ;
}
out << "} " << id2www(d_name) << ";\n" ;
return ;
}
static string four_spaces = " ";
void print_var_das(ostream &out, BaseType *bt, string indent=""){
AttrTable attr_table = bt->get_attr_table();
out << indent << add_space_encoding(bt->name()) << " {" << endl;
attr_table.print(out, indent+four_spaces);
Constructor *cnstrctr = dynamic_cast < Constructor * >(bt);
if(cnstrctr) {
Constructor::Vars_iter i = cnstrctr->var_begin();
Constructor::Vars_iter e = cnstrctr->var_end();
for (; i!=e; i++) {
print_var_das(out,*i,indent+four_spaces);
}
}
out << indent << "}" << endl;
}
void
DDS::print_das(ostream &out)
{
string indent(" ");
out << "Attributes {" << endl ;
for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
print_var_das(out, *i, four_spaces);
}
// Print the global attributes at the end.
d_attr.print(out,indent);
out << "}" << endl ;
}
void
DDS::print_constrained(FILE *out)
{
ostringstream oss;
print_constrained(oss);
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
}
void
DDS::print_constrained(ostream &out)
{
out << "Dataset {\n" ;
for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
// for each variable, indent with four spaces, print a trailing
// semicolon, do not print debugging information, print only
// variables in the current projection.
(*i)->print_decl(out, " ", true, false, true) ;
}
out << "} " << id2www(d_name) << ";\n" ;
return;
}
void
DDS::print_xml(FILE *out, bool constrained, const string &blob)
{
ostringstream oss;
print_xml_writer(oss, constrained, blob);
fwrite(oss.str().data(), 1, oss.str().length(), out);
}
void
DDS::print_xml(ostream &out, bool constrained, const string &blob)
{
print_xml_writer(out, constrained, blob);
}
class VariablePrintXMLWriter : public unary_function<BaseType *, void>
{
XMLWriter &d_xml;
bool d_constrained;
public:
VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
: d_xml(xml), d_constrained(constrained)
{}
void operator()(BaseType *bt)
{
bt->print_xml_writer(d_xml, d_constrained);
}
};
void
DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
{
XMLWriter xml(" ");
// Stamp and repeat for these sections; trying to economize is makes it
// even more confusing
if (get_dap_major() >= 4) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)get_dap_version().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
if (!get_request_xml_base().empty()) {
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
}
if (!get_namespace().empty()) {
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)get_namespace().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
}
}
else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
if (!get_request_xml_base().empty()) {
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
}
}
else { // dap2
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
}
// Print the global attributes
d_attr.print_xml_writer(xml);
// Print each variable
for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
// For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
// the CID of the MIME part that holds the data. For DAP2 (which includes
// 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
// given.
if (get_dap_major() >= 4) {
if (!blob.empty()) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
string cid = "cid:" + blob;
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
}
}
else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
string cid = "cid:" + blob;
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
}
else { // dap2
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
}
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
out << xml.get_doc();// << ends;// << endl;
}
void
DDS::print_dmr(ostream &out, bool constrained)
{
if (get_dap_major() < 4)
throw InternalErr(__FILE__, __LINE__, "Tried to print a DMR with DAP major version less than 4");
XMLWriter xml(" ");
// DAP4 wraps a dataset in a top-level Group element.
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
(const xmlChar*) c_xml_namespace.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
< 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
(const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns",
(const xmlChar*) get_namespace().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion",
(const xmlChar*) get_dap_version().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*) get_dmr_version().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
if (!get_request_xml_base().empty()) {
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
(const xmlChar*) get_request_xml_base().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
}
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d_name.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
// Print the global attributes
d_attr.print_xml_writer(xml);
// Print each variable
for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
#if 0
// For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
// the CID of the MIME part that holds the data. For DAP2 (which includes
// 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
// given.
if (get_dap_major() >= 4) {
if (!blob.empty()) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
string cid = "cid:" + blob;
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
}
}
#endif
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
out << xml.get_doc();
}
// Used by DDS::send() when returning data from a function call.
bool
DDS::check_semantics(bool all)
{
// The dataset must have a d_name
if (d_name == "") {
cerr << "A dataset must have a d_name" << endl;
return false;
}
string msg;
if (!unique_names(vars, d_name, "Dataset", msg))
return false;
if (all)
for (Vars_iter i = vars.begin(); i != vars.end(); i++)
if (!(*i)->check_semantics(msg, true))
return false;
return true;
}
bool
DDS::mark(const string &n, bool state)
{
// TODO use auto_ptr
BaseType::btp_stack *s = new BaseType::btp_stack;
DBG2(cerr << "DDS::mark: Looking for " << n << endl);
BaseType *variable = var(n, s);
if (!variable) {
DBG2(cerr << "Could not find variable " << n << endl);
delete s; s = 0;
return false;
}
variable->set_send_p(state);
DBG2(cerr << "DDS::mark: Set variable " << variable->d_name()
<< " (a " << variable->type_name() << ")" << endl);
// Now check the btp_stack and run BaseType::set_send_p for every
// BaseType pointer on the stack. Using BaseType::set_send_p() will
// set the property for a Constructor but not its contained variables
// which preserves the semantics of projecting just one field.
while (!s->empty()) {
s->top()->BaseType::set_send_p(state);
DBG2(cerr << "DDS::mark: Set variable " << s->top()->d_name()
<< " (a " << s->top()->type_name() << ")" << endl);
// FIXME get_parent() hosed?
#if 1
string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
#endif
s->pop();
}
delete s ; s = 0;
return true;
}
void
DDS::mark_all(bool state)
{
for (Vars_iter i = vars.begin(); i != vars.end(); i++)
(*i)->set_send_p(state);
}
void
DDS::dump(ostream &strm) const
{
strm << DapIndent::LMarg << "DDS::dump - ("
<< (void *)this << ")" << endl ;
DapIndent::Indent() ;
strm << DapIndent::LMarg << "d_name: " << d_name << endl ;
strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
strm << DapIndent::LMarg << "global attributes:" << endl ;
DapIndent::Indent() ;
d_attr.dump(strm) ;
DapIndent::UnIndent() ;
if (vars.size()) {
strm << DapIndent::LMarg << "vars:" << endl ;
DapIndent::Indent() ;
Vars_citer i = vars.begin() ;
Vars_citer ie = vars.end() ;
for (; i != ie; i++) {
(*i)->dump(strm) ;
}
DapIndent::UnIndent() ;
}
else {
strm << DapIndent::LMarg << "vars: none" << endl ;
}
DapIndent::UnIndent() ;
}
} // namespace libdap
libdap::BaseType::name
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:311
libdap::DDS::print
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:1029
libdap::AttrTable::attr_end
virtual Attr_iter attr_end()
Definition: AttrTable.cc:718
libdap::DDS::insert_var_nocopy
void insert_var_nocopy(Vars_iter i, BaseType *ptr)
Definition: DDS.cc:868
libdap::AttrTable
Contains the attributes for a dataset.
Definition: AttrTable.h:142
libdap::DDS::get_vars_iter
Vars_iter get_vars_iter(int i)
Get an iterator.
Definition: DDS.cc:832
libdap::DDS::insert_var
void insert_var(Vars_iter i, BaseType *ptr)
Insert a variable before the referenced element.
Definition: DDS.cc:851
libdap::DDS::var_begin
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:805
libdap::BaseType::print_xml_writer
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: BaseType.cc:1125
libdap::add_space_encoding
string add_space_encoding(const string &s)
Definition: AttrTable.cc:77
libdap::AttrTable::get_name
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:237
libdap::DDS::DDS
DDS(BaseTypeFactory *factory, const string &name="")
Definition: DDS.cc:205
libdap::DDS::get_request_size
int get_request_size(bool constrained)
Get the estimated response size.
Definition: DDS.cc:566
std
STL namespace.
libdap::DDS::var
BaseType * var(const string &n, BaseType::btp_stack &s)
Definition: DDS.cc:698
libdap::DDS::transfer_attributes
virtual void transfer_attributes(DAS *das)
Definition: DDS.cc:287
libdap::DDS::filename
string filename() const
Definition: DDS.cc:388
libdap::DDS::print_xml
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition: DDS.cc:1149
libdap::AttrTable::print
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1242
libdap::DDS::print_xml_writer
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition: DDS.cc:1204
libdap::DDS::add_var_nocopy
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition: DDS.cc:614
libdap::Structure
Holds a structure (aggregate) type.
Definition: Structure.h:83
libdap::DDS::var_rend
Vars_riter var_rend()
Return a reverse iterator.
Definition: DDS.cc:823
libdap::DDS::get_dataset_name
string get_dataset_name() const
Definition: DDS.cc:357
libdap::DDS::num_var
int num_var()
Returns the number of variables in the DDS.
Definition: DDS.cc:879
libdap
Definition: AlarmHandler.h:35
libdap::DDS::mark
bool mark(const string &name, bool state)
Mark the send_p flag of the named variable to state.
Definition: DDS.cc:1472
libdap::InternalErr
A class for software fault reporting.
Definition: InternalErr.h:64
libdap::DDS::parse
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition: DDS.cc:948
libdap::BaseType::var
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Returns a pointer to a member of a constructor class.
Definition: BaseType.cc:749
libdap::BaseType::is_vector_type
virtual bool is_vector_type() const
Returns true if the instance is a vector (i.e., array) type variable.
Definition: BaseType.cc:393
libdap::BaseType::set_send_p
virtual void set_send_p(bool state)
Definition: BaseType.cc:559
libdap::BaseType::is_constructor_type
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable...
Definition: BaseType.cc:403
libdap::DDS::mark_all
void mark_all(bool state)
Definition: DDS.cc:1519
libdap::DDS
Definition: DDS.h:180
libdap::BaseTypeFactory
Definition: BaseTypeFactory.h:80
libdap::DDS::print_dmr
void print_dmr(ostream &out, bool constrained)
Definition: DDS.cc:1337
libdap::DDS::get_attr_table
virtual AttrTable & get_attr_table()
Definition: DDS.cc:373
libdap::DDS::get_var_index
BaseType * get_var_index(int i)
Get a variable.
Definition: DDS.cc:841
libdap::DDS::check_semantics
bool check_semantics(bool all=false)
Check the semantics of each of the variables represented in the DDS.
Definition: DDS.cc:1426
libdap::DDS::container
Structure * container()
Definition: DDS.cc:548
libdap::DDS::get_dap_major
int get_dap_major() const
Get the DAP major version as sent by the client.
Definition: DDS.h:261
libdap::DDS::get_request_xml_base
string get_request_xml_base() const
Get the URL that will return this DDS/DDX/DataThing.
Definition: DDS.h:279
libdap::DDS::container_name
string container_name()
Definition: DDS.cc:512
libdap::Error::get_error_message
string get_error_message() const
Definition: Error.cc:276
libdap::DAS::get_top_level_attributes
virtual AttrTable * get_top_level_attributes()
Returns the top most set of attributes.
Definition: DAS.h:166
libdap::DDS::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition: DDS.cc:1533
libdap::AttrTable::attr_begin
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:710
libdap::DAS::container_name
virtual string container_name() const
Returns the name of the current attribute container when multiple files used to build this DAS...
Definition: DAS.h:149
libdap::BaseType::ptr_duplicate
virtual BaseType * ptr_duplicate()=0
libdap::DDS::get_namespace
string get_namespace() const
Get the namespace associated with the DDS - likely set only by DDX responses.
Definition: DDS.h:285
libdap::www2id
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
libdap::Constructor
Definition: Constructor.h:43
libdap::DDS::var_end
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:817
libdap::DDS::tag_nested_sequences
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition: DDS.cc:936
libdap::BaseType::get_attr_table
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:573
libdap::DDS::set_dap_minor
void set_dap_minor(int p)
Definition: DDS.cc:424
libdap::DDS::set_dataset_name
void set_dataset_name(const string &n)
Definition: DDS.cc:364
libdap::BaseType
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
libdap::DapObj
libdap base object for common functionality of libdap objects
Definition: DapObj.h:55
libdap::parser_arg
Pass parameters by reference to a parser.
Definition: parser.h:68
libdap::DDS::del_var
void del_var(const string &n)
Removes a variable from the DDS.
Definition: DDS.cc:642
libdap::BaseType::type_name
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:370
libdap::Constructor::var_begin
Vars_iter var_begin()
Definition: Constructor.cc:356
libdap::DDS::var_rbegin
Vars_riter var_rbegin()
Return a reverse iterator.
Definition: DDS.cc:811
libdap::Constructor::var_end
Vars_iter var_end()
Definition: Constructor.cc:364
libdap::DAS
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:121
libdap::XMLWriter
Definition: XMLWriter.h:39
libdap::Error
A class for error processing.
Definition: Error.h:90
libdap::DDS::get_dap_minor
int get_dap_minor() const
Get the DAP minor version as sent by the client.
Definition: DDS.h:263
libdap::DDS::set_dap_major
void set_dap_major(int p)
Definition: DDS.cc:405
libdap::DDS::print_constrained
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition: DDS.cc:1103
libdap::DDS::set_dap_version
void set_dap_version(const string &version_string="2.0")
Definition: DDS.cc:441
libdap::id2www
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
libdap::DDS::add_var
void add_var(BaseType *bt)
Adds a copy of the variable to the DDS. Using the ptr_duplicate() method, perform a deep copy on the ...
Definition: DDS.cc:587