|
Packit |
a4aae4 |
|
|
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) 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 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//#define DODS_DEBUG 1
|
|
Packit |
a4aae4 |
//#define DODS_DEBUG2 1
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <cstring>
|
|
Packit |
a4aae4 |
#include <cstdarg>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "BaseType.h"
|
|
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 "DDXParserSAX2.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "mime_util.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if defined(DODS_DEBUG) || defined(DODS_DEUG2)
|
|
Packit |
a4aae4 |
static const char *states[] =
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
"start",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"dataset",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"attribute_container",
|
|
Packit |
a4aae4 |
"attribute",
|
|
Packit |
a4aae4 |
"attribute_value",
|
|
Packit |
a4aae4 |
"other_xml_attribute",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"alias",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"simple_type",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"array",
|
|
Packit |
a4aae4 |
"dimension",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"grid",
|
|
Packit |
a4aae4 |
"map",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"structure",
|
|
Packit |
a4aae4 |
"sequence",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"blob href",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"unknown",
|
|
Packit |
a4aae4 |
"error"
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
// Glue the BaseTypeFactory to the enum-based factory defined statically
|
|
Packit |
a4aae4 |
// here.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *DDXParser::factory(Type t, const string & name)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
switch (t) {
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
return d_factory->NewByte(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
return d_factory->NewInt16(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
return d_factory->NewUInt16(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
return d_factory->NewInt32(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
return d_factory->NewUInt32(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
return d_factory->NewFloat32(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
return d_factory->NewFloat64(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_str_c:
|
|
Packit |
a4aae4 |
return d_factory->NewStr(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_url_c:
|
|
Packit |
a4aae4 |
return d_factory->NewUrl(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_array_c:
|
|
Packit |
a4aae4 |
return d_factory->NewArray(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_structure_c:
|
|
Packit |
a4aae4 |
return d_factory->NewStructure(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_sequence_c:
|
|
Packit |
a4aae4 |
return d_factory->NewSequence(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_grid_c:
|
|
Packit |
a4aae4 |
return d_factory->NewGrid(name);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
return 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static bool is_not(const char *name, const char *tag)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return strcmp(name, tag) != 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void DDXParser::set_state(DDXParser::ParseState state)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
s.push(state);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DDXParser::ParseState DDXParser::get_state() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return s.top();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void DDXParser::pop_state()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
s.pop();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Dump XML attributes to local store so they can be easily manipulated.
|
|
Packit |
a4aae4 |
Attribute names are always folded to lower case.
|
|
Packit |
a4aae4 |
@param attrs The XML attribute array */
|
|
Packit |
a4aae4 |
void DDXParser::transfer_xml_attrs(const xmlChar **attributes, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!attribute_table.empty())
|
|
Packit |
a4aae4 |
attribute_table.clear(); // erase old attributes
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
unsigned int index = 0;
|
|
Packit |
a4aae4 |
for (int i = 0; i < nb_attributes; ++i, index += 5) {
|
|
Packit |
a4aae4 |
// Make a value using the attribute name and the prefix, namespace URI
|
|
Packit |
a4aae4 |
// and the value. The prefix might be null.
|
|
Packit |
a4aae4 |
attribute_table.insert(map<string, XMLAttribute>::value_type(
|
|
Packit |
a4aae4 |
string((const char *)attributes[index]),
|
|
Packit |
a4aae4 |
XMLAttribute(attributes + index + 1)));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG(cerr << "Attribute '" << (const char *)attributes[index] << "': "
|
|
Packit |
a4aae4 |
<< attribute_table[(const char *)attributes[index]].value << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void DDXParser::transfer_xml_ns(const xmlChar **namespaces, int nb_namespaces)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
for (int i = 0; i < nb_namespaces; ++i ) {
|
|
Packit |
a4aae4 |
// make a value with the prefix and namespace URI. The prefix might be
|
|
Packit |
a4aae4 |
// null.
|
|
Packit |
a4aae4 |
namespace_table.insert(map<string,string>::value_type(
|
|
Packit |
a4aae4 |
namespaces[i*2] != 0 ? (const char *)namespaces[i*2] : "",
|
|
Packit |
a4aae4 |
(const char *)namespaces[i*2+1]));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Is an attribute present? Attribute names are always lower case.
|
|
Packit |
a4aae4 |
@note To use this method, first call transfer_xml_attrs.
|
|
Packit |
a4aae4 |
@param attr The XML attribute
|
|
Packit |
a4aae4 |
@return True if the XML attribute was present in the last tag */
|
|
Packit |
a4aae4 |
bool DDXParser::check_required_attribute(const string & attr)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
map < string, XMLAttribute >::iterator i = attribute_table.find(attr);
|
|
Packit |
a4aae4 |
if (i == attribute_table.end())
|
|
Packit |
a4aae4 |
ddx_fatal_error(this, "Required attribute '%s' not found.",
|
|
Packit |
a4aae4 |
attr.c_str());
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Is an attribute present? Attribute names are always lower case.
|
|
Packit |
a4aae4 |
@note To use this method, first call transfer_xml_attrs.
|
|
Packit |
a4aae4 |
@param attr The XML attribute
|
|
Packit |
a4aae4 |
@return True if the XML attribute was present in the last/current tag,
|
|
Packit |
a4aae4 |
false otherwise. */
|
|
Packit |
a4aae4 |
bool DDXParser::check_attribute(const string & attr)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (attribute_table.find(attr) != attribute_table.end());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given that an \c Attribute tag has just been read, determine whether the
|
|
Packit |
a4aae4 |
element is a container or a simple type, set the state and, for a simple
|
|
Packit |
a4aae4 |
type record the type and name for use when \c value elements are found.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note Modified to discriminate between OtherXML and the older DAP2.0
|
|
Packit |
a4aae4 |
attribute types (container, Byte, ...).
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param attrs The array of XML attribute values */
|
|
Packit |
a4aae4 |
void DDXParser::process_attribute_element(const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// These methods set the state to parser_error if a problem is found.
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bool error = !(check_required_attribute(string("name"))
|
|
Packit |
a4aae4 |
&& check_required_attribute(string("type")));
|
|
Packit |
a4aae4 |
if (error)
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (attribute_table["type"].value == "Container") {
|
|
Packit |
a4aae4 |
set_state(inside_attribute_container);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
AttrTable *child;
|
|
Packit |
a4aae4 |
AttrTable *parent = at_stack.top();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
child = parent->append_container(attribute_table["name"].value);
|
|
Packit |
a4aae4 |
at_stack.push(child); // save.
|
|
Packit |
a4aae4 |
DBG2(cerr << "Pushing at" << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (attribute_table["type"].value == "OtherXML") {
|
|
Packit |
a4aae4 |
set_state(inside_other_xml_attribute);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dods_attr_name = attribute_table["name"].value;
|
|
Packit |
a4aae4 |
dods_attr_type = attribute_table["type"].value;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
set_state(inside_attribute);
|
|
Packit |
a4aae4 |
// *** Modify parser. Add a special state for inside OtherXML since it
|
|
Packit |
a4aae4 |
// does not use the <value> element.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dods_attr_name = attribute_table["name"].value;
|
|
Packit |
a4aae4 |
dods_attr_type = attribute_table["type"].value;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given that an \c Alias tag has just been read, set the state and process
|
|
Packit |
a4aae4 |
the alias.
|
|
Packit |
a4aae4 |
@param attrs The XML attribute array */
|
|
Packit |
a4aae4 |
void DDXParser::process_attribute_alias(const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
if (check_required_attribute(string("name"))
|
|
Packit |
a4aae4 |
&& check_required_attribute(string("attribute"))) {
|
|
Packit |
a4aae4 |
set_state(inside_alias);
|
|
Packit |
a4aae4 |
at_stack.top()->attr_alias(attribute_table["name"].value,
|
|
Packit |
a4aae4 |
attribute_table["attribute"].value);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given that a tag which opens a variable declaration has just been read,
|
|
Packit |
a4aae4 |
create the variable. Once created, push the variable onto the stack of
|
|
Packit |
a4aae4 |
variables, push that variables attribute table onto the attribute table
|
|
Packit |
a4aae4 |
stack and update the state of the parser.
|
|
Packit |
a4aae4 |
@param t The type of variable to create.
|
|
Packit |
a4aae4 |
@param s The next state of the parser.
|
|
Packit |
a4aae4 |
@param attrs the attributes read with the tag */
|
|
Packit |
a4aae4 |
void DDXParser::process_variable(Type t, ParseState s, const xmlChar **attrs,
|
|
Packit |
a4aae4 |
int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
set_state(s);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (bt_stack.top()->type() == dods_array_c
|
|
Packit |
a4aae4 |
|| check_required_attribute("name")) { // throws on error/false
|
|
Packit |
a4aae4 |
BaseType *btp = factory(t, attribute_table["name"].value);
|
|
Packit |
a4aae4 |
if (!btp) {
|
|
Packit |
a4aae4 |
ddx_fatal_error(this, "Internal parser error; could not instantiate the variable '%s'.",
|
|
Packit |
a4aae4 |
attribute_table["name"].value.c_str());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// Only run this code if btp is not null! jhrg 9/14/15
|
|
Packit |
a4aae4 |
// Once we make the new variable, we not only load it on to the
|
|
Packit |
a4aae4 |
// BaseType stack, we also load its AttrTable on the AttrTable stack.
|
|
Packit |
a4aae4 |
// The attribute processing software always operates on the AttrTable
|
|
Packit |
a4aae4 |
// at the top of the AttrTable stack (at_stack).
|
|
Packit |
a4aae4 |
bt_stack.push(btp);
|
|
Packit |
a4aae4 |
at_stack.push(&btp->get_attr_table());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given that a \c dimension tag has just been read, add that information to
|
|
Packit |
a4aae4 |
the array on the top of the BaseType stack.
|
|
Packit |
a4aae4 |
@param attrs The XML attributes included in the \c dimension tag */
|
|
Packit |
a4aae4 |
void DDXParser::process_dimension(const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
if (check_required_attribute(string("size"))) {
|
|
Packit |
a4aae4 |
set_state(inside_dimension);
|
|
Packit |
a4aae4 |
Array *ap = dynamic_cast < Array * >(bt_stack.top());
|
|
Packit |
a4aae4 |
if (!ap) {
|
|
Packit |
a4aae4 |
ddx_fatal_error(this, "Parse error: Expected an array variable.");
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
ap->append_dim(atoi(attribute_table["size"].value.c_str()),
|
|
Packit |
a4aae4 |
attribute_table["name"].value);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given that a \c blob tag has just been read, extract and save the CID
|
|
Packit |
a4aae4 |
included in the element. */
|
|
Packit |
a4aae4 |
void DDXParser::process_blob(const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
if (check_required_attribute(string("href"))) {
|
|
Packit |
a4aae4 |
set_state(inside_blob_href);
|
|
Packit |
a4aae4 |
*blob_href = attribute_table["href"].value;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Check to see if the current tag is either an \c Attribute or an \c Alias
|
|
Packit |
a4aae4 |
start tag. This method is a glorified macro...
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param name The start tag name
|
|
Packit |
a4aae4 |
@param attrs The tag's XML attributes
|
|
Packit |
a4aae4 |
@return True if the tag was an \c Attribute or \c Alias tag */
|
|
Packit |
a4aae4 |
inline bool
|
|
Packit |
a4aae4 |
DDXParser::is_attribute_or_alias(const char *name, const xmlChar **attrs,
|
|
Packit |
a4aae4 |
int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (strcmp(name, "Attribute") == 0) {
|
|
Packit |
a4aae4 |
process_attribute_element(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
// next state: inside_attribtue or inside_attribute_container
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (strcmp(name, "Alias") == 0) {
|
|
Packit |
a4aae4 |
process_attribute_alias(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
// next state: inside_alias
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Check to see if the current tag is the start of a variable declaration.
|
|
Packit |
a4aae4 |
If so, process it. A glorified macro...
|
|
Packit |
a4aae4 |
@param name The start tag name
|
|
Packit |
a4aae4 |
@param attrs The tag's XML attributes
|
|
Packit |
a4aae4 |
@return True if the tag was a variable tag */
|
|
Packit |
a4aae4 |
inline bool DDXParser::is_variable(const char *name, const xmlChar **attrs,
|
|
Packit |
a4aae4 |
int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
Type t = get_type(name);
|
|
Packit |
a4aae4 |
//if ((t = is_simple_type(name)) != dods_null_c) {
|
|
Packit |
a4aae4 |
if (is_simple_type(t)) {
|
|
Packit |
a4aae4 |
process_variable(t, inside_simple_type, attrs, nb_attributes);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (strcmp(name, "Array") == 0) {
|
|
Packit |
a4aae4 |
process_variable(dods_array_c, inside_array, attrs, nb_attributes);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (strcmp(name, "Structure") == 0) {
|
|
Packit |
a4aae4 |
process_variable(dods_structure_c, inside_structure, attrs, nb_attributes);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (strcmp(name, "Sequence") == 0) {
|
|
Packit |
a4aae4 |
process_variable(dods_sequence_c, inside_sequence, attrs, nb_attributes);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (strcmp(name, "Grid") == 0) {
|
|
Packit |
a4aae4 |
process_variable(dods_grid_c, inside_grid, attrs, nb_attributes);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void DDXParser::finish_variable(const char *tag, Type t, const char *expected)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (strcmp(tag, expected) != 0) {
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(this,
|
|
Packit |
a4aae4 |
"Expected an end tag for a %s; found '%s' instead.",
|
|
Packit |
a4aae4 |
expected, tag);
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
pop_state();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *btp = bt_stack.top();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bt_stack.pop();
|
|
Packit |
a4aae4 |
at_stack.pop();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (btp->type() != t) {
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(this,
|
|
Packit |
a4aae4 |
"Internal error: Expected a %s variable.",
|
|
Packit |
a4aae4 |
expected);
|
|
Packit |
a4aae4 |
delete btp;
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// Once libxml2 validates, this can go away. 05/30/03 jhrg
|
|
Packit |
a4aae4 |
if (t == dods_array_c
|
|
Packit |
a4aae4 |
&& static_cast<Array*>(btp)->dimensions() == 0) {
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(this,
|
|
Packit |
a4aae4 |
"No dimension element included in the Array '%s'.",
|
|
Packit |
a4aae4 |
btp->name().c_str());
|
|
Packit |
a4aae4 |
delete btp;
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *parent = bt_stack.top();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!(parent->is_vector_type() || parent->is_constructor_type())) {
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(this,
|
|
Packit |
a4aae4 |
"Tried to add the array variable '%s' to a non-constructor type (%s %s).",
|
|
Packit |
a4aae4 |
tag,
|
|
Packit |
a4aae4 |
bt_stack.top()->type_name().c_str(),
|
|
Packit |
a4aae4 |
bt_stack.top()->name().c_str());
|
|
Packit |
a4aae4 |
delete btp;
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parent->add_var_nocopy(btp);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @name SAX Parser Callbacks
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
These methods are declared static in the class header. This gives them C
|
|
Packit |
a4aae4 |
linkage which allows them to be used as callbacks by the SAX parser
|
|
Packit |
a4aae4 |
engine. */
|
|
Packit |
a4aae4 |
//@{
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Initialize the SAX parser state object. This object is passed to each
|
|
Packit |
a4aae4 |
callback as a void pointer. The initial state is parser_start.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param p The SAX parser */
|
|
Packit |
a4aae4 |
void DDXParser::ddx_start_document(void * p)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DDXParser *parser = static_cast<DDXParser*>(p);
|
|
Packit |
a4aae4 |
parser->error_msg = "";
|
|
Packit |
a4aae4 |
parser->char_data = "";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// init attr table stack.
|
|
Packit |
a4aae4 |
parser->at_stack.push(&parser->dds->get_attr_table());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Trick; DDS *should* be a child of Structure. To simplify parsing,
|
|
Packit |
a4aae4 |
// stuff a Structure on the bt_stack and dump the top level variables
|
|
Packit |
a4aae4 |
// there. Once we're done, transfer the variables to the DDS.
|
|
Packit |
a4aae4 |
parser->bt_stack.push(new Structure("dummy_dds"));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->set_state(parser_start);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG2(cerr << "Parser state: " << states[parser->get_state()] << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Clean up after finishing a parse.
|
|
Packit |
a4aae4 |
@param p The SAX parser */
|
|
Packit |
a4aae4 |
void DDXParser::ddx_end_document(void * p)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DDXParser *parser = static_cast<DDXParser*>(p);
|
|
Packit |
a4aae4 |
DBG2(cerr << "Ending state == " << states[parser->get_state()] <<
|
|
Packit |
a4aae4 |
endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->get_state() != parser_start)
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser, "The document contained unbalanced tags.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If we've found any sort of error, don't make the DDX; intern() will
|
|
Packit |
a4aae4 |
// take care of the error.
|
|
Packit |
a4aae4 |
if (parser->get_state() == parser_error) {
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Pop the temporary Structure off the stack and transfer its variables
|
|
Packit |
a4aae4 |
// to the DDS.
|
|
Packit |
a4aae4 |
Constructor *cp = dynamic_cast < Constructor * >(parser->bt_stack.top());
|
|
Packit |
a4aae4 |
if (!cp) {
|
|
Packit |
a4aae4 |
delete parser->bt_stack.top();
|
|
Packit |
a4aae4 |
parser->bt_stack.pop();
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser, "Parse error: Expected a Structure, Sequence or Grid variable.");
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end(); ++i) {
|
|
Packit |
a4aae4 |
(*i)->set_parent(0); // top-level vars have no parents
|
|
Packit |
a4aae4 |
parser->dds->add_var(*i);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
delete parser->bt_stack.top();
|
|
Packit |
a4aae4 |
parser->bt_stack.pop();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void DDXParser::ddx_sax2_start_element(void *p,
|
|
Packit |
a4aae4 |
const xmlChar *l, const xmlChar *prefix, const xmlChar *URI,
|
|
Packit |
a4aae4 |
int nb_namespaces, const xmlChar **namespaces,
|
|
Packit |
a4aae4 |
int nb_attributes, int /*nb_defaulted*/, const xmlChar **attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DDXParser *parser = static_cast<DDXParser*>(p);
|
|
Packit |
a4aae4 |
const char *localname = (const char *)l;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG2(cerr << "start element: " << localname << ", states: "
|
|
Packit |
a4aae4 |
<< states[parser->get_state()]);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case parser_start:
|
|
Packit |
a4aae4 |
if (strcmp(localname, "Dataset") == 0) {
|
|
Packit |
a4aae4 |
parser->set_state(inside_dataset);
|
|
Packit |
a4aae4 |
parser->root_ns = URI != 0 ? (const char *)URI: "";
|
|
Packit |
a4aae4 |
parser->transfer_xml_attrs(attributes, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->check_required_attribute(string("name")))
|
|
Packit |
a4aae4 |
parser->dds->set_dataset_name(parser->attribute_table["name"].value);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->check_attribute("dapVersion"))
|
|
Packit |
a4aae4 |
parser->dds->set_dap_version(parser->attribute_table["dapVersion"].value);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected response to start with a Dataset element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_dataset:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (parser->is_variable(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (strcmp(localname, "blob") == 0 || strcmp(localname, "dataBLOB") == 0) {
|
|
Packit |
a4aae4 |
parser->process_blob(attributes, nb_attributes);
|
|
Packit |
a4aae4 |
// next state: inside_data_blob
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an Attribute, Alias or variable element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute_container:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an Attribute or Alias element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (strcmp(localname, "value") == 0)
|
|
Packit |
a4aae4 |
parser->set_state(inside_attribute_value);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute_value:
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Internal parser error; unexpected state, inside value while processing element '%s'.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute:
|
|
Packit |
a4aae4 |
DBGN(cerr << endl << "\t inside_other_xml_attribute: " << localname << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->other_xml_depth++;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Accumulate the elements here
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->other_xml.append("<");
|
|
Packit |
a4aae4 |
if (prefix) {
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *)prefix);
|
|
Packit |
a4aae4 |
parser->other_xml.append(":");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml.append(localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (nb_namespaces != 0) {
|
|
Packit |
a4aae4 |
parser->transfer_xml_ns(namespaces, nb_namespaces);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (map<string,string>::iterator i = parser->namespace_table.begin();
|
|
Packit |
a4aae4 |
i != parser->namespace_table.end();
|
|
Packit |
a4aae4 |
++i) {
|
|
Packit |
a4aae4 |
parser->other_xml.append(" xmlns");
|
|
Packit |
a4aae4 |
if (!i->first.empty()) {
|
|
Packit |
a4aae4 |
parser->other_xml.append(":");
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->first);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml.append("=\"");
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->second);
|
|
Packit |
a4aae4 |
parser->other_xml.append("\"");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (nb_attributes != 0) {
|
|
Packit |
a4aae4 |
parser->transfer_xml_attrs(attributes, nb_attributes);
|
|
Packit |
a4aae4 |
for (XMLAttrMap::iterator i = parser->attr_table_begin();
|
|
Packit |
a4aae4 |
i != parser->attr_table_end();
|
|
Packit |
a4aae4 |
++i) {
|
|
Packit |
a4aae4 |
parser->other_xml.append(" ");
|
|
Packit |
a4aae4 |
if (!i->second.prefix.empty()) {
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->second.prefix);
|
|
Packit |
a4aae4 |
parser->other_xml.append(":");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->first);
|
|
Packit |
a4aae4 |
parser->other_xml.append("=\"");
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->second.value);
|
|
Packit |
a4aae4 |
parser->other_xml.append("\"");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->other_xml.append(">");
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_alias:
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Internal parser error; unexpected state, inside alias while processing element '%s'.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_simple_type:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_array:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (is_not(localname, "Array")
|
|
Packit |
a4aae4 |
&& parser->is_variable(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (strcmp(localname, "dimension") == 0) {
|
|
Packit |
a4aae4 |
parser->process_dimension(attributes, nb_attributes);
|
|
Packit |
a4aae4 |
// next state: inside_dimension
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_dimension:
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Internal parser error; unexpected state, inside dimension while processing element '%s'.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_structure:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (parser->is_variable(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an Attribute, Alias or variable element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_sequence:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (parser->is_variable(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an Attribute, Alias or variable element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_grid:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (strcmp(localname, "Array") == 0)
|
|
Packit |
a4aae4 |
parser->process_variable(dods_array_c, inside_array, attributes, nb_attributes);
|
|
Packit |
a4aae4 |
else if (strcmp(localname, "Map") == 0)
|
|
Packit |
a4aae4 |
parser->process_variable(dods_array_c, inside_map, attributes, nb_attributes);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an Attribute, Alias or variable element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_map:
|
|
Packit |
a4aae4 |
if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (is_not(localname, "Array") && is_not(localname, "Sequence")
|
|
Packit |
a4aae4 |
&& is_not(localname, "Grid")
|
|
Packit |
a4aae4 |
&& parser->is_variable(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (strcmp(localname, "dimension") == 0) {
|
|
Packit |
a4aae4 |
parser->process_dimension(attributes, nb_attributes);
|
|
Packit |
a4aae4 |
// next state: inside_dimension
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_blob_href:
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Internal parser error; unexpected state, inside blob href while processing element '%s'.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_unknown:
|
|
Packit |
a4aae4 |
// *** Never used? If so remove/error
|
|
Packit |
a4aae4 |
parser->set_state(parser_unknown);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_error:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBGN(cerr << " ... " << states[parser->get_state()] << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void DDXParser::ddx_sax2_end_element(void *p, const xmlChar *l,
|
|
Packit |
a4aae4 |
const xmlChar *prefix, const xmlChar *URI)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DDXParser *parser = static_cast<DDXParser*>(p);
|
|
Packit |
a4aae4 |
const char *localname = (const char *)l;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG2(cerr << "End element " << localname << " (state "
|
|
Packit |
a4aae4 |
<< states[parser->get_state()] << ")" << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case parser_start:
|
|
Packit |
a4aae4 |
ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Internal parser error; unexpected state, inside start state while processing element '%s'.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_dataset:
|
|
Packit |
a4aae4 |
if (strcmp(localname, "Dataset") == 0)
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an end Dataset tag; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute_container:
|
|
Packit |
a4aae4 |
if (strcmp(localname, "Attribute") == 0) {
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
parser->at_stack.pop(); // pop when leaving a container.
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an end Attribute tag; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute:
|
|
Packit |
a4aae4 |
if (strcmp(localname, "Attribute") == 0)
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an end Attribute tag; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute_value:
|
|
Packit |
a4aae4 |
if (strcmp(localname, "value") == 0) {
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
AttrTable *atp = parser->at_stack.top();
|
|
Packit |
a4aae4 |
atp->append_attr(parser->dods_attr_name,
|
|
Packit |
a4aae4 |
parser->dods_attr_type, parser->char_data);
|
|
Packit |
a4aae4 |
parser->char_data = ""; // Null this after use.
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an end value tag; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute: {
|
|
Packit |
a4aae4 |
if (strcmp(localname, "Attribute") == 0
|
|
Packit |
a4aae4 |
&& parser->root_ns == (const char *)URI) {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBGN(cerr << endl << "\t Popping the 'inside_other_xml_attribute' state"
|
|
Packit |
a4aae4 |
<< endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
AttrTable *atp = parser->at_stack.top();
|
|
Packit |
a4aae4 |
atp->append_attr(parser->dods_attr_name,
|
|
Packit |
a4aae4 |
parser->dods_attr_type, parser->other_xml);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->other_xml = ""; // Null this after use.
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
DBGN(cerr << endl << "\t inside_other_xml_attribute: " << localname
|
|
Packit |
a4aae4 |
<< ", depth: " << parser->other_xml_depth << endl);
|
|
Packit |
a4aae4 |
if (parser->other_xml_depth == 0)
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an OtherXML attribute to end! Instead I found '%s'",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
parser->other_xml_depth--;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->other_xml.append("</");
|
|
Packit |
a4aae4 |
if (prefix) {
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *)prefix);
|
|
Packit |
a4aae4 |
parser->other_xml.append(":");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml.append(localname);
|
|
Packit |
a4aae4 |
parser->other_xml.append(">");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// Alias is busted in libdap++ 05/29/03 jhrg
|
|
Packit |
a4aae4 |
case inside_alias:
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_simple_type: {
|
|
Packit |
a4aae4 |
Type t = get_type(localname);
|
|
Packit |
a4aae4 |
if (is_simple_type(t)) {
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
BaseType *btp = parser->bt_stack.top();
|
|
Packit |
a4aae4 |
parser->bt_stack.pop();
|
|
Packit |
a4aae4 |
parser->at_stack.pop();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *parent = parser->bt_stack.top();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parent->is_vector_type() || parent->is_constructor_type()) {
|
|
Packit |
a4aae4 |
parent->add_var(btp);
|
|
Packit |
a4aae4 |
delete btp;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).",
|
|
Packit |
a4aae4 |
localname,
|
|
Packit |
a4aae4 |
parser->bt_stack.top()->
|
|
Packit |
a4aae4 |
type_name().c_str(),
|
|
Packit |
a4aae4 |
parser->bt_stack.top()->name().
|
|
Packit |
a4aae4 |
c_str());
|
|
Packit |
a4aae4 |
delete btp;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an end tag for a simple type; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_array:
|
|
Packit |
a4aae4 |
parser->finish_variable(localname, dods_array_c, "Array");
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_dimension:
|
|
Packit |
a4aae4 |
if (strcmp(localname, "dimension") == 0)
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an end dimension tag; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_structure:
|
|
Packit |
a4aae4 |
parser->finish_variable(localname, dods_structure_c, "Structure");
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_sequence:
|
|
Packit |
a4aae4 |
parser->finish_variable(localname, dods_sequence_c, "Sequence");
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_grid:
|
|
Packit |
a4aae4 |
parser->finish_variable(localname, dods_grid_c, "Grid");
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_map:
|
|
Packit |
a4aae4 |
parser->finish_variable(localname, dods_array_c, "Map");
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_blob_href:
|
|
Packit |
a4aae4 |
if (strcmp(localname, "blob") == 0 || strcmp(localname, "dataBLOB") == 0)
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected an end dataBLOB/blob tag; found '%s' instead.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_unknown:
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_error:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBGN(cerr << " ... " << states[parser->get_state()] << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Process/accumulate character data. This may be called more than once for
|
|
Packit |
a4aae4 |
one logical clump of data. Only save character data when processing
|
|
Packit |
a4aae4 |
'value' elements; throw away all other characters. */
|
|
Packit |
a4aae4 |
void DDXParser::ddx_get_characters(void * p, const xmlChar * ch, int len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DDXParser *parser = static_cast<DDXParser*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case inside_attribute_value:
|
|
Packit |
a4aae4 |
parser->char_data.append((const char *)(ch), len);
|
|
Packit |
a4aae4 |
DBG2(cerr << "Characters: '" << parser->char_data << "'" << endl);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute:
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *)(ch), len);
|
|
Packit |
a4aae4 |
DBG2(cerr << "Other XML Characters: '" << parser->other_xml << "'" << endl);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Read whitespace that's not really important for content. This is used
|
|
Packit |
a4aae4 |
only for the OtherXML attribute type to preserve formating of the XML.
|
|
Packit |
a4aae4 |
Doing so makes the attribute value far easier to read.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void DDXParser::ddx_ignoreable_whitespace(void *p, const xmlChar *ch,
|
|
Packit |
a4aae4 |
int len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DDXParser *parser = static_cast<DDXParser*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute:
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *)(ch), len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get characters in a cdata block. DAP does not use CData, but XML in an
|
|
Packit |
a4aae4 |
OtherXML attribute (the value of that DAP attribute) might use it. This
|
|
Packit |
a4aae4 |
callback also allows CData when the parser is in the 'parser_unknown'
|
|
Packit |
a4aae4 |
state since some future DAP element might use it.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void DDXParser::ddx_get_cdata(void *p, const xmlChar *value, int len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DDXParser *parser = static_cast<DDXParser*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute:
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *)(value), len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_unknown:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
DDXParser::ddx_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Found a CData block but none are allowed by DAP.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Handle the standard XML entities.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param parser The SAX parser
|
|
Packit |
a4aae4 |
@param name The XML entity. */
|
|
Packit |
a4aae4 |
xmlEntityPtr DDXParser::ddx_get_entity(void *, const xmlChar * name)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return xmlGetPredefinedEntity(name);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Process an XML fatal error. Note that SAX provides for warnings, errors
|
|
Packit |
a4aae4 |
and fatal errors. This code treats them all as fatal errors since there's
|
|
Packit |
a4aae4 |
typically no way to tell a user about the error since there's often no
|
|
Packit |
a4aae4 |
user interface for this software.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param p The SAX parser
|
|
Packit |
a4aae4 |
@param msg A printf-style format string. */
|
|
Packit |
a4aae4 |
void DDXParser::ddx_fatal_error(void * p, const char *msg, ...)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
va_list args;
|
|
Packit |
a4aae4 |
DDXParser *parser = static_cast<DDXParser*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->set_state(parser_error);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
va_start(args, msg);
|
|
Packit |
a4aae4 |
char str[1024];
|
|
Packit |
a4aae4 |
vsnprintf(str, 1024, msg, args);
|
|
Packit |
a4aae4 |
va_end(args);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int line = xmlSAX2GetLineNumber(parser->ctxt);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->error_msg += "At line " + long_to_string(line) + ": ";
|
|
Packit |
a4aae4 |
parser->error_msg += string(str) + string("\n");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//@}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void DDXParser::cleanup_parse(xmlParserCtxtPtr & context)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
bool wellFormed = context->wellFormed;
|
|
Packit |
a4aae4 |
bool valid = context->valid;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
context->sax = NULL;
|
|
Packit |
a4aae4 |
xmlFreeParserCtxt(context);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If there's an error, there may still be items on the stack at the
|
|
Packit |
a4aae4 |
// end of the parse.
|
|
Packit |
a4aae4 |
while (!bt_stack.empty()) {
|
|
Packit |
a4aae4 |
delete bt_stack.top();
|
|
Packit |
a4aae4 |
bt_stack.pop();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!wellFormed) {
|
|
Packit |
a4aae4 |
throw DDXParseFailed(string("The DDX is not a well formed XML document.\n") + error_msg);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!valid) {
|
|
Packit |
a4aae4 |
throw DDXParseFailed(string("The DDX is not a valid document.\n") + error_msg);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (get_state() == parser_error) {
|
|
Packit |
a4aae4 |
throw DDXParseFailed(string("Error parsing DDX response.\n") + error_msg);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Read a DDX from a C++ input stream and populate a DDS object.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param in
|
|
Packit |
a4aae4 |
* @param dds
|
|
Packit |
a4aae4 |
* @param cid
|
|
Packit |
a4aae4 |
* @param boundary
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void DDXParser::intern_stream(istream &in, DDS *dest_dds, string &cid, const string &boundary)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Code example from libxml2 docs re: read from a stream.
|
|
Packit |
a4aae4 |
if (!in || in.eof())
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Input stream not open or read error");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
const int size = 1024;
|
|
Packit |
a4aae4 |
char chars[size + 1];
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// int res = fread(chars, 1, 4, in);
|
|
Packit |
a4aae4 |
in.read(chars, 4);
|
|
Packit |
a4aae4 |
int res = in.gcount();
|
|
Packit |
a4aae4 |
if (res > 0) {
|
|
Packit |
a4aae4 |
chars[4]='\0';
|
|
Packit |
a4aae4 |
xmlParserCtxtPtr context = xmlCreatePushParserCtxt(NULL, NULL, chars, res, "stream");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!context)
|
|
Packit |
a4aae4 |
throw DDXParseFailed("Error parsing DDX response: Input does not look like XML");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
ctxt = context; // need ctxt for error messages
|
|
Packit |
a4aae4 |
dds = dest_dds; // dump values here
|
|
Packit |
a4aae4 |
blob_href = &cid; // cid goes here
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
xmlSAXHandler ddx_sax_parser;
|
|
Packit |
a4aae4 |
memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) );
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity;
|
|
Packit |
a4aae4 |
ddx_sax_parser.startDocument = &DDXParser::ddx_start_document;
|
|
Packit |
a4aae4 |
ddx_sax_parser.endDocument = &DDXParser::ddx_end_document;
|
|
Packit |
a4aae4 |
ddx_sax_parser.characters = &DDXParser::ddx_get_characters;
|
|
Packit |
a4aae4 |
ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace;
|
|
Packit |
a4aae4 |
ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata;
|
|
Packit |
a4aae4 |
ddx_sax_parser.warning = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.error = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.initialized = XML_SAX2_MAGIC;
|
|
Packit |
a4aae4 |
ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element;
|
|
Packit |
a4aae4 |
ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
context->sax = &ddx_sax_parser;
|
|
Packit |
a4aae4 |
context->userData = this;
|
|
Packit |
a4aae4 |
context->validate = true;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
in.getline(chars, size); // chars has size+1 elements
|
|
Packit |
a4aae4 |
res = in.gcount();
|
|
Packit |
a4aae4 |
chars[res-1] = '\n'; // libxml needs the newline; w/o it the parse will fail
|
|
Packit |
a4aae4 |
chars[res] = '\0';
|
|
Packit |
a4aae4 |
while (res > 0 && !is_boundary(chars, boundary)) {
|
|
Packit |
a4aae4 |
DBG(cerr << "line (" << res << "): " << chars << endl);
|
|
Packit |
a4aae4 |
xmlParseChunk(ctxt, chars, res, 0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
in.getline(chars, size); // chars has size+1 elements
|
|
Packit |
a4aae4 |
res = in.gcount();
|
|
Packit |
a4aae4 |
if (res > 0) {
|
|
Packit |
a4aae4 |
chars[res-1] = '\n';
|
|
Packit |
a4aae4 |
chars[res] = '\0';
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This call ends the parse: The fourth argument of xmlParseChunk is
|
|
Packit |
a4aae4 |
// the bool 'terminate.'
|
|
Packit |
a4aae4 |
xmlParseChunk(ctxt, chars, 0, 1);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
cleanup_parse(context);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
throw DDXParseFailed("Error parsing DDX response: Could not read from input stream.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Read the DDX from a stream instead of a file.
|
|
Packit |
a4aae4 |
@see DDXParser::intern(). */
|
|
Packit |
a4aae4 |
void DDXParser::intern_stream(FILE *in, DDS *dest_dds, string &cid, const string &boundary)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Code example from libxml2 docs re: read from a stream.
|
|
Packit |
a4aae4 |
if (!in || feof(in) || ferror(in))
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Input stream not open or read error");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
const int size = 1024;
|
|
Packit |
a4aae4 |
char chars[size];
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int res = fread(chars, 1, 4, in);
|
|
Packit |
a4aae4 |
if (res > 0) {
|
|
Packit |
a4aae4 |
chars[4]='\0';
|
|
Packit |
a4aae4 |
xmlParserCtxtPtr context = xmlCreatePushParserCtxt(NULL, NULL, chars, res, "stream");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!context)
|
|
Packit |
a4aae4 |
throw DDXParseFailed("Error parsing DDX response: Input does not look like XML");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
ctxt = context; // need ctxt for error messages
|
|
Packit |
a4aae4 |
dds = dest_dds; // dump values here
|
|
Packit |
a4aae4 |
blob_href = &cid; // cid goes here
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
xmlSAXHandler ddx_sax_parser;
|
|
Packit |
a4aae4 |
memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) );
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity;
|
|
Packit |
a4aae4 |
ddx_sax_parser.startDocument = &DDXParser::ddx_start_document;
|
|
Packit |
a4aae4 |
ddx_sax_parser.endDocument = &DDXParser::ddx_end_document;
|
|
Packit |
a4aae4 |
ddx_sax_parser.characters = &DDXParser::ddx_get_characters;
|
|
Packit |
a4aae4 |
ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace;
|
|
Packit |
a4aae4 |
ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata;
|
|
Packit |
a4aae4 |
ddx_sax_parser.warning = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.error = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.initialized = XML_SAX2_MAGIC;
|
|
Packit |
a4aae4 |
ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element;
|
|
Packit |
a4aae4 |
ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
context->sax = &ddx_sax_parser;
|
|
Packit |
a4aae4 |
context->userData = this;
|
|
Packit |
a4aae4 |
context->validate = true;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
while ((fgets(chars, size, in) != 0) && !is_boundary(chars, boundary)) {
|
|
Packit |
a4aae4 |
DBG(cerr << "line (" << strlen(chars) << "): " << chars << endl);
|
|
Packit |
a4aae4 |
xmlParseChunk(ctxt, chars, strlen(chars), 0);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// This call ends the parse: The fourth argument of xmlParseChunk is
|
|
Packit |
a4aae4 |
// the bool 'terminate.'
|
|
Packit |
a4aae4 |
xmlParseChunk(ctxt, chars, 0, 1);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
cleanup_parse(context);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
throw DDXParseFailed("Error parsing DDX response: Could not read from input file.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Parse a DDX document stored in a file. The XML in the document is parsed
|
|
Packit |
a4aae4 |
and a binary DDX is built. This implementation stores the result in a DDS
|
|
Packit |
a4aae4 |
object where each instance of BaseType can hold an AttrTable object.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param document Read the DDX from this file.
|
|
Packit |
a4aae4 |
@param dest_dds Value/result parameter; dumps the information to this DDS
|
|
Packit |
a4aae4 |
instance.
|
|
Packit |
a4aae4 |
@param cid Value/result parameter; puts the href which references the \c
|
|
Packit |
a4aae4 |
CID.
|
|
Packit |
a4aae4 |
@exception DDXParseFailed Thrown if the XML document could not be
|
|
Packit |
a4aae4 |
read or parsed. */
|
|
Packit |
a4aae4 |
void DDXParser::intern(const string & document, DDS * dest_dds, string &cid)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Create the context pointer explicitly so that we can store a pointer
|
|
Packit |
a4aae4 |
// to it in the DDXParser instance. This provides a way to generate our
|
|
Packit |
a4aae4 |
// own error messages *with* line numbers. The messages are pretty
|
|
Packit |
a4aae4 |
// meaningless otherwise. This means that we use an interface from the
|
|
Packit |
a4aae4 |
// 'parser internals' header, and not the 'parser' header. However, this
|
|
Packit |
a4aae4 |
// interface is also used in one of the documented examples, so it's
|
|
Packit |
a4aae4 |
// probably pretty stable. 06/02/03 jhrg
|
|
Packit |
a4aae4 |
xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str());
|
|
Packit |
a4aae4 |
if (!context)
|
|
Packit |
a4aae4 |
throw
|
|
Packit |
a4aae4 |
DDXParseFailed(string
|
|
Packit |
a4aae4 |
("Could not initialize the parser with the file: '")
|
|
Packit |
a4aae4 |
+ document + string("'."));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dds = dest_dds; // dump values here
|
|
Packit |
a4aae4 |
blob_href = &cid;
|
|
Packit |
a4aae4 |
ctxt = context; // need ctxt for error messages
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
xmlSAXHandler ddx_sax_parser;
|
|
Packit |
a4aae4 |
memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) );
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity;
|
|
Packit |
a4aae4 |
ddx_sax_parser.startDocument = &DDXParser::ddx_start_document;
|
|
Packit |
a4aae4 |
ddx_sax_parser.endDocument = &DDXParser::ddx_end_document;
|
|
Packit |
a4aae4 |
ddx_sax_parser.characters = &DDXParser::ddx_get_characters;
|
|
Packit |
a4aae4 |
ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace;
|
|
Packit |
a4aae4 |
ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata;
|
|
Packit |
a4aae4 |
ddx_sax_parser.warning = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.error = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error;
|
|
Packit |
a4aae4 |
ddx_sax_parser.initialized = XML_SAX2_MAGIC;
|
|
Packit |
a4aae4 |
ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element;
|
|
Packit |
a4aae4 |
ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
context->sax = &ddx_sax_parser;
|
|
Packit |
a4aae4 |
context->userData = this;
|
|
Packit |
a4aae4 |
context->validate = false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
xmlParseDocument(context);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
cleanup_parse(context);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|