libdap Updated for version 3.21.0
libdap4 is an implementation of OPeNDAP's DAP protocol.
Sequence.cc
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 <string>
42#include <sstream>
43
44#include "Byte.h"
45#include "Int16.h"
46#include "UInt16.h"
47#include "Int32.h"
48#include "UInt32.h"
49#include "Float32.h"
50#include "Float64.h"
51#include "Str.h"
52#include "Url.h"
53#include "Array.h"
54#include "Structure.h"
55#include "Sequence.h"
56#include "Grid.h"
57
58#include "Marshaller.h"
59#include "UnMarshaller.h"
60
61#include "debug.h"
62#include "Error.h"
63#include "InternalErr.h"
64#include "Sequence.h"
65#include "DDS.h"
66#include "DataDDS.h"
67#include "util.h"
68#include "InternalErr.h"
69#include "escaping.h"
70
71#include "D4Attributes.h"
72#include "D4Sequence.h"
73#include "D4Group.h"
74#include "Constructor.h"
75#include "DMR.h"
76#include "DapIndent.h"
77
78#undef CLEAR_LOCAL_DATA
79
80using namespace std;
81
82namespace libdap {
83
84static const unsigned char end_of_sequence = 0xA5; // binary pattern 1010 0101
85static const unsigned char start_of_instance = 0x5A; // binary pattern 0101 1010
86
87// Private member functions
88
89void Sequence::m_duplicate(const Sequence &s)
90{
91 DBG(cerr << "In Sequence::m_duplicate" << endl);
92
93 d_row_number = s.d_row_number;
94 d_starting_row_number = s.d_starting_row_number;
95 d_ending_row_number = s.d_ending_row_number;
96 d_row_stride = s.d_row_stride;
97 d_leaf_sequence = s.d_leaf_sequence;
98 d_unsent_data = s.d_unsent_data;
99 d_wrote_soi = s.d_wrote_soi;
100 d_top_most = s.d_top_most;
101
102 Sequence &cs = const_cast<Sequence &>(s);
103
104 // Copy the BaseType objects used to hold values.
105 for (vector<BaseTypeRow *>::iterator rows_iter = cs.d_values.begin(); rows_iter != cs.d_values.end(); rows_iter++) {
106 // Get the current BaseType Row
107 BaseTypeRow *src_bt_row_ptr = *rows_iter;
108 // Create a new row.
109 BaseTypeRow *dest_bt_row_ptr = new BaseTypeRow;
110 // Copy the BaseType objects from a row to new BaseType objects.
111 // Push new BaseType objects onto new row.
112 for (BaseTypeRow::iterator bt_row_iter = src_bt_row_ptr->begin(); bt_row_iter != src_bt_row_ptr->end();
113 bt_row_iter++) {
114 BaseType *src_bt_ptr = *bt_row_iter;
115 BaseType *dest_bt_ptr = src_bt_ptr->ptr_duplicate();
116 dest_bt_row_ptr->push_back(dest_bt_ptr);
117 }
118 // Push new row onto d_values.
119 d_values.push_back(dest_bt_row_ptr);
120 }
121}
122
123static void write_end_of_sequence(Marshaller &m)
124{
125 m.put_opaque((char *) &end_of_sequence, 1);
126}
127
128static void write_start_of_instance(Marshaller &m)
129{
130 m.put_opaque((char *) &start_of_instance, 1);
131}
132
133static unsigned char read_marker(UnMarshaller &um)
134{
135 unsigned char marker;
136 um.get_opaque((char *) &marker, 1);
137
138 return marker;
139}
140
141static bool is_start_of_instance(unsigned char marker)
142{
143 return (marker == start_of_instance);
144}
145
146static bool is_end_of_sequence(unsigned char marker)
147{
148 return (marker == end_of_sequence);
149}
150
151// Public member functions
152
161Sequence::Sequence(const string &n) :
162 Constructor(n, dods_sequence_c), d_row_number(-1), d_starting_row_number(-1), d_row_stride(1), d_ending_row_number(
163 -1), d_unsent_data(false), d_wrote_soi(false), d_leaf_sequence(false), d_top_most(false)
164{
165}
166
177Sequence::Sequence(const string &n, const string &d) :
178 Constructor(n, d, dods_sequence_c), d_row_number(-1), d_starting_row_number(-1),
179 d_row_stride(1), d_ending_row_number(-1), d_unsent_data(false),
180 d_wrote_soi(false), d_leaf_sequence(false), d_top_most(false)
181{
182}
183
186 Constructor(rhs)
187{
188 m_duplicate(rhs);
189}
190
191BaseType *
193{
194 return new Sequence(*this);
195}
196
211void
212Sequence::transform_to_dap4(D4Group *root, Constructor *container)
213{
214 D4Sequence *dest;
215 // If it's already a DAP4 object then we can just return it!
216 if(is_dap4()){
217 dest = static_cast<D4Sequence*>(ptr_duplicate());
218 dest->set_length(-1);
219 container->add_var_nocopy(dest);
220 return;
221 }
222 dest = new D4Sequence(name());
224 dest->set_length(-1);
225 container->add_var_nocopy(dest);
226}
227
228static inline void delete_bt(BaseType *bt_ptr)
229{
230 delete bt_ptr;
231 bt_ptr = 0;
232}
233
234static inline void delete_rows(BaseTypeRow *bt_row_ptr)
235{
236 for_each(bt_row_ptr->begin(), bt_row_ptr->end(), delete_bt);
237
238 delete bt_row_ptr;
239 bt_row_ptr = 0;
240}
241
242Sequence::~Sequence()
243{
244 try {
245 Sequence::clear_local_data(); // make the call explicit in a destructor
246 }
247 catch (const std::exception &) {
248 // It's hard to know what to do - Log it when we can, but that can fail, too.
249 }
250}
251
253{
254 if (!d_values.empty()) {
255 for_each(d_values.begin(), d_values.end(), delete_rows);
256 d_values.resize(0);
257 }
258
259 set_read_p(false);
260}
261
262Sequence &
263Sequence::operator=(const Sequence &rhs)
264{
265 if (this == &rhs) return *this;
266 Constructor::operator=(rhs);
267 m_duplicate(rhs);
268 return *this;
269}
270
275{
276 return true;
277}
278
280{
281 ostringstream oss;
282
283 oss << BaseType::toString();
284
285 for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
286 oss << (*i)->toString();
287 }
288
289 oss << endl;
290
291 return oss.str();
292}
293
295{
296 bool linear = true;
297 bool seq_found = false;
298 for (Vars_iter iter = d_vars.begin(); linear && iter != d_vars.end(); iter++) {
299 if ((*iter)->type() == dods_sequence_c) {
300 // A linear sequence cannot have more than one child seq. at any
301 // one level. If we've already found a seq at this level, return
302 // false.
303 if (seq_found) {
304 linear = false;
305 break;
306 }
307 seq_found = true;
308 linear = static_cast<Sequence *>((*iter))->is_linear();
309 }
310 else if ((*iter)->type() == dods_structure_c) {
311 linear = static_cast<Structure*>((*iter))->is_linear();
312 }
313 else {
314 // A linear sequence cannot have Arrays, Lists or Grids.
315 linear = (*iter)->is_simple_type();
316 }
317 }
318
319 return linear;
320}
321
328{
329 if (row >= d_values.size()) return 0; //nullptr
330 return d_values[row];
331}
332
340{
341 d_values = values;
342}
343
347{
348 return d_values;
349}
350
355{
356 return d_values;
357}
358
364BaseType *
365Sequence::var_value(size_t row, const string &name)
366{
367 BaseTypeRow *bt_row_ptr = row_value(row);
368 if (!bt_row_ptr) return 0;
369
370 BaseTypeRow::iterator bt_row_iter = bt_row_ptr->begin();
371 BaseTypeRow::iterator bt_row_end = bt_row_ptr->end();
372 while (bt_row_iter != bt_row_end && (*bt_row_iter)->name() != name)
373 ++bt_row_iter;
374
375 if (bt_row_iter == bt_row_end)
376 return 0;
377 else
378 return *bt_row_iter;
379}
380
386BaseType *
387Sequence::var_value(size_t row, size_t i)
388{
389 BaseTypeRow *bt_row_ptr = row_value(row);
390 if (!bt_row_ptr) return 0;
391
392 if (i >= bt_row_ptr->size()) return 0;
393
394 return (*bt_row_ptr)[i];
395}
396
397// This version returns -1. Each API-specific subclass should define a more
398// reasonable version. jhrg 5/24/96
399
416{
417 return -1;
418}
419
420// Hmmm. how is this different from length()?
421int Sequence::number_of_rows() const
422{
423 return d_values.size();
424}
425
430{
431 d_row_number = -1;
432}
433
440{
442
443 if (recur)
444 for (Vars_iter i = var_begin(), e = var_end(); i != e; ++i)
445 if ((*i)->type() == dods_sequence_c)
446 reset_row_number(true);
447}
448
449// Notes:
450// Assume that read() is implemented so that, when reading data for a nested
451// sequence, only the outer most level is *actually* read.
452// This is a consequence of our current (12/7/99) implementation of
453// the JGOFS server (which is the only server to actually use nested
454// sequences). 12/7/99 jhrg
455//
456// Stop assuming this. This logic is being moved into the JGOFS server
457// itself. 6/1/2001 jhrg
458
459// The read() function returns a boolean value, with TRUE
460// indicating that read() should be called again because there's
461// more data to read, and FALSE indicating there's no more data
462// to read. Note that this behavior is necessary to properly
463// handle variables that contain Sequences. Jose Garcia If an
464// error exists while reading, the implementers of the surrogate
465// library SHOULD throw an Error object which will propagate
466// beyond this point to to the original caller.
467// Jose Garcia
468
501bool Sequence::read_row(int row, DDS &dds, ConstraintEvaluator &eval, bool ce_eval)
502{
503 DBG2(cerr << "Entering Sequence::read_row for " << name() << ", row number " << row << ", current row " << d_row_number << endl);
504 if (row < d_row_number) throw InternalErr("Trying to back up inside a sequence!");
505
506 if (row == d_row_number) {
507 DBG2(cerr << "Leaving Sequence::read_row for " << name() << endl);
508 return false;
509 }
510
511 bool eof = false; // Start out assuming EOF is false.
512 while (!eof && d_row_number < row) {
513 if (!read_p()) {
514 // jhrg original version from 10/9/13 : eof = (read() == false);
515 eof = read();
516 }
517
518 // Advance the row number if ce_eval is false (we're not supposed to
519 // evaluate the selection) or both ce_eval and the selection are
520 // true.
521 if (!eof && (!ce_eval || eval.eval_selection(dds, dataset()))) d_row_number++;
522
523 set_read_p(false); // ...so that the next instance will be read
524 }
525
526 // Once we finish the above loop, set read_p to true so that the caller
527 // knows that data *has* been read. This is how the read() methods of the
528 // elements of the sequence know to not call read() but instead look for
529 // data values inside themselves.
530 set_read_p(true);
531
532 // Return true if we have valid data, false if we've read to the EOF.
533 DBG2(cerr << "Leaving Sequence::read_row for " << name() << " with eof: " << eof << endl);
534 return !eof; // jhrg 10/10/13 was: eof == 0;
535}
536
537// Private. This is used to process constraints on the rows of a sequence.
538// Starting with 3.2 we support constraints like Sequence[10:2:20]. This
539// odd-looking logic first checks if d_ending_row_number is the sentinel
540// value of -1. If so, the sequence was not constrained by row number and
541// this method should never return true (which indicates that we're at the
542// end of a row-number constraint). If d_ending_row_number is not -1, then is
543// \e i at the end point? 6/1/2001 jhrg
544inline bool Sequence::is_end_of_rows(int i)
545{
546 return ((d_ending_row_number == -1) ? false : (i > d_ending_row_number));
547}
548
609bool Sequence::serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval)
610{
611 // Special case leaf sequences!
612 bool status = false;
613
614 if (is_leaf_sequence())
615 status = serialize_leaf(dds, eval, m, ce_eval);
616 else
617 status = serialize_parent_part_one(dds, eval, m);
618
619 return status;
620}
621
622// We know this is not a leaf Sequence. That means that this Sequence holds
623// another Sequence as one of its fields _and_ that child Sequence triggers
624// the actual transmission of values.
625
626bool Sequence::serialize_parent_part_one(DDS &dds, ConstraintEvaluator &eval, Marshaller &m)
627{
628 DBG2(cerr << "Entering serialize_parent_part_one for " << name() << endl);
629
630 int i = (d_starting_row_number != -1) ? d_starting_row_number : 0;
631
632 // read_row returns true if valid data was read, false if the EOF was
633 // found. 6/1/2001 jhrg
634 // Since this is a parent sequence, read the row ignoring the CE (all of
635 // the CE clauses will be evaluated by the leaf sequence).
636 bool status = read_row(i, dds, eval, false);
637 DBG2(cerr << "Sequence::serialize_parent_part_one::read_row() status: " << status << endl);
638
639 while (status && !is_end_of_rows(i)) {
640 i += d_row_stride;
641
642 // DBG(cerr << "Writing Start of Instance marker" << endl);
643 // write_start_of_instance(sink);
644
645 // In this loop serialize will signal an error with an exception.
646 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
647 // Only call serialize for child Sequences; the leaf sequence
648 // will trigger the transmission of values for its parents (this
649 // sequence and maybe others) once it gets some valid data to
650 // send.
651 // Note that if the leaf sequence has no variables in the current
652 // projection, its serialize() method will never be called and that's
653 // the method that triggers actually sending values. Thus the leaf
654 // sequence must be the lowest level sequence with values whose send_p
655 // property is true.
656 if ((*iter)->send_p() && (*iter)->type() == dods_sequence_c) (*iter)->serialize(eval, dds, m);
657 }
658
659 set_read_p(false); // ...so this will read the next instance
660
661 status = read_row(i, dds, eval, false);
662 DBG(cerr << "Sequence::serialize_parent_part_one::read_row() status: " << status << endl);
663 }
664 // Reset current row number for next nested sequence element.
665 d_row_number = -1;
666
667 // Always write the EOS marker? 12/23/04 jhrg
668 // Yes. According to DAP2, a completely empty response is signaled by
669 // a return value of only the EOS marker for the outermost sequence.
670 if (d_top_most || d_wrote_soi) {
671 DBG(cerr << "Writing End of Sequence marker" << endl);
672 write_end_of_sequence(m);
673 d_wrote_soi = false;
674 }
675
676 return true; // Signal errors with exceptions.
677}
678
679// If we are here then we know that this is 'parent sequence' and that the
680// leaf sequence has found valid data to send. We also know that
681// serialize_parent_part_one has been called so data are in the instance's
682// fields. This is where we send data. Whereas ..._part_one() contains a
683// loop to iterate over all of rows in a parent sequence, this does not. This
684// method assumes that the serialize_leaf() will call it each time it needs
685// to be called.
686//
687// NB: This code only works if the child sequences appear after all other
688// variables.
689void Sequence::serialize_parent_part_two(DDS &dds, ConstraintEvaluator &eval, Marshaller &m)
690{
691 DBG(cerr << "Entering serialize_parent_part_two for " << name() << endl);
692
693 BaseType *btp = get_parent();
694 if (btp && btp->type() == dods_sequence_c) static_cast<Sequence&>(*btp).serialize_parent_part_two(dds, eval, m);
695
696 if (d_unsent_data) {
697 DBG(cerr << "Writing Start of Instance marker" << endl);
698 d_wrote_soi = true;
699 write_start_of_instance(m);
700
701 // In this loop serialize will signal an error with an exception.
702 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
703 // Send all the non-sequence variables
704 DBG(cerr << "Sequence::serialize_parent_part_two(), serializing "
705 << (*iter)->name() << endl);
706 if ((*iter)->send_p() && (*iter)->type() != dods_sequence_c) {
707 DBG(cerr << "Send P is true, sending " << (*iter)->name() << endl);
708 (*iter)->serialize(eval, dds, m, false);
709 }
710 }
711
712 d_unsent_data = false; // read should set this.
713 }
714}
715
716// This code is only run by a leaf sequence. Note that a one level sequence
717// is also a leaf sequence.
718bool Sequence::serialize_leaf(DDS &dds, ConstraintEvaluator &eval, Marshaller &m, bool ce_eval)
719{
720 DBG(cerr << "Entering Sequence::serialize_leaf for " << name() << endl);
721 int i = (d_starting_row_number != -1) ? d_starting_row_number : 0;
722
723 // read_row returns true if valid data was read, false if the EOF was
724 // found. 6/1/2001 jhrg
725 bool status = read_row(i, dds, eval, ce_eval);
726 DBG(cerr << "Sequence::serialize_leaf::read_row() status: " << status << endl);
727
728 // Once the first valid (satisfies the CE) row of the leaf sequence has
729 // been read, we know we're going to send data. Send the current instance
730 // of the parent/ancestor sequences now, if there are any. We only need
731 // to do this once, hence it's not inside the while loop, but we only
732 // send the parent seq data _if_ there's data in the leaf to send, that's
733 // why we wait until after the first call to read_row() here in the leaf
734 // sequence.
735 //
736 // NB: It's important to only call serialize_parent_part_two() for a
737 // Sequence that really is the parent of a leaf sequence.
738 if (status && !is_end_of_rows(i)) {
739 BaseType *btp = get_parent();
740 if (btp && btp->type() == dods_sequence_c) static_cast<Sequence&>(*btp).serialize_parent_part_two(dds, eval, m);
741 }
742
743 d_wrote_soi = false;
744 while (status && !is_end_of_rows(i)) {
745 i += d_row_stride;
746
747 DBG(cerr << "Writing Start of Instance marker" << endl);
748 d_wrote_soi = true;
749 write_start_of_instance(m);
750
751 // In this loop serialize will signal an error with an exception.
752 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
753 DBG(cerr << "Sequence::serialize_leaf(), serializing "
754 << (*iter)->name() << endl);
755 if ((*iter)->send_p()) {
756 DBG(cerr << "Send P is true, sending " << (*iter)->name() << endl);
757 (*iter)->serialize(eval, dds, m, false);
758 }
759 }
760
761 set_read_p(false); // ...so this will read the next instance
762
763 status = read_row(i, dds, eval, ce_eval);
764 DBG(cerr << "Sequence::serialize_leaf::read_row() status: " << status << endl);
765 }
766
767 // Only write the EOS marker if there's a matching Start Of Instance
768 // Marker in the stream.
769 if (d_wrote_soi || d_top_most) {
770 DBG(cerr << "Writing End of Sequence marker" << endl);
771 write_end_of_sequence(m);
772 }
773
774 return true; // Signal errors with exceptions.
775}
776
800{
801 DBG(cerr << "Sequence::intern_data - for " << name() << endl); DBG2(cerr << " intern_data, values: " << &d_values << endl);
802 if (is_dap4())
803 throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (").append(name()).append(")."), __FILE__, __LINE__);
804
805 // Why use a stack instead of return values? We need the stack because
806 // Sequences nested three of more levels deep will lose the middle
807 // instances when the intern_data_parent_part_two() code is run.
808 sequence_values_stack_t sequence_values_stack;
809
810 sequence_values_stack.push(&d_values);
811
812 intern_data_private(eval, dds, sequence_values_stack);
813}
814
815void Sequence::intern_data_private(ConstraintEvaluator &eval, DDS &dds, sequence_values_stack_t &sequence_values_stack)
816{
817 DBG(cerr << "Entering intern_data_private for " << name() << endl);
818
819 if (is_leaf_sequence())
820 intern_data_for_leaf(dds, eval, sequence_values_stack);
821 else
822 intern_data_parent_part_one(dds, eval, sequence_values_stack);
823}
824
825void Sequence::intern_data_parent_part_one(DDS & dds, ConstraintEvaluator & eval,
826 sequence_values_stack_t & sequence_values_stack)
827{
828 DBG(cerr << "Entering intern_data_parent_part_one for " << name() << endl);
829
830 int i = (get_starting_row_number() != -1) ? get_starting_row_number() : 0;
831
832 // read_row returns true if valid data was read, false if the EOF was
833 // found. 6/1/2001 jhrg
834 // Since this is a parent sequence, read the row ignoring the CE (all of
835 // the CE clauses will be evaluated by the leaf sequence).
836 bool status = read_row(i, dds, eval, false);
837
838 // Grab the current size of the value stack. We do this because it is
839 // possible that no nested sequences for this row happened to be
840 // selected because of a constraint evaluation or the last row is not
841 // selected because of a constraint evaluation. In either case, no
842 // nested sequence d_values are pushed onto the stack, so there is
843 // nothing to pop at the end of this function. pcw 07/14/08
844 SequenceValues::size_type orig_stack_size = sequence_values_stack.size();
845
846 while (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
847 i += get_row_stride();
848 for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
849 if ((*iter)->send_p()) {
850 switch ((*iter)->type()) {
851 case dods_sequence_c:
852 static_cast<Sequence&>(**iter).intern_data_private(eval, dds, sequence_values_stack);
853 break;
854
855 default:
856 (*iter)->intern_data(eval, dds);
857 break;
858 }
859 }
860 }
861
862 set_read_p(false); // ...so this will read the next instance
863
864 status = read_row(i, dds, eval, false);
865 }
866
867 // Reset current row number for next nested sequence element.
869
870 // if the size of the stack is larger than the original size (retrieved
871 // above) then pop the top set of d_values from the stack. If it's the
872 // same, then no nested sequences, or possibly the last nested sequence,
873 // were pushed onto the stack, so there is nothing to pop.
874 if (sequence_values_stack.size() > orig_stack_size) {
875 DBG2(cerr << " popping d_values (" << sequence_values_stack.top()
876 << ") off stack; size: " << sequence_values_stack.size() << endl);
877 sequence_values_stack.pop();
878 }
879
880 DBG(cerr << "Leaving intern_data_parent_part_one for " << name() << endl);
881}
882
883void Sequence::intern_data_parent_part_two(DDS &dds, ConstraintEvaluator &eval,
884 sequence_values_stack_t &sequence_values_stack)
885{
886 DBG(cerr << "Entering intern_data_parent_part_two for " << name() << endl);
887
888 BaseType *btp = get_parent();
889 if (btp && btp->type() == dods_sequence_c) {
890 static_cast<Sequence&>(*btp).intern_data_parent_part_two(dds, eval, sequence_values_stack);
891 }
892
893 DBG2(cerr << " stack size: " << sequence_values_stack.size() << endl);
894 SequenceValues *values = sequence_values_stack.top();
895 DBG2(cerr << " using values = " << (void *)values << endl);
896
897 if (get_unsent_data()) {
898 BaseTypeRow *row_data = new BaseTypeRow;
899
900 // In this loop transfer_data will signal an error with an exception.
901 for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
902
903 if ((*iter)->send_p() && (*iter)->type() != dods_sequence_c) {
904 row_data->push_back((*iter)->ptr_duplicate());
905 }
906 else if ((*iter)->send_p()) { //Sequence; must be the last variable
907 Sequence *tmp = dynamic_cast<Sequence*>((*iter)->ptr_duplicate());
908 if (!tmp) {
909 delete row_data;
910 throw InternalErr(__FILE__, __LINE__, "Expected a Sequence.");
911 }
912 row_data->push_back(tmp);
913 DBG2(cerr << " pushing d_values of " << tmp->name()
914 << " (" << &(tmp->d_values)
915 << ") on stack; size: " << sequence_values_stack.size()
916 << endl);
917 // This pushes the d_values field of the newly created leaf
918 // Sequence onto the stack. The code then returns to intern
919 // _data_for_leaf() where this value will be used.
920 sequence_values_stack.push(&(tmp->d_values));
921 }
922 }
923
924 DBG2(cerr << " pushing values for " << name()
925 << " to " << values << endl);
926 values->push_back(row_data);
927 set_unsent_data(false);
928 }
929
930 DBG(cerr << "Leaving intern_data_parent_part_two for " << name() << endl);
931}
932
933void Sequence::intern_data_for_leaf(DDS &dds, ConstraintEvaluator &eval, sequence_values_stack_t &sequence_values_stack)
934{
935 DBG(cerr << "Entering intern_data_for_leaf for " << name() << endl);
936
937 int i = (get_starting_row_number() != -1) ? get_starting_row_number() : 0;
938
939 DBG2(cerr << " reading row " << i << endl);
940 bool status = read_row(i, dds, eval, true);
941 DBG2(cerr << " status: " << status << endl); DBG2(cerr << " ending row number: " << get_ending_row_number() << endl);
942
943 if (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
944 BaseType *btp = get_parent();
945 if (btp && btp->type() == dods_sequence_c) {
946 // This call will read the values for the parent sequences and
947 // then allocate a new instance for the leaf and push that onto
948 // the stack.
949 static_cast<Sequence&>(*btp).intern_data_parent_part_two(dds, eval, sequence_values_stack);
950 }
951
952 // intern_data_parent_part_two pushes the d_values field of the leaf
953 // onto the stack, so this operation grabs that value and then loads
954 // data into it.
955 SequenceValues *values = sequence_values_stack.top();
956 DBG2(cerr << " using values = " << values << endl);
957
958 while (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
959 i += get_row_stride();
960
961 // Copy data from the object's fields to this new BaeTypeRow instance
962 BaseTypeRow *row_data = new BaseTypeRow;
963 for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
964 if ((*iter)->send_p()) {
965 row_data->push_back((*iter)->ptr_duplicate());
966 }
967 }
968
969 DBG2(cerr << " pushing values for " << name()
970 << " to " << values << endl);
971 // Save the row_data to values().
972 values->push_back(row_data);
973
974 set_read_p(false); // ...so this will read the next instance
975 // Read the ith row into this object's fields
976 status = read_row(i, dds, eval, true);
977 }
978
979 DBG2(cerr << " popping d_values (" << sequence_values_stack.top()
980 << ") off stack; size: " << sequence_values_stack.size() << endl);
981 sequence_values_stack.pop();
982 }
983
984 DBG(cerr << "Leaving intern_data_for_leaf for " << name() << endl);
985}
986
1007bool Sequence::deserialize(UnMarshaller &um, DDS *dds, bool reuse)
1008{
1009#if 0
1010 // Nathan's tip - this is something that should never happen
1011 DataDDS *dd = dynamic_cast<DataDDS *>(dds);
1012 if (!dd) throw InternalErr("Expected argument 'dds' to be a DataDDS!");
1013
1014 DBG2(cerr << "Reading from server/protocol version: "
1015 << dd->get_protocol_major() << "." << dd->get_protocol_minor()
1016 << endl);
1017
1018 // Check for old servers.
1019 if (dd->get_protocol_major() < 2) {
1020 throw Error(
1021 string("The protocl version (") + dd->get_protocol()
1022 + ") indicates that this\nis an old server which may not correctly transmit Sequence variables.\nContact the server administrator.");
1023 }
1024#endif
1025 while (true) {
1026 // Grab the sequence stream's marker.
1027 unsigned char marker = read_marker(um);
1028 if (is_end_of_sequence(marker))
1029 break; // EXIT the while loop here!!!
1030 else if (is_start_of_instance(marker)) {
1031 d_row_number++;
1032 DBG2(cerr << "Reading row " << d_row_number << " of "
1033 << name() << endl);
1034 BaseTypeRow *bt_row_ptr = new BaseTypeRow;
1035 // Read the instance's values, building up the row
1036 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
1037 BaseType *bt_ptr = (*iter)->ptr_duplicate();
1038 bt_ptr->deserialize(um, dds, reuse);
1039 DBG2(cerr << "Deserialized " << bt_ptr->name() << " ("
1040 << bt_ptr << ") = "); DBG2(bt_ptr->print_val(stderr, ""));
1041 bt_row_ptr->push_back(bt_ptr);
1042 }
1043 // Append this row to those accumulated.
1044 d_values.push_back(bt_row_ptr);
1045 }
1046 else
1047 throw Error("I could not read the expected Sequence data stream marker!");
1048 };
1049
1050 return false;
1051}
1052
1053// Return the current row number.
1054
1067{
1068 return d_starting_row_number;
1069}
1070
1082{
1083 return d_row_stride;
1084}
1085
1098{
1099 return d_ending_row_number;
1100}
1101
1110void Sequence::set_row_number_constraint(int start, int stop, int stride)
1111{
1112 if (stop < start) throw Error(malformed_expr, "Starting row number must precede the ending row number.");
1113
1114 d_starting_row_number = start;
1115 d_row_stride = stride;
1116 d_ending_row_number = stop;
1117}
1118
1119void Sequence::print_one_row(FILE *out, int row, string space, bool print_row_num)
1120{
1121 ostringstream oss;
1122 print_one_row(oss, row, space, print_row_num);
1123 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1124}
1125
1126void Sequence::print_one_row(ostream &out, int row, string space, bool print_row_num)
1127{
1128 if (print_row_num) out << "\n" << space << row << ": ";
1129
1130 out << "{ ";
1131
1132 int elements = element_count();
1133 int j = 0;
1134 BaseType *bt_ptr = 0;
1135
1136 // This version of print_one_row() works for both data read with
1137 // deserialize(), where each variable is assumed to have valid data, and
1138 // intern_data(), where some/many variables do not. Because of that, it's
1139 // not correct to assume that all of the elements will be printed, which
1140 // is what the old code did.
1141 // Print the first value
1142 while (j < elements && !bt_ptr) {
1143 bt_ptr = var_value(row, j++);
1144 if (bt_ptr) { // data
1145 if (bt_ptr->type() == dods_sequence_c)
1146 static_cast<Sequence*>(bt_ptr)->print_val_by_rows(out, space + " ", false, print_row_num);
1147 else
1148 bt_ptr->print_val(out, space, false);
1149 }
1150 }
1151
1152 // Print the remaining values
1153 while (j < elements) {
1154 bt_ptr = var_value(row, j++);
1155 if (bt_ptr) { // data
1156 out << ", ";
1157 if (bt_ptr->type() == dods_sequence_c)
1158 static_cast<Sequence*>(bt_ptr)->print_val_by_rows(out, space + " ", false, print_row_num);
1159 else
1160 bt_ptr->print_val(out, space, false);
1161 }
1162 }
1163
1164 out << " }";
1165}
1166
1167void Sequence::print_val_by_rows(FILE *out, string space, bool print_decl_p, bool print_row_numbers)
1168{
1169 ostringstream oss;
1170 print_val_by_rows(oss, space, print_decl_p, print_row_numbers);
1171 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1172}
1173
1174void Sequence::print_val_by_rows(ostream &out, string space, bool print_decl_p, bool print_row_numbers)
1175{
1176 if (print_decl_p) {
1177 print_decl(out, space, false);
1178 out << " = ";
1179 }
1180
1181 out << "{ ";
1182
1183 int rows = number_of_rows() - 1;
1184 int i;
1185 for (i = 0; i < rows; ++i) {
1186 print_one_row(out, i, space, print_row_numbers);
1187 out << ", ";
1188 }
1189 print_one_row(out, i, space, print_row_numbers);
1190
1191 out << " }";
1192
1193 if (print_decl_p) out << ";\n";
1194}
1195
1196void Sequence::print_val(FILE *out, string space, bool print_decl_p)
1197{
1198 print_val_by_rows(out, space, print_decl_p, false);
1199}
1200
1201void Sequence::print_val(ostream &out, string space, bool print_decl_p)
1202{
1203 print_val_by_rows(out, space, print_decl_p, false);
1204}
1205
1206void Sequence::set_leaf_p(bool state)
1207{
1208 d_leaf_sequence = state;
1209}
1210
1211bool Sequence::is_leaf_sequence()
1212{
1213 return d_leaf_sequence;
1214}
1215
1241{
1242 bool has_child_sequence = false;
1243
1244 if (lvl == 1) d_top_most = true;
1245
1246 DBG2(cerr << "Processing sequence " << name() << endl);
1247
1248 for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
1249 // About the test for send_p(): Only descend into a sequence if it has
1250 // fields that might be sent. Thus if, in a two-level sequence, nothing
1251 // in the lower level is to be sent, the upper level is marked as the
1252 // leaf sequence. This ensures that values _will_ be sent (see the comment
1253 // in serialize_leaf() and serialize_parent_part_one()).
1254 if ((*iter)->type() == dods_sequence_c && (*iter)->send_p()) {
1255 if (has_child_sequence)
1256 throw Error("This implementation does not support more than one nested sequence at a level. Contact the server administrator.");
1257
1258 has_child_sequence = true;
1259 static_cast<Sequence&>(**iter).set_leaf_sequence(++lvl);
1260 }
1261 else if ((*iter)->type() == dods_structure_c) {
1262 static_cast<Structure&>(**iter).set_leaf_sequence(lvl);
1263 }
1264 }
1265
1266 if (!has_child_sequence)
1267 set_leaf_p(true);
1268 else
1269 set_leaf_p(false);
1270
1271 DBG2(cerr << "is_leaf_sequence(): " << is_leaf_sequence() << " (" << name() << ")" << endl);
1272}
1273
1282void Sequence::dump(ostream &strm) const
1283{
1284 strm << DapIndent::LMarg << "Sequence::dump - (" << (void *) this << ")" << endl;
1285 DapIndent::Indent();
1286 Constructor::dump(strm);
1287 strm << DapIndent::LMarg << "# rows deserialized: " << d_row_number << endl;
1288 strm << DapIndent::LMarg << "bracket notation information:" << endl;
1289 DapIndent::Indent();
1290 strm << DapIndent::LMarg << "starting row #: " << d_starting_row_number << endl;
1291 strm << DapIndent::LMarg << "row stride: " << d_row_stride << endl;
1292 strm << DapIndent::LMarg << "ending row #: " << d_ending_row_number << endl;
1293 DapIndent::UnIndent();
1294
1295 strm << DapIndent::LMarg << "data been sent? " << d_unsent_data << endl;
1296 strm << DapIndent::LMarg << "start of instance? " << d_wrote_soi << endl;
1297 strm << DapIndent::LMarg << "is leaf sequence? " << d_leaf_sequence << endl;
1298 strm << DapIndent::LMarg << "top most in hierarchy? " << d_top_most << endl;
1299 DapIndent::UnIndent();
1300}
1301
1302} // namespace libdap
1303
The basic data type for the DODS DAP types.
Definition BaseType.h:120
virtual void intern_data()
Read data into this variable.
Definition BaseType.cc:936
virtual bool deserialize(UnMarshaller &um, DDS *dds, bool reuse=false)
Receive data from the net.
Definition BaseType.cc:949
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:317
virtual BaseType * get_parent() const
Definition BaseType.cc:748
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:477
virtual string dataset() const
Returns the name of the dataset used to create this instance.
Definition BaseType.cc:355
virtual string toString()
Definition BaseType.cc:180
virtual BaseType * ptr_duplicate()=0
BaseType(const string &n, const Type &t, bool is_dap4=false)
The BaseType constructor.
Definition BaseType.cc:126
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition BaseType.cc:1096
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.
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()
void dump(ostream &strm) const override
dumps information about this object
Holds a sequence.
Definition D4Sequence.h:134
void set_length(int64_t count) override
Definition D4Sequence.h:199
Holds a DAP2 DDS.
Definition DataDDS.h:78
A class for error processing.
Definition Error.h:94
A class for software fault reporting.
Definition InternalErr.h:65
abstract base class used to marshal/serialize dap data objects
Definition Marshaller.h:50
Holds a sequence.
Definition Sequence.h:163
virtual void transform_to_dap4(D4Group *root, Constructor *container)
Definition Sequence.cc:212
virtual SequenceValues value()
Definition Sequence.cc:346
virtual string toString()
Definition Sequence.cc:279
virtual void dump(ostream &strm) const
dumps information about this object
Definition Sequence.cc:1282
virtual bool read_row(int row, DDS &dds, ConstraintEvaluator &eval, bool ce_eval=true)
Definition Sequence.cc:501
virtual void set_leaf_sequence(int lvl=1)
Mark the Sequence which holds the leaf elements.
Definition Sequence.cc:1240
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition Sequence.cc:1201
Sequence(const string &n)
The Sequence constructor.
Definition Sequence.cc:161
virtual SequenceValues & value_ref()
Definition Sequence.cc:354
virtual void set_value(SequenceValues &values)
Definition Sequence.cc:339
virtual BaseType * ptr_duplicate()
Definition Sequence.cc:192
virtual bool is_linear()
Check to see whether this variable can be printed simply.
Definition Sequence.cc:294
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:365
virtual void clear_local_data()
Definition Sequence.cc:252
virtual bool is_dap2_only_type()
Definition Sequence.cc:274
bool get_unsent_data() const
Get the unsent data property.
Definition Sequence.h:271
int get_starting_row_number()
Get the starting row number.
Definition Sequence.cc:1066
void reset_row_number()
Rest the row number counter.
Definition Sequence.cc:429
void set_unsent_data(bool usd)
Set the unsent data property.
Definition Sequence.h:277
virtual bool serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval=true)
Definition Sequence.cc:609
virtual int length() const
Definition Sequence.cc:415
virtual bool deserialize(UnMarshaller &um, DDS *dds, bool reuse=false)
Deserialize (read from the network) the entire Sequence.
Definition Sequence.cc:1007
virtual int get_row_stride()
Get the row stride.
Definition Sequence.cc:1081
virtual int get_ending_row_number()
Get the ending row number.
Definition Sequence.cc:1097
virtual BaseTypeRow * row_value(size_t row)
Get a whole row from the sequence.
Definition Sequence.cc:327
virtual void set_row_number_constraint(int start, int stop, int stride=1)
Definition Sequence.cc:1110
Holds a structure (aggregate) type.
Definition Structure.h:84
virtual void set_leaf_sequence(int level=1)
Traverse Structure, set Sequence leaf nodes.
Definition Structure.cc:309
abstract base class used to unmarshall/deserialize dap data objects
top level DAP object to house generic methods
Definition AISConnect.cc:30
vector< BaseType * > BaseTypeRow
Definition D4Sequence.h:50
vector< BaseTypeRow * > SequenceValues
Definition D4Sequence.h:53