libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
Sequence.cc
Go to the documentation of this file.
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2002,2003 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// (c) COPYRIGHT URI/MIT 1994-1999
26// Please read the full copyright statement in the file COPYRIGHT_URI.
27//
28// Authors:
29// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30
31// Implementation for the class Structure
32//
33// jhrg 9/14/94
34
35#include "config.h"
36
37// #define DODS_DEBUG
38// #define DODS_DEBUG2
39
40#include <algorithm>
41#include <sstream>
42#include <string>
43
44#include "Array.h"
45#include "Byte.h"
46#include "Float32.h"
47#include "Float64.h"
48#include "Grid.h"
49#include "Int16.h"
50#include "Int32.h"
51#include "Sequence.h"
52#include "Str.h"
53#include "Structure.h"
54#include "UInt16.h"
55#include "UInt32.h"
56#include "Url.h"
57
58#include "Marshaller.h"
59#include "UnMarshaller.h"
60
61#include "DDS.h"
62#include "DataDDS.h"
63#include "Error.h"
64#include "InternalErr.h"
65#include "Sequence.h"
66#include "debug.h"
67#include "escaping.h"
68#include "util.h"
69
70#include "Constructor.h"
71#include "D4Attributes.h"
72#include "D4Group.h"
73#include "D4Sequence.h"
74#include "DMR.h"
75#include "DapIndent.h"
76
77#undef CLEAR_LOCAL_DATA
78
79using namespace std;
80
81namespace libdap {
82
83static const unsigned char end_of_sequence = 0xA5; // binary pattern 1010 0101
84static const unsigned char start_of_instance = 0x5A; // binary pattern 0101 1010
85
86// Private member functions
87
89 DBG(cerr << "In Sequence::m_duplicate" << endl);
90
91 d_row_number = s.d_row_number;
92 d_starting_row_number = s.d_starting_row_number;
93 d_ending_row_number = s.d_ending_row_number;
94 d_row_stride = s.d_row_stride;
95 d_leaf_sequence = s.d_leaf_sequence;
96 d_unsent_data = s.d_unsent_data;
97 d_wrote_soi = s.d_wrote_soi;
98 d_top_most = s.d_top_most;
99
100 Sequence &cs = const_cast<Sequence &>(s);
101
102 // Copy the BaseType objects used to hold values.
103 for (vector<BaseTypeRow *>::iterator rows_iter = cs.d_values.begin(); rows_iter != cs.d_values.end(); rows_iter++) {
104 // Get the current BaseType Row
105 BaseTypeRow *src_bt_row_ptr = *rows_iter;
106 // Create a new row.
107 BaseTypeRow *dest_bt_row_ptr = new BaseTypeRow;
108 // Copy the BaseType objects from a row to new BaseType objects.
109 // Push new BaseType objects onto new row.
110 for (BaseTypeRow::iterator bt_row_iter = src_bt_row_ptr->begin(); bt_row_iter != src_bt_row_ptr->end();
111 bt_row_iter++) {
112 BaseType *src_bt_ptr = *bt_row_iter;
113 BaseType *dest_bt_ptr = src_bt_ptr->ptr_duplicate();
114 dest_bt_row_ptr->push_back(dest_bt_ptr);
115 }
116 // Push new row onto d_values.
117 d_values.push_back(dest_bt_row_ptr);
118 }
119}
120
121static void write_end_of_sequence(Marshaller &m) { m.put_opaque((char *)&end_of_sequence, 1); }
122
123static void write_start_of_instance(Marshaller &m) { m.put_opaque((char *)&start_of_instance, 1); }
124
125static unsigned char read_marker(UnMarshaller &um) {
126 unsigned char marker;
127 um.get_opaque((char *)&marker, 1);
128
129 return marker;
130}
131
132static bool is_start_of_instance(unsigned char marker) { return (marker == start_of_instance); }
133
134static bool is_end_of_sequence(unsigned char marker) { return (marker == end_of_sequence); }
135
136// Public member functions
137
146Sequence::Sequence(const string &n)
147 : Constructor(n, dods_sequence_c), d_row_number(-1), d_starting_row_number(-1), d_row_stride(1),
148 d_ending_row_number(-1), d_unsent_data(false), d_wrote_soi(false), d_leaf_sequence(false), d_top_most(false) {}
149
160Sequence::Sequence(const string &n, const string &d)
161 : Constructor(n, d, dods_sequence_c), d_row_number(-1), d_starting_row_number(-1), d_row_stride(1),
162 d_ending_row_number(-1), d_unsent_data(false), d_wrote_soi(false), d_leaf_sequence(false), d_top_most(false) {}
163
166
168
184 D4Sequence *dest;
185 // If it's already a DAP4 object then we can just return it!
186 if (is_dap4()) {
187 dest = static_cast<D4Sequence *>(ptr_duplicate());
188 dest->set_length(-1);
189 container->add_var_nocopy(dest);
190 return;
191 }
192 dest = new D4Sequence(name());
194 dest->set_length(-1);
195 container->add_var_nocopy(dest);
196}
197
198static inline void delete_bt(BaseType *bt_ptr) {
199 delete bt_ptr;
200 bt_ptr = 0;
201}
202
203static inline void delete_rows(BaseTypeRow *bt_row_ptr) {
204 for_each(bt_row_ptr->begin(), bt_row_ptr->end(), delete_bt);
205
206 delete bt_row_ptr;
207 bt_row_ptr = 0;
208}
209
211 try {
212 Sequence::clear_local_data(); // make the call explicit in a destructor
213 } catch (const std::exception &) {
214 // It's hard to know what to do - Log it when we can, but that can fail, too.
215 }
216}
217
219 if (!d_values.empty()) {
220 for_each(d_values.begin(), d_values.end(), delete_rows);
221 d_values.resize(0);
222 }
223
224 set_read_p(false);
225}
226
228 if (this == &rhs)
229 return *this;
231 m_duplicate(rhs);
232 return *this;
233}
234
238bool Sequence::is_dap2_only_type() { return true; }
239
241 ostringstream oss;
242
243 oss << BaseType::toString();
244
245 for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
246 oss << (*i)->toString();
247 }
248
249 oss << endl;
250
251 return oss.str();
252}
253
255 bool linear = true;
256 bool seq_found = false;
257 for (Vars_iter iter = d_vars.begin(); linear && iter != d_vars.end(); iter++) {
258 if ((*iter)->type() == dods_sequence_c) {
259 // A linear sequence cannot have more than one child seq. at any
260 // one level. If we've already found a seq at this level, return
261 // false.
262 if (seq_found) {
263 linear = false;
264 break;
265 }
266 seq_found = true;
267 linear = static_cast<Sequence *>((*iter))->is_linear();
268 } else if ((*iter)->type() == dods_structure_c) {
269 linear = static_cast<Structure *>((*iter))->is_linear();
270 } else {
271 // A linear sequence cannot have Arrays, Lists or Grids.
272 linear = (*iter)->is_simple_type();
273 }
274 }
275
276 return linear;
277}
278
284 if (row >= d_values.size())
285 return 0; // nullptr
286 return d_values[row];
287}
288
295void Sequence::set_value(SequenceValues &values) { d_values = values; }
296
299SequenceValues Sequence::value() { return d_values; }
300
303SequenceValues &Sequence::value_ref() { return d_values; }
304
310BaseType *Sequence::var_value(size_t row, const string &name) {
311 BaseTypeRow *bt_row_ptr = row_value(row);
312 if (!bt_row_ptr)
313 return 0;
314
315 BaseTypeRow::iterator bt_row_iter = bt_row_ptr->begin();
316 BaseTypeRow::iterator bt_row_end = bt_row_ptr->end();
317 while (bt_row_iter != bt_row_end && (*bt_row_iter)->name() != name)
318 ++bt_row_iter;
319
320 if (bt_row_iter == bt_row_end)
321 return 0;
322 else
323 return *bt_row_iter;
324}
325
331BaseType *Sequence::var_value(size_t row, size_t i) {
332 BaseTypeRow *bt_row_ptr = row_value(row);
333 if (!bt_row_ptr)
334 return 0;
335
336 if (i >= bt_row_ptr->size())
337 return 0;
338
339 return (*bt_row_ptr)[i];
340}
341
342// This version returns -1. Each API-specific subclass should define a more
343// reasonable version. jhrg 5/24/96
344
360int Sequence::length() const { return -1; }
361
362// Hmmm. how is this different from length()?
363int Sequence::number_of_rows() const { return d_values.size(); }
364
368void Sequence::reset_row_number() { d_row_number = -1; }
369
377
378 if (recur)
379 for (Vars_iter i = var_begin(), e = var_end(); i != e; ++i)
380 if ((*i)->type() == dods_sequence_c)
381 reset_row_number(true);
382}
383
384// Notes:
385// Assume that read() is implemented so that, when reading data for a nested
386// sequence, only the outer most level is *actually* read.
387// This is a consequence of our current (12/7/99) implementation of
388// the JGOFS server (which is the only server to actually use nested
389// sequences). 12/7/99 jhrg
390//
391// Stop assuming this. This logic is being moved into the JGOFS server
392// itself. 6/1/2001 jhrg
393
394// The read() function returns a boolean value, with TRUE
395// indicating that read() should be called again because there's
396// more data to read, and FALSE indicating there's no more data
397// to read. Note that this behavior is necessary to properly
398// handle variables that contain Sequences. Jose Garcia If an
399// error exists while reading, the implementers of the surrogate
400// library SHOULD throw an Error object which will propagate
401// beyond this point to to the original caller.
402// Jose Garcia
403
436bool Sequence::read_row(int row, DDS &dds, ConstraintEvaluator &eval, bool ce_eval) {
437 DBG2(cerr << "Entering Sequence::read_row for " << name() << ", row number " << row << ", current row "
438 << d_row_number << endl);
439 if (row < d_row_number)
440 throw InternalErr("Trying to back up inside a sequence!");
441
442 if (row == d_row_number) {
443 DBG2(cerr << "Leaving Sequence::read_row for " << name() << endl);
444 return false;
445 }
446
447 bool eof = false; // Start out assuming EOF is false.
448 while (!eof && d_row_number < row) {
449 if (!read_p()) {
450 // jhrg original version from 10/9/13 : eof = (read() == false);
451 eof = read();
452 }
453
454 // Advance the row number if ce_eval is false (we're not supposed to
455 // evaluate the selection) or both ce_eval and the selection are
456 // true.
457 if (!eof && (!ce_eval || eval.eval_selection(dds, dataset())))
458 d_row_number++;
459
460 set_read_p(false); // ...so that the next instance will be read
461 }
462
463 // Once we finish the above loop, set read_p to true so that the caller
464 // knows that data *has* been read. This is how the read() methods of the
465 // elements of the sequence know to not call read() but instead look for
466 // data values inside themselves.
467 set_read_p(true);
468
469 // Return true if we have valid data, false if we've read to the EOF.
470 DBG2(cerr << "Leaving Sequence::read_row for " << name() << " with eof: " << eof << endl);
471 return !eof; // jhrg 10/10/13 was: eof == 0;
472}
473
474// Private. This is used to process constraints on the rows of a sequence.
475// Starting with 3.2 we support constraints like Sequence[10:2:20]. This
476// odd-looking logic first checks if d_ending_row_number is the sentinel
477// value of -1. If so, the sequence was not constrained by row number and
478// this method should never return true (which indicates that we're at the
479// end of a row-number constraint). If d_ending_row_number is not -1, then is
480// \e i at the end point? 6/1/2001 jhrg
481inline bool Sequence::is_end_of_rows(int i) {
482 return ((d_ending_row_number == -1) ? false : (i > d_ending_row_number));
483}
484
545bool Sequence::serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval) {
546 // Special case leaf sequences!
547 bool status = false;
548
549 if (is_leaf_sequence())
550 status = serialize_leaf(dds, eval, m, ce_eval);
551 else
552 status = serialize_parent_part_one(dds, eval, m);
553
554 return status;
555}
556
557// We know this is not a leaf Sequence. That means that this Sequence holds
558// another Sequence as one of its fields _and_ that child Sequence triggers
559// the actual transmission of values.
560
562 DBG2(cerr << "Entering serialize_parent_part_one for " << name() << endl);
563
564 int i = (d_starting_row_number != -1) ? d_starting_row_number : 0;
565
566 // read_row returns true if valid data was read, false if the EOF was
567 // found. 6/1/2001 jhrg
568 // Since this is a parent sequence, read the row ignoring the CE (all of
569 // the CE clauses will be evaluated by the leaf sequence).
570 bool status = read_row(i, dds, eval, false);
571 DBG2(cerr << "Sequence::serialize_parent_part_one::read_row() status: " << status << endl);
572
573 while (status && !is_end_of_rows(i)) {
574 i += d_row_stride;
575
576 // DBG(cerr << "Writing Start of Instance marker" << endl);
577 // write_start_of_instance(sink);
578
579 // In this loop serialize will signal an error with an exception.
580 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
581 // Only call serialize for child Sequences; the leaf sequence
582 // will trigger the transmission of values for its parents (this
583 // sequence and maybe others) once it gets some valid data to
584 // send.
585 // Note that if the leaf sequence has no variables in the current
586 // projection, its serialize() method will never be called and that's
587 // the method that triggers actually sending values. Thus the leaf
588 // sequence must be the lowest level sequence with values whose send_p
589 // property is true.
590 if ((*iter)->send_p() && (*iter)->type() == dods_sequence_c)
591 (*iter)->serialize(eval, dds, m);
592 }
593
594 set_read_p(false); // ...so this will read the next instance
595
596 status = read_row(i, dds, eval, false);
597 DBG(cerr << "Sequence::serialize_parent_part_one::read_row() status: " << status << endl);
598 }
599 // Reset current row number for next nested sequence element.
600 d_row_number = -1;
601
602 // Always write the EOS marker? 12/23/04 jhrg
603 // Yes. According to DAP2, a completely empty response is signaled by
604 // a return value of only the EOS marker for the outermost sequence.
605 if (d_top_most || d_wrote_soi) {
606 DBG(cerr << "Writing End of Sequence marker" << endl);
607 write_end_of_sequence(m);
608 d_wrote_soi = false;
609 }
610
611 return true; // Signal errors with exceptions.
612}
613
614// If we are here then we know that this is 'parent sequence' and that the
615// leaf sequence has found valid data to send. We also know that
616// serialize_parent_part_one has been called so data are in the instance's
617// fields. This is where we send data. Whereas ..._part_one() contains a
618// loop to iterate over all of rows in a parent sequence, this does not. This
619// method assumes that the serialize_leaf() will call it each time it needs
620// to be called.
621//
622// NB: This code only works if the child sequences appear after all other
623// variables.
625 DBG(cerr << "Entering serialize_parent_part_two for " << name() << endl);
626
627 BaseType *btp = get_parent();
628 if (btp && btp->type() == dods_sequence_c)
629 static_cast<Sequence &>(*btp).serialize_parent_part_two(dds, eval, m);
630
631 if (d_unsent_data) {
632 DBG(cerr << "Writing Start of Instance marker" << endl);
633 d_wrote_soi = true;
634 write_start_of_instance(m);
635
636 // In this loop serialize will signal an error with an exception.
637 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
638 // Send all the non-sequence variables
639 DBG(cerr << "Sequence::serialize_parent_part_two(), serializing " << (*iter)->name() << endl);
640 if ((*iter)->send_p() && (*iter)->type() != dods_sequence_c) {
641 DBG(cerr << "Send P is true, sending " << (*iter)->name() << endl);
642 (*iter)->serialize(eval, dds, m, false);
643 }
644 }
645
646 d_unsent_data = false; // read should set this.
647 }
648}
649
650// This code is only run by a leaf sequence. Note that a one level sequence
651// is also a leaf sequence.
652bool Sequence::serialize_leaf(DDS &dds, ConstraintEvaluator &eval, Marshaller &m, bool ce_eval) {
653 DBG(cerr << "Entering Sequence::serialize_leaf for " << name() << endl);
654 int i = (d_starting_row_number != -1) ? d_starting_row_number : 0;
655
656 // read_row returns true if valid data was read, false if the EOF was
657 // found. 6/1/2001 jhrg
658 bool status = read_row(i, dds, eval, ce_eval);
659 DBG(cerr << "Sequence::serialize_leaf::read_row() status: " << status << endl);
660
661 // Once the first valid (satisfies the CE) row of the leaf sequence has
662 // been read, we know we're going to send data. Send the current instance
663 // of the parent/ancestor sequences now, if there are any. We only need
664 // to do this once, hence it's not inside the while loop, but we only
665 // send the parent seq data _if_ there's data in the leaf to send, that's
666 // why we wait until after the first call to read_row() here in the leaf
667 // sequence.
668 //
669 // NB: It's important to only call serialize_parent_part_two() for a
670 // Sequence that really is the parent of a leaf sequence.
671 if (status && !is_end_of_rows(i)) {
672 BaseType *btp = get_parent();
673 if (btp && btp->type() == dods_sequence_c)
674 static_cast<Sequence &>(*btp).serialize_parent_part_two(dds, eval, m);
675 }
676
677 d_wrote_soi = false;
678 while (status && !is_end_of_rows(i)) {
679 i += d_row_stride;
680
681 DBG(cerr << "Writing Start of Instance marker" << endl);
682 d_wrote_soi = true;
683 write_start_of_instance(m);
684
685 // In this loop serialize will signal an error with an exception.
686 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
687 DBG(cerr << "Sequence::serialize_leaf(), serializing " << (*iter)->name() << endl);
688 if ((*iter)->send_p()) {
689 DBG(cerr << "Send P is true, sending " << (*iter)->name() << endl);
690 (*iter)->serialize(eval, dds, m, false);
691 }
692 }
693
694 set_read_p(false); // ...so this will read the next instance
695
696 status = read_row(i, dds, eval, ce_eval);
697 DBG(cerr << "Sequence::serialize_leaf::read_row() status: " << status << endl);
698 }
699
700 // Only write the EOS marker if there's a matching Start Of Instance
701 // Marker in the stream.
702 if (d_wrote_soi || d_top_most) {
703 DBG(cerr << "Writing End of Sequence marker" << endl);
704 write_end_of_sequence(m);
705 }
706
707 return true; // Signal errors with exceptions.
708}
709
733 DBG(cerr << "Sequence::intern_data - for " << name() << endl);
734 DBG2(cerr << " intern_data, values: " << &d_values << endl);
735 if (is_dap4())
736 throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (")
737 .append(name())
738 .append(")."),
739 __FILE__, __LINE__);
740
741 // Why use a stack instead of return values? We need the stack because
742 // Sequences nested three of more levels deep will lose the middle
743 // instances when the intern_data_parent_part_two() code is run.
744 sequence_values_stack_t sequence_values_stack;
745
746 sequence_values_stack.push(&d_values);
747
748 intern_data_private(eval, dds, sequence_values_stack);
749}
750
752 sequence_values_stack_t &sequence_values_stack) {
753 DBG(cerr << "Entering intern_data_private for " << name() << endl);
754
755 if (is_leaf_sequence())
756 intern_data_for_leaf(dds, eval, sequence_values_stack);
757 else
758 intern_data_parent_part_one(dds, eval, sequence_values_stack);
759}
760
762 sequence_values_stack_t &sequence_values_stack) {
763 DBG(cerr << "Entering intern_data_parent_part_one for " << name() << endl);
764
765 int i = (get_starting_row_number() != -1) ? get_starting_row_number() : 0;
766
767 // read_row returns true if valid data was read, false if the EOF was
768 // found. 6/1/2001 jhrg
769 // Since this is a parent sequence, read the row ignoring the CE (all of
770 // the CE clauses will be evaluated by the leaf sequence).
771 bool status = read_row(i, dds, eval, false);
772
773 // Grab the current size of the value stack. We do this because it is
774 // possible that no nested sequences for this row happened to be
775 // selected because of a constraint evaluation or the last row is not
776 // selected because of a constraint evaluation. In either case, no
777 // nested sequence d_values are pushed onto the stack, so there is
778 // nothing to pop at the end of this function. pcw 07/14/08
779 SequenceValues::size_type orig_stack_size = sequence_values_stack.size();
780
781 while (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
782 i += get_row_stride();
783 for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
784 if ((*iter)->send_p()) {
785 switch ((*iter)->type()) {
786 case dods_sequence_c:
787 static_cast<Sequence &>(**iter).intern_data_private(eval, dds, sequence_values_stack);
788 break;
789
790 default:
791 (*iter)->intern_data(eval, dds);
792 break;
793 }
794 }
795 }
796
797 set_read_p(false); // ...so this will read the next instance
798
799 status = read_row(i, dds, eval, false);
800 }
801
802 // Reset current row number for next nested sequence element.
804
805 // if the size of the stack is larger than the original size (retrieved
806 // above) then pop the top set of d_values from the stack. If it's the
807 // same, then no nested sequences, or possibly the last nested sequence,
808 // were pushed onto the stack, so there is nothing to pop.
809 if (sequence_values_stack.size() > orig_stack_size) {
810 DBG2(cerr << " popping d_values (" << sequence_values_stack.top()
811 << ") off stack; size: " << sequence_values_stack.size() << endl);
812 sequence_values_stack.pop();
813 }
814
815 DBG(cerr << "Leaving intern_data_parent_part_one for " << name() << endl);
816}
817
819 sequence_values_stack_t &sequence_values_stack) {
820 DBG(cerr << "Entering intern_data_parent_part_two for " << name() << endl);
821
822 BaseType *btp = get_parent();
823 if (btp && btp->type() == dods_sequence_c) {
824 static_cast<Sequence &>(*btp).intern_data_parent_part_two(dds, eval, sequence_values_stack);
825 }
826
827 DBG2(cerr << " stack size: " << sequence_values_stack.size() << endl);
828 SequenceValues *values = sequence_values_stack.top();
829 DBG2(cerr << " using values = " << (void *)values << endl);
830
831 if (get_unsent_data()) {
832 BaseTypeRow *row_data = new BaseTypeRow;
833
834 // In this loop transfer_data will signal an error with an exception.
835 for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
836
837 if ((*iter)->send_p() && (*iter)->type() != dods_sequence_c) {
838 row_data->push_back((*iter)->ptr_duplicate());
839 } else if ((*iter)->send_p()) { // Sequence; must be the last variable
840 Sequence *tmp = dynamic_cast<Sequence *>((*iter)->ptr_duplicate());
841 if (!tmp) {
842 delete row_data;
843 throw InternalErr(__FILE__, __LINE__, "Expected a Sequence.");
844 }
845 row_data->push_back(tmp);
846 DBG2(cerr << " pushing d_values of " << tmp->name() << " (" << &(tmp->d_values)
847 << ") on stack; size: " << sequence_values_stack.size() << endl);
848 // This pushes the d_values field of the newly created leaf
849 // Sequence onto the stack. The code then returns to intern
850 // _data_for_leaf() where this value will be used.
851 sequence_values_stack.push(&(tmp->d_values));
852 }
853 }
854
855 DBG2(cerr << " pushing values for " << name() << " to " << values << endl);
856 values->push_back(row_data);
857 set_unsent_data(false);
858 }
859
860 DBG(cerr << "Leaving intern_data_parent_part_two for " << name() << endl);
861}
862
864 sequence_values_stack_t &sequence_values_stack) {
865 DBG(cerr << "Entering intern_data_for_leaf for " << name() << endl);
866
867 int i = (get_starting_row_number() != -1) ? get_starting_row_number() : 0;
868
869 DBG2(cerr << " reading row " << i << endl);
870 bool status = read_row(i, dds, eval, true);
871 DBG2(cerr << " status: " << status << endl);
872 DBG2(cerr << " ending row number: " << get_ending_row_number() << endl);
873
874 if (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
875 BaseType *btp = get_parent();
876 if (btp && btp->type() == dods_sequence_c) {
877 // This call will read the values for the parent sequences and
878 // then allocate a new instance for the leaf and push that onto
879 // the stack.
880 static_cast<Sequence &>(*btp).intern_data_parent_part_two(dds, eval, sequence_values_stack);
881 }
882
883 // intern_data_parent_part_two pushes the d_values field of the leaf
884 // onto the stack, so this operation grabs that value and then loads
885 // data into it.
886 SequenceValues *values = sequence_values_stack.top();
887 DBG2(cerr << " using values = " << values << endl);
888
889 while (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
890 i += get_row_stride();
891
892 // Copy data from the object's fields to this new BaeTypeRow instance
893 BaseTypeRow *row_data = new BaseTypeRow;
894 for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
895 if ((*iter)->send_p()) {
896 row_data->push_back((*iter)->ptr_duplicate());
897 }
898 }
899
900 DBG2(cerr << " pushing values for " << name() << " to " << values << endl);
901 // Save the row_data to values().
902 values->push_back(row_data);
903
904 set_read_p(false); // ...so this will read the next instance
905 // Read the ith row into this object's fields
906 status = read_row(i, dds, eval, true);
907 }
908
909 DBG2(cerr << " popping d_values (" << sequence_values_stack.top()
910 << ") off stack; size: " << sequence_values_stack.size() << endl);
911 sequence_values_stack.pop();
912 }
913
914 DBG(cerr << "Leaving intern_data_for_leaf for " << name() << endl);
915}
916
937bool Sequence::deserialize(UnMarshaller &um, DDS *dds, bool reuse) {
938#if 0
939 // Nathan's tip - this is something that should never happen
940 DataDDS *dd = dynamic_cast<DataDDS *>(dds);
941 if (!dd) throw InternalErr("Expected argument 'dds' to be a DataDDS!");
942
943 DBG2(cerr << "Reading from server/protocol version: "
944 << dd->get_protocol_major() << "." << dd->get_protocol_minor()
945 << endl);
946
947 // Check for old servers.
948 if (dd->get_protocol_major() < 2) {
949 throw Error(
950 string("The protocl version (") + dd->get_protocol()
951 + ") indicates that this\nis an old server which may not correctly transmit Sequence variables.\nContact the server administrator.");
952 }
953#endif
954 while (true) {
955 // Grab the sequence stream's marker.
956 unsigned char marker = read_marker(um);
957 if (is_end_of_sequence(marker))
958 break; // EXIT the while loop here!!!
959 else if (is_start_of_instance(marker)) {
960 d_row_number++;
961 DBG2(cerr << "Reading row " << d_row_number << " of " << name() << endl);
962 BaseTypeRow *bt_row_ptr = new BaseTypeRow;
963 // Read the instance's values, building up the row
964 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
965 BaseType *bt_ptr = (*iter)->ptr_duplicate();
966 bt_ptr->deserialize(um, dds, reuse);
967 DBG2(cerr << "Deserialized " << bt_ptr->name() << " (" << bt_ptr << ") = ");
968 DBG2(bt_ptr->print_val(stderr, ""));
969 bt_row_ptr->push_back(bt_ptr);
970 }
971 // Append this row to those accumulated.
972 d_values.push_back(bt_row_ptr);
973 } else
974 throw Error("I could not read the expected Sequence data stream marker!");
975 };
976
977 return false;
978}
979
980// Return the current row number.
981
993int Sequence::get_starting_row_number() { return d_starting_row_number; }
994
1005int Sequence::get_row_stride() { return d_row_stride; }
1006
1018int Sequence::get_ending_row_number() { return d_ending_row_number; }
1019
1028void Sequence::set_row_number_constraint(int start, int stop, int stride) {
1029 if (stop < start)
1030 throw Error(malformed_expr, "Starting row number must precede the ending row number.");
1031
1032 d_starting_row_number = start;
1033 d_row_stride = stride;
1034 d_ending_row_number = stop;
1035}
1036
1037void Sequence::print_one_row(FILE *out, int row, string space, bool print_row_num) {
1038 ostringstream oss;
1039 print_one_row(oss, row, space, print_row_num);
1040 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1041}
1042
1043void Sequence::print_one_row(ostream &out, int row, string space, bool print_row_num) {
1044 if (print_row_num)
1045 out << "\n" << space << row << ": ";
1046
1047 out << "{ ";
1048
1049 int elements = element_count();
1050 int j = 0;
1051 BaseType *bt_ptr = 0;
1052
1053 // This version of print_one_row() works for both data read with
1054 // deserialize(), where each variable is assumed to have valid data, and
1055 // intern_data(), where some/many variables do not. Because of that, it's
1056 // not correct to assume that all of the elements will be printed, which
1057 // is what the old code did.
1058 // Print the first value
1059 while (j < elements && !bt_ptr) {
1060 bt_ptr = var_value(row, j++);
1061 if (bt_ptr) { // data
1062 if (bt_ptr->type() == dods_sequence_c)
1063 static_cast<Sequence *>(bt_ptr)->print_val_by_rows(out, space + " ", false, print_row_num);
1064 else
1065 bt_ptr->print_val(out, space, false);
1066 }
1067 }
1068
1069 // Print the remaining values
1070 while (j < elements) {
1071 bt_ptr = var_value(row, j++);
1072 if (bt_ptr) { // data
1073 out << ", ";
1074 if (bt_ptr->type() == dods_sequence_c)
1075 static_cast<Sequence *>(bt_ptr)->print_val_by_rows(out, space + " ", false, print_row_num);
1076 else
1077 bt_ptr->print_val(out, space, false);
1078 }
1079 }
1080
1081 out << " }";
1082}
1083
1084void Sequence::print_val_by_rows(FILE *out, string space, bool print_decl_p, bool print_row_numbers) {
1085 ostringstream oss;
1086 print_val_by_rows(oss, space, print_decl_p, print_row_numbers);
1087 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1088}
1089
1090void Sequence::print_val_by_rows(ostream &out, string space, bool print_decl_p, bool print_row_numbers) {
1091 if (print_decl_p) {
1092 print_decl(out, space, false);
1093 out << " = ";
1094 }
1095
1096 out << "{ ";
1097
1098 int rows = number_of_rows() - 1;
1099 int i;
1100 for (i = 0; i < rows; ++i) {
1101 print_one_row(out, i, space, print_row_numbers);
1102 out << ", ";
1103 }
1104 print_one_row(out, i, space, print_row_numbers);
1105
1106 out << " }";
1107
1108 if (print_decl_p)
1109 out << ";\n";
1110}
1111
1112void Sequence::print_val(FILE *out, string space, bool print_decl_p) {
1113 print_val_by_rows(out, space, print_decl_p, false);
1114}
1115
1116void Sequence::print_val(ostream &out, string space, bool print_decl_p) {
1117 print_val_by_rows(out, space, print_decl_p, false);
1118}
1119
1120void Sequence::set_leaf_p(bool state) { d_leaf_sequence = state; }
1121
1122bool Sequence::is_leaf_sequence() { return d_leaf_sequence; }
1123
1149 bool has_child_sequence = false;
1150
1151 if (lvl == 1)
1152 d_top_most = true;
1153
1154 DBG2(cerr << "Processing sequence " << name() << endl);
1155
1156 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
1157 // About the test for send_p(): Only descend into a sequence if it has
1158 // fields that might be sent. Thus if, in a two-level sequence, nothing
1159 // in the lower level is to be sent, the upper level is marked as the
1160 // leaf sequence. This ensures that values _will_ be sent (see the comment
1161 // in serialize_leaf() and serialize_parent_part_one()).
1162 if ((*iter)->type() == dods_sequence_c && (*iter)->send_p()) {
1163 if (has_child_sequence)
1164 throw Error("This implementation does not support more than one nested sequence at a level. Contact "
1165 "the server administrator.");
1166
1167 has_child_sequence = true;
1168 static_cast<Sequence &>(**iter).set_leaf_sequence(++lvl);
1169 } else if ((*iter)->type() == dods_structure_c) {
1170 static_cast<Structure &>(**iter).set_leaf_sequence(lvl);
1171 }
1172 }
1173
1174 if (!has_child_sequence)
1175 set_leaf_p(true);
1176 else
1177 set_leaf_p(false);
1178
1179 DBG2(cerr << "is_leaf_sequence(): " << is_leaf_sequence() << " (" << name() << ")" << endl);
1180}
1181
1190void Sequence::dump(ostream &strm) const {
1191 strm << DapIndent::LMarg << "Sequence::dump - (" << (void *)this << ")" << endl;
1193 Constructor::dump(strm);
1194 strm << DapIndent::LMarg << "# rows deserialized: " << d_row_number << endl;
1195 strm << DapIndent::LMarg << "bracket notation information:" << endl;
1197 strm << DapIndent::LMarg << "starting row #: " << d_starting_row_number << endl;
1198 strm << DapIndent::LMarg << "row stride: " << d_row_stride << endl;
1199 strm << DapIndent::LMarg << "ending row #: " << d_ending_row_number << endl;
1201
1202 strm << DapIndent::LMarg << "data been sent? " << d_unsent_data << endl;
1203 strm << DapIndent::LMarg << "start of instance? " << d_wrote_soi << endl;
1204 strm << DapIndent::LMarg << "is leaf sequence? " << d_leaf_sequence << endl;
1205 strm << DapIndent::LMarg << "top most in hierarchy? " << d_top_most << endl;
1207}
1208
1209} // namespace libdap
#define malformed_expr
(400)
Definition Error.h:66
The basic data type for the DODS DAP types.
Definition BaseType.h:118
virtual void intern_data()
Read data into this variable.
Definition BaseType.cc:805
virtual bool deserialize(UnMarshaller &um, DDS *dds, bool reuse=false)
Receive data from the net.
Definition BaseType.cc:814
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:296
virtual BaseType * get_parent() const
Definition BaseType.cc:636
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:410
virtual string dataset() const
Returns the name of the dataset used to create this instance.
Definition BaseType.cc:326
virtual string toString()
Definition BaseType.cc:170
virtual bool is_dap4() const
Definition BaseType.h:181
virtual BaseType * ptr_duplicate()=0
virtual Type type() const
Returns the type of the class instance.
Definition BaseType.cc:329
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition BaseType.cc:949
Evaluate a constraint expression.
bool eval_selection(DDS &dds, const std::string &dataset)
Evaluate a boolean-valued constraint expression. This is main method for the evaluator and is called ...
int element_count(bool leaves=false) override
Count the members of constructor types.
void transform_to_dap4(D4Group *root, Constructor *dest) override
DAP2 to DAP4 transform.
void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false) override
Print an ASCII representation of the variable structure.
void set_read_p(bool state) override
Set the 'read_p' property for the Constructor and its members.
std::vector< BaseType * >::iterator Vars_iter
Definition Constructor.h:60
std::vector< BaseType * > d_vars
Definition Constructor.h:47
bool read() override
Read the elements of Constructor marked for transmission.
void add_var_nocopy(BaseType *bt, Part part=nil) override
Vars_iter var_begin()
Constructor & operator=(const Constructor &rhs)
Definition Constructor.h:70
Constructor(const string &name, const Type &type, bool is_dap4=false)
Definition Constructor.h:52
void dump(ostream &strm) const override
dumps information about this object
Holds a sequence.
Definition D4Sequence.h:131
void set_length(int64_t count) override
Definition D4Sequence.h:195
static ostream & LMarg(ostream &strm)
Definition DapIndent.cc:61
static void Indent()
Definition DapIndent.cc:44
static void UnIndent()
Definition DapIndent.cc:46
Holds a DAP2 DDS.
Definition DataDDS.h:76
int get_protocol_major() const
Definition DataDDS.h:115
int get_protocol_minor() const
Definition DataDDS.h:116
string get_protocol() const
Definition DataDDS.h:114
A class for error processing.
Definition Error.h:92
A class for software fault reporting.
Definition InternalErr.h:61
abstract base class used to marshal/serialize dap data objects
Definition Marshaller.h:50
virtual void put_opaque(char *val, unsigned int len)=0
void m_duplicate(const Sequence &s)
Definition Sequence.cc:88
virtual void transform_to_dap4(D4Group *root, Constructor *container)
Definition Sequence.cc:183
virtual bool serialize_leaf(DDS &dds, ConstraintEvaluator &eval, Marshaller &m, bool ce_eval)
Definition Sequence.cc:652
virtual SequenceValues value()
Definition Sequence.cc:299
virtual string toString()
Definition Sequence.cc:240
virtual void intern_data_for_leaf(DDS &dds, ConstraintEvaluator &eval, sequence_values_stack_t &sequence_values_stack)
Definition Sequence.cc:863
virtual bool serialize_parent_part_one(DDS &dds, ConstraintEvaluator &eval, Marshaller &m)
Definition Sequence.cc:561
virtual bool is_leaf_sequence()
Definition Sequence.cc:1122
virtual void dump(ostream &strm) const
dumps information about this object
Definition Sequence.cc:1190
virtual bool read_row(int row, DDS &dds, ConstraintEvaluator &eval, bool ce_eval=true)
Definition Sequence.cc:436
virtual void set_leaf_sequence(int lvl=1)
Mark the Sequence which holds the leaf elements.
Definition Sequence.cc:1148
virtual void intern_data_parent_part_one(DDS &dds, ConstraintEvaluator &eval, sequence_values_stack_t &sequence_values_stack)
Definition Sequence.cc:761
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition Sequence.cc:1116
virtual void print_one_row(ostream &out, int row, string space, bool print_row_num=false)
Definition Sequence.cc:1043
stack< SequenceValues * > sequence_values_stack_t
Definition Sequence.h:203
virtual void serialize_parent_part_two(DDS &dds, ConstraintEvaluator &eval, Marshaller &m)
Definition Sequence.cc:624
virtual ~Sequence()
Definition Sequence.cc:210
Sequence & operator=(const Sequence &rhs)
Definition Sequence.cc:227
Sequence(const string &n)
The Sequence constructor.
Definition Sequence.cc:146
virtual SequenceValues & value_ref()
Definition Sequence.cc:303
virtual void set_value(SequenceValues &values)
Definition Sequence.cc:295
virtual BaseType * ptr_duplicate()
Definition Sequence.cc:167
virtual bool is_linear()
Check to see whether this variable can be printed simply.
Definition Sequence.cc:254
virtual BaseType * var_value(size_t row, const string &name)
Get the BaseType pointer to the named variable of a given row.
Definition Sequence.cc:310
virtual void set_leaf_p(bool state)
Definition Sequence.cc:1120
virtual void clear_local_data()
Definition Sequence.cc:218
virtual bool is_dap2_only_type()
Definition Sequence.cc:238
virtual void print_val_by_rows(ostream &out, string space="", bool print_decl_p=true, bool print_row_numbers=true)
Definition Sequence.cc:1090
virtual void intern_data_parent_part_two(DDS &dds, ConstraintEvaluator &eval, sequence_values_stack_t &sequence_values_stack)
Definition Sequence.cc:818
virtual void intern_data_private(ConstraintEvaluator &eval, DDS &dds, sequence_values_stack_t &sequence_values_stack)
Definition Sequence.cc:751
bool get_unsent_data() const
Get the unsent data property.
Definition Sequence.h:269
int get_starting_row_number()
Get the starting row number.
Definition Sequence.cc:993
void reset_row_number()
Rest the row number counter.
Definition Sequence.cc:368
void set_unsent_data(bool usd)
Set the unsent data property.
Definition Sequence.h:272
virtual bool serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval=true)
Definition Sequence.cc:545
virtual int length() const
Definition Sequence.cc:360
virtual bool deserialize(UnMarshaller &um, DDS *dds, bool reuse=false)
Deserialize (read from the network) the entire Sequence.
Definition Sequence.cc:937
virtual int get_row_stride()
Get the row stride.
Definition Sequence.cc:1005
virtual int get_ending_row_number()
Get the ending row number.
Definition Sequence.cc:1018
virtual BaseTypeRow * row_value(size_t row)
Get a whole row from the sequence.
Definition Sequence.cc:283
virtual void set_row_number_constraint(int start, int stop, int stride=1)
Definition Sequence.cc:1028
virtual int number_of_rows() const
Definition Sequence.cc:363
Holds a structure (aggregate) type.
Definition Structure.h:82
virtual void set_leaf_sequence(int level=1)
Traverse Structure, set Sequence leaf nodes.
Definition Structure.cc:285
abstract base class used to unmarshall/deserialize dap data objects
STL iterator class.
#define DBG(x)
Definition debug.h:58
#define DBG2(x)
Definition debug.h:74
top level DAP object to house generic methods
Definition AISConnect.cc:30
@ dods_sequence_c
Definition Type.h:108
@ dods_structure_c
Definition Type.h:106
vector< BaseType * > BaseTypeRow
Definition D4Sequence.h:49
vector< BaseTypeRow * > SequenceValues
Definition D4Sequence.h:52