35#include <libdap/BaseType.h>
36#include <libdap/Str.h>
37#include <libdap/Byte.h>
38#include <libdap/D4Attributes.h>
39#include <libdap/XMLWriter.h>
40#include <libdap/util.h>
43#define PUGIXML_NO_XPATH
44#define PUGIXML_HEADER_ONLY
51#include "BESInternalError.h"
53#include "DmrppRequestHandler.h"
54#include "DmrppCommon.h"
56#include "byteswap_compat.h"
62#define prolog std::string("DmrppCommon::").append(__func__).append("() - ")
67static const string dmrpp_3 =
"dmrpp:3";
68static const string dmrpp_4 =
"dmrpp:4";
85void join_threads(pthread_t threads[],
unsigned int num_threads)
88 for (
unsigned int i = 0; i < num_threads; ++i) {
90 BESDEBUG(dmrpp_3,
"Join thread " << i <<
" after an exception was caught." << endl);
92 if ((status = pthread_join(threads[i], (
void **) &error)) < 0) {
93 BESDEBUG(dmrpp_3,
"Could not join thread " << i <<
", " << strerror(status)<< endl);
95 else if (error != NULL) {
96 BESDEBUG(dmrpp_3,
"Joined thread " << i <<
", error exit: " << *error << endl);
99 BESDEBUG(dmrpp_3,
"Joined thread " << i <<
", successful exit." << endl);
107 if (DmrppRequestHandler::d_emulate_original_filter_order_behavior) {
109 if (value.find(
"shuffle") != string::npos)
110 d_filters.append(
" shuffle");
111 if (value.find(
"deflate") != string::npos)
112 d_filters.append(
" deflate");
113 if (value.find(
"fletcher32") != string::npos)
114 d_filters.append(
" fletcher32");
134 d_chunk_dimension_sizes.clear();
136 if (chunk_dims_string.empty())
return;
138 string chunk_dims = chunk_dims_string;
140 if (chunk_dims.find_first_not_of(
"1234567890 ") != string::npos)
141 throw BESInternalError(
"while processing chunk dimension information, illegal character(s)", __FILE__, __LINE__);
149 if (chunk_dims.find(space) != string::npos) {
151 while ((strPos = chunk_dims.find(space)) != string::npos) {
152 strVal = chunk_dims.substr(0, strPos);
154 d_chunk_dimension_sizes.push_back(strtol(strVal.c_str(),
nullptr, 10));
155 chunk_dims.erase(0, strPos + space.size());
161 d_chunk_dimension_sizes.push_back(strtol(chunk_dims.c_str(),
nullptr, 10));
172 if (compression_type_string.empty())
return;
183 if (byte_order_string.empty())
return;
186 if (byte_order_string.compare(
"LE") == 0) {
188 d_twiddle_bytes = is_host_big_endian();
190 if (byte_order_string.compare(
"BE") == 0) {
192 d_twiddle_bytes = !(is_host_big_endian());
213 shared_ptr<http::url> data_url,
214 const string &byte_order,
215 unsigned long long size,
216 unsigned long long offset,
217 const string &position_in_array)
219 vector<unsigned long long> cpia_vector;
220 Chunk::parse_chunk_position_in_array_string(position_in_array, cpia_vector);
221 return add_chunk(std::move(data_url), byte_order, size, offset, cpia_vector);
225 shared_ptr<http::url> data_url,
226 const string &byte_order,
227 unsigned long long size,
228 unsigned long long offset,
229 unsigned int filter_mask,
230 const string &position_in_array)
232 vector<unsigned long long> cpia_vector;
233 Chunk::parse_chunk_position_in_array_string(position_in_array, cpia_vector);
234 return add_chunk(std::move(data_url), byte_order, size, offset,filter_mask,cpia_vector);
249 shared_ptr<http::url> data_url,
250 const string &byte_order,
251 unsigned long long size,
252 unsigned long long offset,
253 const vector<unsigned long long> &position_in_array)
255 std::shared_ptr<Chunk> chunk(
new Chunk(std::move(data_url), byte_order, size, offset, position_in_array));
257 d_chunks.push_back(chunk);
258 return d_chunks.size();
262 shared_ptr<http::url> data_url,
263 const string &byte_order,
264 unsigned long long size,
265 unsigned long long offset,
266 unsigned int filter_mask,
267 const vector<unsigned long long> &position_in_array)
269 std::shared_ptr<Chunk> chunk(
new Chunk(std::move(data_url), byte_order, size, offset, filter_mask,position_in_array));
271 d_chunks.push_back(chunk);
272 return d_chunks.size();
276 shared_ptr<http::url> data_url,
277 const string &byte_order,
278 unsigned long long size,
279 unsigned long long offset,
281 unsigned int linked_block_index)
283 std::shared_ptr<Chunk> chunk(
new Chunk(std::move(data_url), byte_order, size, offset, linked_block,linked_block_index));
285 d_chunks.push_back(chunk);
286 return d_chunks.size();
290 const string &byte_order,
291 unsigned long long size,
292 unsigned long long offset,
294 unsigned int linked_block_index)
296 std::shared_ptr<Chunk> chunk(
new Chunk(byte_order, size, offset, linked_block,linked_block_index));
298 d_chunks.push_back(chunk);
299 return d_chunks.size();
304 std::shared_ptr<http::url> d_data_url,
305 const std::string &byte_order,
306 unsigned long long size,
307 unsigned long long offset,
308 const std::vector<unsigned long long> &position_in_array,
309 bool multi_linked_blocks,
310 unsigned int lb_index)
313 shared_ptr<Chunk> chunk(
new Chunk(std::move(d_data_url), byte_order, size, offset, position_in_array,multi_linked_blocks,lb_index));
314 d_chunks.push_back(chunk);
315 return d_chunks.size();
319 const std::string &byte_order,
320 unsigned long long size,
321 unsigned long long offset,
322 const std::vector<unsigned long long> &position_in_array,
323 bool multi_linked_blocks,
324 unsigned int lb_index)
327 shared_ptr<Chunk> chunk(
new Chunk(byte_order, size, offset, position_in_array,multi_linked_blocks,lb_index));
328 d_chunks.push_back(chunk);
329 return d_chunks.size();
334 std::shared_ptr<http::url> d_data_url,
335 const std::string &byte_order,
336 const std::string &position_in_array,
337 const std::vector<std::pair<unsigned long long, unsigned long long>> &lb_offset_length)
339 shared_ptr<Chunk> chunk(
new Chunk(std::move(d_data_url), byte_order, position_in_array,lb_offset_length));
340 d_chunks.push_back(chunk);
341 return d_chunks.size();
346 const std::string &byte_order,
347 const std::string &position_in_array,
348 const std::vector<std::pair<unsigned long long, unsigned long long>> &lb_offset_length)
351 shared_ptr<Chunk> chunk(
new Chunk(byte_order, position_in_array,lb_offset_length));
352 d_chunks.push_back(chunk);
353 return d_chunks.size();
372 const string &byte_order,
373 unsigned long long size,
374 unsigned long long offset,
375 const string &position_in_array)
377 vector<unsigned long long> cpia_vector;
378 Chunk::parse_chunk_position_in_array_string(position_in_array, cpia_vector);
379 return add_chunk(byte_order, size, offset, cpia_vector);
397 const string &byte_order,
398 unsigned long long size,
399 unsigned long long offset,
400 const vector<unsigned long long> &position_in_array)
402 shared_ptr<Chunk> chunk(
new Chunk( byte_order, size, offset, position_in_array));
403 d_chunks.push_back(chunk);
404 return d_chunks.size();
409 const string &byte_order,
410 unsigned long long size,
411 unsigned long long offset,
412 unsigned int filter_mask,
413 const vector<unsigned long long> &position_in_array)
415 shared_ptr<Chunk> chunk(
new Chunk( byte_order, size, offset, filter_mask, position_in_array));
416 d_chunks.push_back(chunk);
417 return d_chunks.size();
421 const string &byte_order,
422 const string &fill_value,
423 libdap::Type fv_type,
424 unsigned long long chunk_size,
425 const vector<unsigned long long> &position_in_array)
427 shared_ptr<Chunk> chunk(
new Chunk(byte_order, fill_value, fv_type, chunk_size, position_in_array));
429 d_chunks.push_back(chunk);
430 return d_chunks.size();
434 const string &byte_order,
436 libdap::Type fv_type,
437 unsigned long long chunk_size,
438 const vector<unsigned long long> &position_in_array,
439 const vector<pair<Type,int>> &structure_type_element)
441 shared_ptr<Chunk> chunk(
new Chunk(byte_order, fill_value, fv_type, chunk_size, position_in_array,structure_type_element));
442 d_chunks.push_back(chunk);
443 return d_chunks.size();
447 const string &byte_order,
449 libdap::Type fv_type,
450 unsigned long long chunk_size,
451 const vector<unsigned long long> &position_in_array,
454 shared_ptr<Chunk> chunk(
new Chunk(byte_order, fill_value, fv_type, chunk_size, position_in_array,s_size));
455 d_chunks.push_back(chunk);
456 return d_chunks.size();
479 throw BESInternalError(
string(
"Expected only a single chunk for variable ") + name, __FILE__, __LINE__);
485 return chunk->get_rbuf();
492 throw BESInternalError(
string(
"Expected only a single chunk for variable ") + name, __FILE__, __LINE__);
497 buf_size = chunk->get_rbuf_size();
498 return chunk->get_rbuf();
517 if (xmlTextWriterStartElementNS(xml.get_writer(), (
const xmlChar*)name_space.c_str(), (
const xmlChar*)
"chunks", NULL) < 0)
518 throw BESInternalError(
"Could not start chunks element.", __FILE__, __LINE__);
520 if (!d_filters.empty()) {
521 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"compressionType", (
const xmlChar*) d_filters.c_str()) < 0)
522 throw BESInternalError(
"Could not write compression attribute.", __FILE__, __LINE__);
523 if (!deflate_levels.empty()) {
526 for (
unsigned int i = 0; i <deflate_levels.size(); i++) {
527 if ( i != deflate_levels.size()-1)
528 dls<<deflate_levels[i]<<
" ";
530 dls<<deflate_levels[i];
533 BESDEBUG(dmrpp_3,
"Variable deflate levels: " << dls.str()<<endl);
534 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"deflateLevel", (
const xmlChar*) dls.str().c_str()) < 0)
535 throw BESInternalError(
"Could not write compression attribute.", __FILE__, __LINE__);
541 if (d_uses_fill_value && !d_fill_value_str.empty()) {
542 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"fillValue", (
const xmlChar*) d_fill_value_str.c_str()) < 0)
543 throw BESInternalError(
"Could not write fillValue attribute.", __FILE__, __LINE__);
546 if(!d_chunks.empty()) {
548 if (!first_chunk->get_byte_order().empty()) {
549 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"byteOrder",
550 (
const xmlChar *) first_chunk->get_byte_order().c_str()) < 0)
551 throw BESInternalError(
"Could not write attribute byteOrder", __FILE__, __LINE__);
555 if (!d_chunks.empty() && !struct_offsets.empty()) {
558 for (
unsigned int i = 0; i <struct_offsets.size(); i++) {
559 if ( i != struct_offsets.size()-1)
560 sos = sos + to_string(struct_offsets[i]) +
" ";
562 sos = sos +to_string(struct_offsets[i]);
564 BESDEBUG(dmrpp_3,
"Structure offset: " << sos<<endl);
565 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"structOffset", (
const xmlChar*) sos.c_str()) < 0)
566 throw BESInternalError(
"Could not write structOffset.", __FILE__, __LINE__);
570 if (!d_chunks.empty() && multi_linked_blocks_chunk ==
true) {
571 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"LBChunk",
572 (
const xmlChar *)
"true") < 0)
573 throw BESInternalError(
"Could not write attribute LBChunk", __FILE__, __LINE__);
577 if (!d_filters.empty() && d_disable_dio ==
true) {
578 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"DIO",
579 (
const xmlChar *)
"off") < 0)
580 throw BESInternalError(
"Could not write attribute DIO", __FILE__, __LINE__);
583 if (!d_chunk_dimension_sizes.empty()) {
588 copy(d_chunk_dimension_sizes.begin(), d_chunk_dimension_sizes.end(), ostream_iterator<unsigned long long>(oss,
" "));
589 string sizes = oss.str();
590 sizes.erase(sizes.size() - 1, 1);
592 if (xmlTextWriterWriteElementNS(xml.get_writer(), (
const xmlChar*) name_space.c_str(), (
const xmlChar*)
"chunkDimensionSizes", NULL,
593 (
const xmlChar*) sizes.c_str()) < 0)
throw BESInternalError(
"Could not write chunkDimensionSizes attribute.", __FILE__, __LINE__);
599 if (chunk->get_linked_block()) {
601 if (xmlTextWriterStartElementNS(xml.get_writer(), (
const xmlChar *) name_space.c_str(),
602 (
const xmlChar *)
"block",
nullptr) < 0)
603 throw BESInternalError(
"Could not start element chunk", __FILE__, __LINE__);
606 ostringstream offset;
607 offset << chunk->get_offset();
608 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"offset",
609 (
const xmlChar *) offset.str().c_str()) < 0)
610 throw BESInternalError(
"Could not write attribute offset", __FILE__, __LINE__);
613 ostringstream nBytes;
614 nBytes << chunk->get_size();
615 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"nBytes",
616 (
const xmlChar *) nBytes.str().c_str()) < 0)
617 throw BESInternalError(
"Could not write attribute nBytes", __FILE__, __LINE__);
622 if (xmlTextWriterStartElementNS(xml.get_writer(), (
const xmlChar *) name_space.c_str(),
623 (
const xmlChar *)
"chunk",
nullptr) < 0)
624 throw BESInternalError(
"Could not start element chunk", __FILE__, __LINE__);
627 ostringstream offset;
628 offset << chunk->get_offset();
629 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"offset",
630 (
const xmlChar *) offset.str().c_str()) < 0)
631 throw BESInternalError(
"Could not write attribute offset", __FILE__, __LINE__);
634 ostringstream nBytes;
635 nBytes << chunk->get_size();
636 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"nBytes",
637 (
const xmlChar *) nBytes.str().c_str()) < 0)
638 throw BESInternalError(
"Could not write attribute nBytes", __FILE__, __LINE__);
641 if (chunk->get_position_in_array().size() > 0) {
643 vector<unsigned long long> pia = chunk->get_position_in_array();
649 copy(pia.begin(), pia.end(), ostream_iterator<unsigned long long>(oss,
","));
650 string pia_str = oss.str();
651 if (pia.size() > 0) pia_str.replace(pia_str.size() - 1, 1,
"]");
652 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"chunkPositionInArray",
653 (
const xmlChar *) pia_str.c_str()) < 0)
654 throw BESInternalError(
"Could not write attribute position in array", __FILE__, __LINE__);
657 if (chunk->get_filter_mask() != 0) {
659 fm << chunk->get_filter_mask();
660 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"fm",
661 (
const xmlChar *) fm.str().c_str()) < 0)
662 throw BESInternalError(
"Could not write attribute fm(filter mask)", __FILE__, __LINE__);
666 if (chunk->get_multi_linked_blocks()) {
667 ostringstream mlb_index;
668 mlb_index << chunk->get_multi_linked_block_index_in_dmrpp_file();
669 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *)
"LinkedBlockIndex",
670 (
const xmlChar *) mlb_index.str().c_str()) < 0)
671 throw BESInternalError(
"Could not write attribute fm(filter mask)", __FILE__, __LINE__);
679 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw BESInternalError(
"Could not end chunk element", __FILE__, __LINE__);
682 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw BESInternalError(
"Could not end chunks element", __FILE__, __LINE__);
692 if (xmlTextWriterWriteElementNS(xml.get_writer(), (
const xmlChar *) name_space.c_str(),
693 (
const xmlChar *)
"compact", NULL,
694 (
const xmlChar *) encoded.c_str()) < 0)
695 throw BESInternalError(
"Could not write compact element.", __FILE__, __LINE__);
699DmrppCommon::print_missing_data_element(
const XMLWriter &xml,
const string &name_space,
const std::string &encoded)
const
702 if (xmlTextWriterWriteElementNS(xml.get_writer(), (
const xmlChar *) name_space.c_str(),
703 (
const xmlChar *)
"missingdata",
nullptr,
704 (
const xmlChar *) encoded.c_str()) < 0)
705 throw BESInternalError(
"Could not write missingdata element.", __FILE__, __LINE__);
709DmrppCommon::print_special_structure_element(
const XMLWriter &xml,
const string &name_space,
const std::string &encoded)
const
712 if (xmlTextWriterWriteElementNS(xml.get_writer(), (
const xmlChar *) name_space.c_str(),
713 (
const xmlChar *)
"specialstructuredata",
nullptr,
714 (
const xmlChar *) encoded.c_str()) < 0)
715 throw BESInternalError(
"Could not write special structure element.", __FILE__, __LINE__);
727DmrppCommon::print_missing_data_element(
const XMLWriter &xml,
const string &name_space,
const char *data,
int length)
const
730 if (xmlTextWriterStartElementNS(xml.get_writer(), (
const xmlChar *) name_space.c_str(),
731 (
const xmlChar *)
"missingdata",
nullptr) < 0)
732 throw BESInternalError(
"Could not start missingdata element.", __FILE__, __LINE__);
734 if (xmlTextWriterWriteBase64(xml.get_writer(), data, 0, length) < 0)
735 throw BESInternalError(
"Could not write the base 64 data for the missingdata element.", __FILE__, __LINE__);
737 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
738 throw BESInternalError(
"Could not end missingdata element.", __FILE__, __LINE__);
754 BaseType &bt =
dynamic_cast<BaseType&
>(*this);
755 if (constrained && !bt.send_p())
758 if (xmlTextWriterStartElement(xml.get_writer(), (
const xmlChar*)bt.type_name().c_str()) < 0)
759 throw InternalErr(__FILE__, __LINE__,
"Could not write " + bt.type_name() +
" element");
761 if (!bt.name().empty()) {
762 BESDEBUG(dmrpp_3,
"Variable full path: " << bt.FQN() <<endl);
763 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar*)
"name", (
const xmlChar*)bt.name().c_str()) < 0)
764 throw InternalErr(__FILE__, __LINE__,
"Could not write attribute for name");
768 bt.attributes()->print_dap4(xml);
770 if (!bt.is_dap4() && bt.get_attr_table().get_size() > 0)
771 bt.get_attr_table().print_xml_writer(xml);
781 if (bt.type() == dods_byte_c) {
782 auto sca_var =
dynamic_cast<libdap::Byte*
>(
this);
783 uint8_t sca_var_value = sca_var->value();
784 string encoded = base64::Base64::encode(&sca_var_value, 1);
788 string err_msg =
"Bad type for scalar missing variable: " + bt.name();
811 case dods_float64_c: {
812 u_int8_t *values = 0;
814 size_t size = bt.buf2val(
reinterpret_cast<void **
>(&values));
815 string encoded = base64::Base64::encode(values, size);
828 auto str =
dynamic_cast<libdap::Str*
>(
this);
829 string str_val = str->value();
830 string encoded = base64::Base64::encode(
reinterpret_cast<const u_int8_t *
>(str_val.c_str()), str_val.size());
837 throw InternalErr(__FILE__, __LINE__,
"Vector::val2buf: bad type");
842 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
843 throw InternalErr(__FILE__, __LINE__,
"Could not end " + bt.type_name() +
" element");
846void DmrppCommon::dump(ostream & strm)
const
848 strm << BESIndent::LMarg <<
"is_filters_empty: " << (is_filters_empty() ?
"true" :
"false") << endl;
849 strm << BESIndent::LMarg <<
"filters: " << (d_filters.c_str()) << endl;
853 strm << BESIndent::LMarg <<
"chunk dimension sizes: [";
854 for (
unsigned int i = 0; i < chunk_dim_sizes.size(); i++) {
855 strm << (i ?
"][" :
"") << chunk_dim_sizes[i];
860 strm << BESIndent::LMarg <<
"Chunks (aka chunks):" << (chunk_refs.size() ?
"" :
"None Found.") << endl;
862 for (
auto & chunk_ref : chunk_refs) {
863 strm << BESIndent::LMarg;
864 chunk_ref->dump(strm);
875 d_dmz->load_chunks(btp);
885 d_dmz->load_attributes(btp);
exception thrown if internal error encountered
static void removeLeadingAndTrailingBlanks(std::string &key)
static std::string d_ns_prefix
The XML namespace prefix to use.
static bool d_print_chunks
if true, print_dap4() prints chunk elements
virtual bool is_compact_layout() const
Returns true if this object utilizes COMPACT layout.
virtual void ingest_compression_type(const std::string &compression_type_string)
Parses the text content of the XML element h4:chunkDimensionSizes into the internal vector<unsigned i...
virtual void load_attributes(libdap::BaseType *btp)
Load the attribute information for this variable.
virtual bool is_missing_data() const
Returns true if this object describes the missing data.
virtual size_t get_chunks_size() const
Use this when the number of chunks is needed.
static std::string d_dmrpp_ns
The DMR++ XML namespace.
void print_chunks_element(libdap::XMLWriter &xml, const std::string &name_space="")
Print the Chunk information.
virtual void parse_chunk_dimension_sizes(const std::string &chunk_dim_sizes_string)
Set the dimension sizes for a chunk.
virtual const std::vector< std::shared_ptr< Chunk > > & get_immutable_chunks() const
A const reference to the vector of chunks.
virtual unsigned long add_chunk(std::shared_ptr< http::url > d_data_url, const std::string &byte_order, unsigned long long size, unsigned long long offset, const std::string &position_in_array)
Adds a chunk to the vector of chunk refs (byteStreams) and returns the size of the chunks internal ve...
void set_filter(const std::string &value)
Set the value of the filters property.
virtual void ingest_byte_order(const std::string &byte_order_string)
Parses the text content of the XML element chunks:byteOrder.
virtual bool get_uses_fill_value() const
virtual const std::vector< unsigned long long > & get_chunk_dimension_sizes() const
The chunk dimension sizes held in a const vector.
void print_dmrpp(libdap::XMLWriter &writer, bool constrained=false)
Print the DMR++ response for the Scalar types.
virtual void load_chunks(libdap::BaseType *btp)
Load chunk information for this variable.
void print_compact_element(libdap::XMLWriter &xml, const std::string &name_space="", const std::string &encoded="") const
Print the Compact base64-encoded information.
virtual char * read_atomic(const std::string &name)
read method for the atomic types