33 #include <curl/curl.h>
35 #include <libdap/BaseType.h>
36 #include <libdap/D4Attributes.h>
37 #include <libdap/XMLWriter.h>
38 #include <libdap/util.h>
40 #define PUGIXML_NO_XPATH
41 #define PUGIXML_HEADER_ONLY
42 #include <pugixml.hpp>
45 #include "BESIndent.h"
48 #include "BESInternalError.h"
50 #include "DmrppRequestHandler.h"
51 #include "DmrppCommon.h"
53 #include "byteswap_compat.h"
58 #define prolog std::string("DmrppCommon::").append(__func__).append("() - ")
63 static const string dmrpp_3 =
"dmrpp:3";
64 static const string dmrpp_4 =
"dmrpp:4";
66 bool DmrppCommon::d_print_chunks =
false;
67 string DmrppCommon::d_dmrpp_ns =
"http://xml.opendap.org/dap/dmrpp/1.0.0#";
68 string DmrppCommon::d_ns_prefix =
"dmrpp";
81 void join_threads(pthread_t threads[],
unsigned int num_threads)
84 for (
unsigned int i = 0; i < num_threads; ++i) {
86 BESDEBUG(dmrpp_3,
"Join thread " << i <<
" after an exception was caught." << endl);
88 if ((status = pthread_join(threads[i], (
void **) &error)) < 0) {
89 BESDEBUG(dmrpp_3,
"Could not join thread " << i <<
", " << strerror(status)<< endl);
91 else if (error != NULL) {
92 BESDEBUG(dmrpp_3,
"Joined thread " << i <<
", error exit: " << *error << endl);
95 BESDEBUG(dmrpp_3,
"Joined thread " << i <<
", successful exit." << endl);
102 void DmrppCommon::set_filter(
const string &value) {
103 if (DmrppRequestHandler::d_emulate_original_filter_order_behavior) {
105 if (value.find(
"shuffle") != string::npos)
106 d_filters.append(
" shuffle");
107 if (value.find(
"deflate") != string::npos)
108 d_filters.append(
" deflate");
109 if (value.find(
"fletcher32") != string::npos)
110 d_filters.append(
" fletcher32");
128 void DmrppCommon::parse_chunk_dimension_sizes(
const string &chunk_dims_string)
130 d_chunk_dimension_sizes.clear();
132 if (chunk_dims_string.empty())
return;
134 string chunk_dims = chunk_dims_string;
136 if (chunk_dims.find_first_not_of(
"1234567890 ") != string::npos)
137 throw BESInternalError(
"while processing chunk dimension information, illegal character(s)", __FILE__, __LINE__);
145 if (chunk_dims.find(space) != string::npos) {
147 while ((strPos = chunk_dims.find(space)) != string::npos) {
148 strVal = chunk_dims.substr(0, strPos);
150 d_chunk_dimension_sizes.push_back(strtol(strVal.c_str(),
nullptr, 10));
151 chunk_dims.erase(0, strPos + space.length());
157 d_chunk_dimension_sizes.push_back(strtol(chunk_dims.c_str(),
nullptr, 10));
166 void DmrppCommon::ingest_compression_type(
const string &compression_type_string)
168 if (compression_type_string.empty())
return;
169 set_filter(compression_type_string);
177 void DmrppCommon::ingest_byte_order(
const string &byte_order_string) {
179 if (byte_order_string.empty())
return;
182 if (byte_order_string.compare(
"LE") == 0) {
184 d_twiddle_bytes = is_host_big_endian();
186 if (byte_order_string.compare(
"BE") == 0) {
188 d_twiddle_bytes = !(is_host_big_endian());
208 unsigned long DmrppCommon::add_chunk(
209 shared_ptr<http::url> data_url,
210 const string &byte_order,
211 unsigned long long size,
212 unsigned long long offset,
213 const string &position_in_array)
215 vector<unsigned long long> cpia_vector;
216 Chunk::parse_chunk_position_in_array_string(position_in_array, cpia_vector);
217 return add_chunk(move(data_url), byte_order, size, offset, cpia_vector);
232 unsigned long DmrppCommon::add_chunk(
233 shared_ptr<http::url> data_url,
234 const string &byte_order,
235 unsigned long long size,
236 unsigned long long offset,
237 const vector<unsigned long long> &position_in_array)
239 std::shared_ptr<Chunk> chunk(
new Chunk(move(data_url), byte_order, size, offset, position_in_array));
241 d_chunks.push_back(chunk);
242 return d_chunks.size();
260 unsigned long DmrppCommon::add_chunk(
261 const string &byte_order,
262 unsigned long long size,
263 unsigned long long offset,
264 const string &position_in_array)
266 vector<unsigned long long> cpia_vector;
267 Chunk::parse_chunk_position_in_array_string(position_in_array, cpia_vector);
268 return add_chunk(byte_order, size, offset, cpia_vector);
285 unsigned long DmrppCommon::add_chunk(
286 const string &byte_order,
287 unsigned long long size,
288 unsigned long long offset,
289 const vector<unsigned long long> &position_in_array)
291 shared_ptr<Chunk> chunk(
new Chunk( byte_order, size, offset, position_in_array));
293 d_chunks.push_back(chunk);
294 return d_chunks.size();
297 unsigned long DmrppCommon::add_chunk(
298 const string &byte_order,
301 unsigned long long chunk_size,
302 const vector<unsigned long long> &position_in_array)
304 shared_ptr<Chunk> chunk(
new Chunk(byte_order,
fill_value, fv_type, chunk_size, position_in_array));
306 d_chunks.push_back(chunk);
307 return d_chunks.size();
328 DmrppCommon::read_atomic(
const string &name)
330 if (get_chunks_size() != 1)
331 throw BESInternalError(
string(
"Expected only a single chunk for variable ") + name, __FILE__, __LINE__);
333 auto chunk = get_immutable_chunks()[0];
337 return chunk->get_rbuf();
354 DmrppCommon::print_chunks_element(XMLWriter &xml,
const string &name_space)
357 if (xmlTextWriterStartElementNS(xml.get_writer(), (
const xmlChar*)name_space.c_str(), (
const xmlChar*)
"chunks", NULL) < 0)
358 throw BESInternalError(
"Could not start chunks element.", __FILE__, __LINE__);
360 if (!d_filters.empty())
361 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"compressionType", (
const xmlChar*) d_filters.c_str()) < 0)
362 throw BESInternalError(
"Could not write compression attribute.", __FILE__, __LINE__);
364 if (d_uses_fill_value && !d_fill_value_str.empty()) {
365 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"fillValue", (
const xmlChar*) d_fill_value_str.c_str()) < 0)
366 throw BESInternalError(
"Could not write fillValue attribute.", __FILE__, __LINE__);
369 if(!d_chunks.empty()) {
370 auto first_chunk = get_immutable_chunks().front();
371 if (!first_chunk->get_byte_order().empty()) {
372 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"byteOrder",
373 (
const xmlChar *) first_chunk->get_byte_order().c_str()) < 0)
374 throw BESInternalError(
"Could not write attribute byteOrder", __FILE__, __LINE__);
378 if (!d_chunk_dimension_sizes.empty()) {
381 copy(d_chunk_dimension_sizes.begin(), d_chunk_dimension_sizes.end(), ostream_iterator<unsigned int>(oss,
" "));
382 string sizes = oss.str();
383 sizes.erase(sizes.size() - 1, 1);
385 if (xmlTextWriterWriteElementNS(xml.get_writer(), (
const xmlChar*) name_space.c_str(), (
const xmlChar*)
"chunkDimensionSizes", NULL,
386 (
const xmlChar*) sizes.c_str()) < 0)
throw BESInternalError(
"Could not write chunkDimensionSizes attribute.", __FILE__, __LINE__);
390 for(
auto chunk: get_immutable_chunks()) {
392 if (xmlTextWriterStartElementNS(xml.get_writer(), (
const xmlChar*)name_space.c_str(), (
const xmlChar*)
"chunk", NULL) < 0)
393 throw BESInternalError(
"Could not start element chunk", __FILE__, __LINE__);
396 ostringstream offset;
397 offset << chunk->get_offset();
398 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"offset",
399 (
const xmlChar *) offset.str().c_str()) < 0)
400 throw BESInternalError(
"Could not write attribute offset", __FILE__, __LINE__);
403 ostringstream nBytes;
404 nBytes << chunk->get_size();
405 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"nBytes",
406 (
const xmlChar *) nBytes.str().c_str()) < 0)
407 throw BESInternalError(
"Could not write attribute nBytes", __FILE__, __LINE__);
409 if (chunk->get_position_in_array().size() > 0) {
411 vector<unsigned long long> pia = chunk->get_position_in_array();
414 copy(pia.begin(), pia.end(), ostream_iterator<unsigned int>(oss,
","));
415 string pia_str = oss.str();
416 if (pia.size() > 0) pia_str.replace(pia_str.size() - 1, 1,
"]");
417 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"chunkPositionInArray", (
const xmlChar*) pia_str.c_str()) < 0)
418 throw BESInternalError(
"Could not write attribute position in array", __FILE__, __LINE__);
422 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw BESInternalError(
"Could not end chunk element", __FILE__, __LINE__);
425 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw BESInternalError(
"Could not end chunks element", __FILE__, __LINE__);
432 DmrppCommon::print_compact_element(XMLWriter &xml,
const string &name_space,
const std::string &encoded)
436 copy(encoded.begin(), encoded.end(), ostream_iterator<char>(oss,
""));
437 string sizes = oss.str();
439 if (xmlTextWriterWriteElementNS(xml.get_writer(), (
const xmlChar *) name_space.c_str(),
440 (
const xmlChar *)
"compact", NULL,
441 (
const xmlChar *) sizes.c_str()) < 0)
442 throw BESInternalError(
"Could not write compact element.", __FILE__, __LINE__);
455 void DmrppCommon::print_dmrpp(XMLWriter &xml,
bool constrained )
457 BaseType &bt =
dynamic_cast<BaseType&
>(*this);
458 if (constrained && !bt.send_p())
461 if (xmlTextWriterStartElement(xml.get_writer(), (
const xmlChar*)bt.type_name().c_str()) < 0)
462 throw InternalErr(__FILE__, __LINE__,
"Could not write " + bt.type_name() +
" element");
464 if (!bt.name().empty())
465 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"name", (
const xmlChar*)bt.name().c_str()) < 0)
466 throw InternalErr(__FILE__, __LINE__,
"Could not write attribute for name");
469 bt.attributes()->print_dap4(xml);
471 if (!bt.is_dap4() && bt.get_attr_table().get_size() > 0)
472 bt.get_attr_table().print_xml_writer(xml);
475 if (DmrppCommon::d_print_chunks && get_chunks_size() > 0)
476 print_chunks_element(xml, DmrppCommon::d_ns_prefix);
478 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
479 throw InternalErr(__FILE__, __LINE__,
"Could not end " + bt.type_name() +
" element");
482 void DmrppCommon::dump(ostream & strm)
const
484 strm << BESIndent::LMarg <<
"is_filters_empty: " << (is_filters_empty() ?
"true" :
"false") << endl;
485 strm << BESIndent::LMarg <<
"filters: " << (d_filters.c_str()) << endl;
487 const vector<unsigned long long> &chunk_dim_sizes = get_chunk_dimension_sizes();
489 strm << BESIndent::LMarg <<
"chunk dimension sizes: [";
490 for (
unsigned int i = 0; i < chunk_dim_sizes.size(); i++) {
491 strm << (i ?
"][" :
"") << chunk_dim_sizes[i];
495 auto chunk_refs = get_immutable_chunks();
496 strm << BESIndent::LMarg <<
"Chunks (aka chunks):" << (chunk_refs.size() ?
"" :
"None Found.") << endl;
498 for (
auto & chunk_ref : chunk_refs) {
499 strm << BESIndent::LMarg;
500 chunk_ref->dump(strm);
510 DmrppCommon::load_chunks(BaseType *btp) {
511 d_dmz->load_chunks(btp);
519 DmrppCommon::load_attributes(libdap::BaseType *btp)
521 d_dmz->load_attributes(btp);
exception thrown if internal error encountered
static void removeLeadingAndTrailingBlanks(std::string &key)