bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
DmrppCommon.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of the BES
4
5// Copyright (c) 2016 OPeNDAP, Inc.
6// Author: James Gallagher <jgallagher@opendap.org>
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Lesser General Public
10// License as published by the Free Software Foundation; either
11// version 2.1 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Lesser General Public License for more details.
17//
18// You should have received a copy of the GNU Lesser General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21//
22// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
23
24#include "config.h"
25
26#include <string>
27#include <sstream>
28#include <vector>
29#include <iterator>
30#include <cstdlib>
31#include <cstring>
32
33#include <curl/curl.h>
34
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>
41
42
43#define PUGIXML_NO_XPATH
44#define PUGIXML_HEADER_ONLY
45#include <pugixml.hpp>
46
47#include "url_impl.h"
48#include "BESIndent.h"
49#include "BESDebug.h"
50#include "BESUtil.h"
51#include "BESInternalError.h"
52
53#include "DmrppRequestHandler.h"
54#include "DmrppCommon.h"
55#include "Chunk.h"
56#include "byteswap_compat.h"
57#include "Base64.h"
58
59using namespace std;
60using namespace libdap;
61
62#define prolog std::string("DmrppCommon::").append(__func__).append("() - ")
63
64namespace dmrpp {
65
66// Used with BESDEBUG
67static const string dmrpp_3 = "dmrpp:3";
68static const string dmrpp_4 = "dmrpp:4";
69
71string DmrppCommon::d_dmrpp_ns = "http://xml.opendap.org/dap/dmrpp/1.0.0#";
72string DmrppCommon::d_ns_prefix = "dmrpp";
73
85void join_threads(pthread_t threads[], unsigned int num_threads)
86{
87 int status;
88 for (unsigned int i = 0; i < num_threads; ++i) {
89 if (threads[i]) {
90 BESDEBUG(dmrpp_3, "Join thread " << i << " after an exception was caught." << endl);
91 string *error = NULL;
92 if ((status = pthread_join(threads[i], (void **) &error)) < 0) {
93 BESDEBUG(dmrpp_3, "Could not join thread " << i << ", " << strerror(status)<< endl);
94 }
95 else if (error != NULL) {
96 BESDEBUG(dmrpp_3, "Joined thread " << i << ", error exit: " << *error << endl);
97 }
98 else {
99 BESDEBUG(dmrpp_3, "Joined thread " << i << ", successful exit." << endl);
100 }
101 }
102 }
103}
104
106void DmrppCommon::set_filter(const string &value) {
107 if (DmrppRequestHandler::d_emulate_original_filter_order_behavior) {
108 d_filters = "";
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");
115
117 }
118 else {
119 d_filters = value;
120 }
121}
122
132void DmrppCommon::parse_chunk_dimension_sizes(const string &chunk_dims_string)
133{
134 d_chunk_dimension_sizes.clear();
135
136 if (chunk_dims_string.empty()) return;
137
138 string chunk_dims = chunk_dims_string;
139 // If the input is anything other than integers and spaces, throw
140 if (chunk_dims.find_first_not_of("1234567890 ") != string::npos)
141 throw BESInternalError("while processing chunk dimension information, illegal character(s)", __FILE__, __LINE__);
142
143 // TODO Rewrite this to use split. jhrg 5/2/22
144 string space(" ");
145 size_t strPos = 0;
146 string strVal;
147
148 // Are there spaces or multiple values?
149 if (chunk_dims.find(space) != string::npos) {
150 // Process space delimited content
151 while ((strPos = chunk_dims.find(space)) != string::npos) {
152 strVal = chunk_dims.substr(0, strPos);
153 // TODO stoull (CDS uses uint64_t) jhrg 5/2/22
154 d_chunk_dimension_sizes.push_back(strtol(strVal.c_str(), nullptr, 10));
155 chunk_dims.erase(0, strPos + space.size());
156 }
157 }
158
159 // If it's multivalued there's still one more value left to process
160 // If it's single valued the same is true, so let's ingest that.
161 d_chunk_dimension_sizes.push_back(strtol(chunk_dims.c_str(), nullptr, 10));
162}
163
170void DmrppCommon::ingest_compression_type(const string &compression_type_string)
171{
172 if (compression_type_string.empty()) return;
173 set_filter(compression_type_string);
174}
175
181void DmrppCommon::ingest_byte_order(const string &byte_order_string) {
182
183 if (byte_order_string.empty()) return;
184
185 // Process content
186 if (byte_order_string.compare("LE") == 0) {
187 d_byte_order = "LE";
188 d_twiddle_bytes = is_host_big_endian();
189 } else {
190 if (byte_order_string.compare("BE") == 0) {
191 d_byte_order = "BE";
192 d_twiddle_bytes = !(is_host_big_endian());
193 } else {
194 throw BESInternalError("Did not recognize byteOrder.", __FILE__, __LINE__);
195 }
196 }
197}
198
199
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)
218{
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);
222}
223
224unsigned long DmrppCommon::add_chunk(
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)
231{
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);
235}
236
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)
254{
255 std::shared_ptr<Chunk> chunk(new Chunk(std::move(data_url), byte_order, size, offset, position_in_array));
256
257 d_chunks.push_back(chunk);
258 return d_chunks.size();
259}
260
261unsigned long DmrppCommon::add_chunk(
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)
268{
269 std::shared_ptr<Chunk> chunk(new Chunk(std::move(data_url), byte_order, size, offset, filter_mask,position_in_array));
270
271 d_chunks.push_back(chunk);
272 return d_chunks.size();
273}
274
275unsigned long DmrppCommon::add_chunk(
276 shared_ptr<http::url> data_url,
277 const string &byte_order,
278 unsigned long long size,
279 unsigned long long offset,
280 bool linked_block,
281 unsigned int linked_block_index)
282{
283 std::shared_ptr<Chunk> chunk(new Chunk(std::move(data_url), byte_order, size, offset, linked_block,linked_block_index));
284
285 d_chunks.push_back(chunk);
286 return d_chunks.size();
287}
288
289unsigned long DmrppCommon::add_chunk(
290 const string &byte_order,
291 unsigned long long size,
292 unsigned long long offset,
293 bool linked_block,
294 unsigned int linked_block_index)
295{
296 std::shared_ptr<Chunk> chunk(new Chunk(byte_order, size, offset, linked_block,linked_block_index));
297
298 d_chunks.push_back(chunk);
299 return d_chunks.size();
300}
301
302// For build_dmrpp to handle multi-linked blocks.
303unsigned long DmrppCommon::add_chunk(
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)
311
312{
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();
316}
317
318unsigned long DmrppCommon::add_chunk(
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)
325
326{
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();
330}
331
332// For retrieving data from the dmrpp module
333unsigned long DmrppCommon::add_chunk(
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)
338{
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();
342}
343
344
345unsigned long DmrppCommon::add_chunk(
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)
349
350{
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();
354}
355
372 const string &byte_order,
373 unsigned long long size,
374 unsigned long long offset,
375 const string &position_in_array)
376{
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);
380}
381
397 const string &byte_order,
398 unsigned long long size,
399 unsigned long long offset,
400 const vector<unsigned long long> &position_in_array)
401{
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();
405}
406
407
408unsigned long DmrppCommon::add_chunk(
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)
414{
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();
418}
419
420unsigned long DmrppCommon::add_chunk(
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)
426{
427 shared_ptr<Chunk> chunk(new Chunk(byte_order, fill_value, fv_type, chunk_size, position_in_array));
428
429 d_chunks.push_back(chunk);
430 return d_chunks.size();
431}
432
433unsigned long DmrppCommon::add_chunk(
434 const string &byte_order,
435 const string &fill_value,
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)
440{
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();
444}
445
446unsigned long DmrppCommon::add_chunk(
447 const string &byte_order,
448 const string &fill_value,
449 libdap::Type fv_type,
450 unsigned long long chunk_size,
451 const vector<unsigned long long> &position_in_array,
452 unsigned int s_size)
453{
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();
457}
475char *
476DmrppCommon::read_atomic(const string &name)
477{
478 if (get_chunks_size() != 1)
479 throw BESInternalError(string("Expected only a single chunk for variable ") + name, __FILE__, __LINE__);
480
481 auto chunk = get_immutable_chunks()[0];
482
483 chunk->read_chunk();
484
485 return chunk->get_rbuf();
486}
487
488// Need to obtain the buffer size for scalar structure.
489char * DmrppCommon::read_atomic(const string &name, size_t & buf_size)
490{
491 if (get_chunks_size() != 1)
492 throw BESInternalError(string("Expected only a single chunk for variable ") + name, __FILE__, __LINE__);
493
494 auto chunk = get_immutable_chunks()[0];
495
496 chunk->read_chunk();
497 buf_size = chunk->get_rbuf_size();
498 return chunk->get_rbuf();
499}
513void
514DmrppCommon::print_chunks_element(XMLWriter &xml, const string &name_space)
515{
516 // Start element "chunks" with dmrpp namespace and attributes:
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__);
519
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()) {
524
525 ostringstream dls;
526 for (unsigned int i = 0; i <deflate_levels.size(); i++) {
527 if ( i != deflate_levels.size()-1)
528 dls<<deflate_levels[i]<<" ";
529 else
530 dls<<deflate_levels[i];
531
532 }
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__);
536
537 }
538
539 }
540
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__);
544 }
545
546 if(!d_chunks.empty()) {
547 auto first_chunk = get_immutable_chunks().front();
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__);
552 }
553 }
554
555 if (!d_chunks.empty() && !struct_offsets.empty()) {
556
557 string sos;
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]) + " ";
561 else
562 sos = sos +to_string(struct_offsets[i]);
563 }
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__);
567
568 }
569
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__);
574 }
575
576 // If the disable_dio flag is true, we will set the DIO=off attribute.
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__);
581 }
582
583 if (!d_chunk_dimension_sizes.empty()) { //d_chunk_dimension_sizes.size() > 0) {
584 // Write element "chunkDimensionSizes" with dmrpp namespace:
585 ostringstream oss;
586 // Note: the ostream_iterator previously used unsigned int, which may siliently generate the wrong value when
587 // the size is >4G. Fix it by using unsigned long long. KY 2023-02-09
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); // trim the trailing space
591
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__);
594 }
595
596 // Start elements "chunk" with dmrpp namespace and attributes:
597 for(auto chunk: get_immutable_chunks()) {
598
599 if (chunk->get_linked_block()) {
600
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__);
604
605 // Get offset string:
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__);
611
612 // Get nBytes string:
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__);
618 }
619
620 else {
621
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__);
625
626 // Get offset string:
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__);
632
633 // Get nBytes string:
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__);
639
640
641 if (chunk->get_position_in_array().size() > 0) {
642 // Get position in array string:
643 vector<unsigned long long> pia = chunk->get_position_in_array();
644 ostringstream oss;
645 oss << "[";
646
647 // Note: the ostream_iterator previously used unsigned int, which may siliently generate the wrong value when
648 // the size is >4G. Fix it by using unsigned long long. KY 2023-02-09
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, "]"); // replace the trailing ',' with ']'
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__);
655
656 // Filter mask only applies to the chunking storage. So check here. Get the filter mask string if the filter mask is not zero.
657 if (chunk->get_filter_mask() != 0) {
658 ostringstream fm;
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__);
663 }
664
665 // Here we also need to check if this chunk contains multi-linked blocks. If yes, add the linked block index here.
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__);
672 }
673
674
675 }
676 }
677
678 // End element "chunk":
679 if (xmlTextWriterEndElement(xml.get_writer()) < 0) throw BESInternalError("Could not end chunk element", __FILE__, __LINE__);
680 }
681
682 if (xmlTextWriterEndElement(xml.get_writer()) < 0) throw BESInternalError("Could not end chunks element", __FILE__, __LINE__);
683}
684
689void
690DmrppCommon::print_compact_element(XMLWriter &xml, const string &name_space, const std::string &encoded) const
691{
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__);
696}
697
698void
699DmrppCommon::print_missing_data_element(const XMLWriter &xml, const string &name_space, const std::string &encoded) const
700{
701
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__);
706}
707
708void
709DmrppCommon::print_special_structure_element(const XMLWriter &xml, const string &name_space, const std::string &encoded) const
710{
711
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__);
716
717}
718
726void
727DmrppCommon::print_missing_data_element(const XMLWriter &xml, const string &name_space, const char *data, int length) const
728{
729
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__);
733
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__);
736
737 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
738 throw BESInternalError("Could not end missingdata element.", __FILE__, __LINE__);
739}
740
741
752void DmrppCommon::print_dmrpp(XMLWriter &xml, bool constrained /*false*/)
753{
754 BaseType &bt = dynamic_cast<BaseType&>(*this);
755 if (constrained && !bt.send_p())
756 return;
757
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");
760
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");
765 }
766
767 if (bt.is_dap4())
768 bt.attributes()->print_dap4(xml);
769
770 if (!bt.is_dap4() && bt.get_attr_table().get_size() > 0)
771 bt.get_attr_table().print_xml_writer(xml);
772
773 // This is the code added to libdap::BaseType::print_dap4(). jhrg 5/10/18
774 // If the scalar variable with contiguous contains a fillvalue, also needs to output. ky 07/12/22
777
778 // print scalar value for special missing variables.
779 if (DmrppCommon::d_print_chunks && is_missing_data() && bt.read_p()) {
780 // Now we only handle dods_byte_c.
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);
785 print_missing_data_element(xml, DmrppCommon::d_ns_prefix, encoded);
786 }
787 else {
788 string err_msg = "Bad type for scalar missing variable: " + bt.name();
789 throw BESInternalError(err_msg, __FILE__, __LINE__);
790 }
791 }
792
793 // print scalar value for compact storage.
794 if (DmrppCommon::d_print_chunks && is_compact_layout() && bt.read_p()) {
795
796 switch (bt.type()) {
797 case dods_byte_c:
798 case dods_char_c:
799 case dods_int8_c:
800 case dods_uint8_c:
801 case dods_int16_c:
802 case dods_uint16_c:
803 case dods_int32_c:
804 case dods_uint32_c:
805 case dods_int64_c:
806 case dods_uint64_c:
807
808 case dods_enum_c:
809
810 case dods_float32_c:
811 case dods_float64_c: {
812 u_int8_t *values = 0;
813 try {
814 size_t size = bt.buf2val(reinterpret_cast<void **>(&values));
815 string encoded = base64::Base64::encode(values, size);
817 delete[] values;
818 }
819 catch (...) {
820 delete[] values;
821 throw;
822 }
823 break;
824 }
825
826 case dods_str_c: {
827
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());
832
833 break;
834 }
835
836 default:
837 throw InternalErr(__FILE__, __LINE__, "Vector::val2buf: bad type");
838 }
839
840
841 }
842 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
843 throw InternalErr(__FILE__, __LINE__, "Could not end " + bt.type_name() + " element");
844}
845
846void DmrppCommon::dump(ostream & strm) const
847{
848 strm << BESIndent::LMarg << "is_filters_empty: " << (is_filters_empty() ? "true" : "false") << endl;
849 strm << BESIndent::LMarg << "filters: " << (d_filters.c_str()) << endl;
850
851 const vector<unsigned long long> &chunk_dim_sizes = get_chunk_dimension_sizes();
852
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];
856 }
857 strm << "]" << endl;
858
859 auto chunk_refs = get_immutable_chunks();
860 strm << BESIndent::LMarg << "Chunks (aka chunks):" << (chunk_refs.size() ? "" : "None Found.") << endl;
861 BESIndent::Indent();
862 for (auto & chunk_ref : chunk_refs) {
863 strm << BESIndent::LMarg;
864 chunk_ref->dump(strm);
865 strm << endl;
866 }
867}
868
873void
875 d_dmz->load_chunks(btp);
876}
877
882void
883DmrppCommon::load_attributes(libdap::BaseType *btp)
884{
885 d_dmz->load_attributes(btp);
886}
887
888} // namespace dmrpp
889
exception thrown if internal error encountered
static void removeLeadingAndTrailingBlanks(std::string &key)
Definition BESUtil.cc:448
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