bes  Updated for version 3.20.6
get_ascii_dap4.cc
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // Copyright (c) 2006 OPeNDAP, Inc.
5 // Author: James Gallagher <jgallagher@opendap.org>
6 //
7 // This is free software; you can redistribute it and/or modify it under the
8 // terms of the GNU Lesser General Public License as published by the Free
9 // Software Foundation; either version 2.1 of the License, or (at your
10 // option) any later version.
11 //
12 // This is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 // more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
22 
23 // This file holds the interface for the 'get data as ascii' function of the
24 // OPeNDAP/HAO data server. This function is called by the BES when it loads
25 // this as a module. The functions in the file ascii_val.cc also use this, so
26 // the same basic processing software can be used both by Hyrax and tie older
27 // Server3.
28 
29 #include <iostream>
30 #include <sstream>
31 #include <iomanip>
32 
33 #include <DMR.h>
34 #include <BaseType.h>
35 #include <Structure.h>
36 #include <Array.h>
37 #include <D4Sequence.h>
38 #include <D4Enum.h>
39 #include <D4Opaque.h>
40 #include <D4Group.h>
41 #include <crc.h>
42 #include "InternalErr.h"
43 
44 #include "get_ascii_dap4.h"
45 
46 namespace dap_asciival {
47 
48 using namespace libdap;
49 using namespace std;
50 
51 // most of the code here defines functions before they are used; these three
52 // need to be declared.
53 static void print_values_as_ascii(BaseType *btp, bool print_name, ostream &strm, Crc32 &checksum);
54 static void print_sequence_header(D4Sequence *s, ostream &strm);
55 static void print_val_by_rows(D4Sequence *seq, ostream &strm, Crc32 &checksum);
56 
67 static void print_array_vector(Array *a, ostream &strm, bool print_name)
68 {
69  if (print_name)
70  strm << a->FQN() << ", " ;
71 
72  // only one dimension
73  // Added to support zero-length arrays. jhrg 2/2/16
74  if (a->dimension_size(a->dim_begin(), true) > 0) {
75  int end = a->dimension_size(a->dim_begin(), true) - 1;
76 
77  for (int i = 0; i < end; ++i) {
78  a->var(i)->print_val(strm, "", false /*print_decl*/);
79  strm << ", ";
80  }
81  a->var(end)->print_val(strm, "", false /*print_decl*/);
82  }
83 }
84 
96 static int print_array_row(Array *a, ostream &strm, int index, int number)
97 {
98  // Added to support zero-length arrays. jhrg 2/2/16
99  if (number > 0) {
100  for (int i = 0; i < number; ++i) {
101  a->var(index++)->print_val(strm, "", false /*print_decl*/);
102  strm << ", ";
103  }
104 
105  a->var(index++)->print_val(strm, "", false /*print_decl*/);
106  }
107  return index;
108 }
109 
110 // This code implements simple modulo arithmetic. The vector shape contains
111 // This code implements simple modulo arithmetic. The vector shape contains
112 // the maximum count value for each dimension, state contains the current
113 // state. For example, if shape holds 10, 20 then when state holds 0, 20
114 // calling this method will increment state to 1, 0. For this example,
115 // calling the method with state equal to 10, 20 will reset state to 0, 0 and
116 // the return value will be false.
117 static bool increment_state(vector<int> *state, const vector<int> &shape)
118 {
119  vector < int >::reverse_iterator state_riter;
120  vector < int >::const_reverse_iterator shape_riter;
121  for (state_riter = state->rbegin(), shape_riter = shape.rbegin();
122  state_riter < state->rend(); state_riter++, shape_riter++) {
123  if (*state_riter == *shape_riter - 1) {
124  *state_riter = 0;
125  }
126  else {
127  *state_riter = *state_riter + 1;
128  return true;
129  }
130  }
131 
132  return false;
133 }
134 
135 static vector <int> get_shape_vector(Array *a, size_t n)
136 {
137  if (n < 1 || n > a->dimensions(true)) {
138  ostringstream oss;
139  oss << "Attempt to get " << n << " dimensions from " << a->name() << " which has " << a->dimensions(true) << " dimensions";
140  throw InternalErr(__FILE__, __LINE__, oss.str());
141  }
142 
143  vector <int>shape;
144  Array::Dim_iter p = a->dim_begin();
145  for (unsigned i = 0; i < n && p != a->dim_end(); ++i, ++p) {
146  shape.push_back(a->dimension_size(p, true));
147  }
148 
149  return shape;
150 }
151 
155 static int get_nth_dim_size(Array *a, size_t n)
156 {
157  if (n > a->dimensions(true) - 1) {
158  ostringstream oss;
159  oss << "Attempt to get dimension " << n << " from " << a->name() << " which has " << a->dimensions(true) << " dimensions";
160  throw InternalErr(__FILE__, __LINE__, oss.str());
161  }
162 
163  return a->dimension_size(a->dim_begin() + n, true);
164 }
165 
166 static void print_ndim_array(Array *a, ostream &strm, bool /*print_name */ )
167 {
168 
169  int dims = a->dimensions(true);
170  if (dims <= 1)
171  throw InternalErr(__FILE__, __LINE__, "Dimension count is <= 1 while printing multidimensional array.");
172 
173  // shape holds the maximum index value of all but the last dimension of
174  // the array (not the size; each value is one less than the size).
175  vector<int> shape = get_shape_vector(a, dims - 1);
176  int rightmost_dim_size = get_nth_dim_size(a, dims - 1);
177 
178  // state holds the indexes of the current row being printed. For an N-dim
179  // array, there are N-1 dims that are iterated over when printing (the
180  // Nth dim is not printed explicitly. Instead it's the number of values
181  // on the row.
182  vector<int> state(dims - 1, 0);
183 
184  bool more_indices;
185  int index = 0;
186  do {
187  // Print indices for all dimensions except the last one.
188  strm << a->FQN();
189 
190  for (int i = 0; i < dims - 1; ++i) {
191  strm << "[" << state[i] << "]" ;
192  }
193  strm << ", " ;
194 
195  index = print_array_row(a, strm, index, rightmost_dim_size - 1);
196  more_indices = increment_state(&state, shape);
197  if (more_indices)
198  strm << endl ;
199 
200  } while (more_indices);
201 }
202 
203 static int get_index(Array *a, vector<int> indices)
204 {
205  if (indices.size() != a->dimensions(true))
206  throw InternalErr(__FILE__, __LINE__, "Index vector is the wrong size!");
207 
208  // suppose shape is [3][4][5][6] for x,y,z,t. The index is
209  // t + z(6) + y(5 * 6) + x(4 * 5 *6).
210  // Assume that indices[0] holds x, indices[1] holds y, ...
211 
212  vector < int >shape = get_shape_vector(a, indices.size());
213 
214  // We want to work from the rightmost index to the left
215  reverse(indices.begin(), indices.end());
216  reverse(shape.begin(), shape.end());
217 
218  vector<int>::iterator indices_iter = indices.begin();
219  vector<int>::iterator shape_iter = shape.begin();
220 
221  int index = *indices_iter++; // in the ex. above, this adds `t'
222  int multiplier = 1;
223  while (indices_iter != indices.end()) {
224  multiplier *= *shape_iter++;
225  index += multiplier * *indices_iter++;
226  }
227 
228  return index;
229 }
230 
240 static void print_complex_array(Array *a, ostream &strm, bool print_name, Crc32 &checksum)
241 {
242  int dims = a->dimensions(true);
243  if (dims < 1)
244  throw InternalErr(__FILE__, __LINE__, "Dimension count is <= 1 while printing multidimensional array.");
245 
246  // shape holds the maximum index value of all but the last dimension of
247  // the array (not the size; each value is one less that the size).
248  vector<int> shape = get_shape_vector(a, dims);
249 
250  vector<int> state(dims, 0);
251 
252  bool more_indices;
253  do {
254  // Print indices for all dimensions except the last one.
255  strm << a->FQN();
256 
257  for (int i = 0; i < dims; ++i) {
258  strm << "[" << state[i] << "]" ;
259  }
260  strm << endl;
261 
262  print_values_as_ascii(a->var(get_index(a, state)), print_name, strm, checksum);
263 
264  more_indices = increment_state(&state, shape);
265 
266  if (more_indices)
267  strm << endl;
268 
269  } while (more_indices);
270 }
271 
281 static void print_values_as_ascii(Array *a, bool print_name, ostream &strm, Crc32 &checksum)
282 {
283  if (a->var()->is_simple_type()) {
284  if (a->dimensions(true) > 1) {
285  print_ndim_array(a, strm, print_name);
286  }
287  else {
288  print_array_vector(a, strm, print_name);
289  }
290  }
291  else {
292  print_complex_array(a, strm, print_name, checksum);
293  }
294 }
295 
296 static void print_structure_header(Structure *s, ostream &strm)
297 {
298  Constructor::Vars_iter p = s->var_begin(), e = s->var_end();
299  bool needs_comma = false;
300  while (p != e) {
301  if((*p)->send_p()){
302  if ((*p)->is_simple_type())
303  strm << (needs_comma?", ":"") << (*p)->FQN();
304  else if ((*p)->type() == dods_structure_c)
305  print_structure_header(static_cast<Structure*>(*p), strm);
306  else if ((*p)->type() == dods_sequence_c)
307  print_sequence_header(static_cast<D4Sequence*>(*p), strm);
308  else
309  throw InternalErr(__FILE__, __LINE__, "Unknown or unsupported type.");
310  needs_comma = true;
311  }
312  ++p;
313  }
314 }
315 
316 static void print_structure_ascii(Structure *s, ostream &strm, bool print_name, Crc32 &checksum)
317 {
318  if (s->is_linear()) {
319  if (print_name) {
320  print_structure_header(s, strm);
321  strm << endl;
322  }
323 
324  Constructor::Vars_iter p = s->var_begin(), e = s->var_end();
325  while (p !=e) {
326  // bug: print_name should be false, but will be true because it's not a param here
327  if ((*p)->send_p()) print_values_as_ascii(*p, false /*print_name*/, strm, checksum);
328 
329  if (++p != e) strm << ", ";
330  }
331  }
332  else {
333  for (Constructor::Vars_iter p = s->var_begin(), e = s->var_end(); p != e; ++p) {
334  if ((*p)->send_p()) {
335  print_values_as_ascii(*p, print_name, strm, checksum);
336  // This line outputs an extra endl when print_ascii is called for
337  // nested structures because an endl is written for each member
338  // and then once for the structure itself. 9/14/2001 jhrg
339  strm << endl;
340  }
341  }
342  }
343 }
344 
345 static void print_values_as_ascii(Structure *v, bool print_name, ostream &strm, Crc32 &checksum)
346 {
347  print_structure_ascii(v, strm, print_name, checksum);
348 }
349 
350 static void print_one_row(D4Sequence *seq, ostream &strm, Crc32 &checksum, int row)
351 {
352  int elements = seq->element_count();
353  int j = 0;
354  BaseType *btp = 0;
355  bool first_val = true;
356 
357  while (j < elements) {
358  btp = seq->var_value(row, j++);
359  if (btp) { // data
360  if (!first_val)
361  strm << ", ";
362  first_val = false;
363  if (btp->type() == dods_sequence_c)
364  print_val_by_rows(static_cast<D4Sequence*>(btp), strm, checksum);
365  else
366  print_values_as_ascii(btp, false, strm, checksum);
367  }
368  }
369 }
370 
371 static void print_val_by_rows(D4Sequence *seq, ostream &strm, Crc32 &checksum)
372 {
373  if (seq->length() != 0) {
374  int rows = seq->length() /*- 1*/; // -1 because the last row is treated specially
375  for (int i = 0; i < rows; ++i) {
376  print_one_row(seq, strm, checksum, i);
377  strm << endl;
378  }
379  }
380 }
381 
382 static void print_sequence_header(D4Sequence *s, ostream &strm)
383 {
384  Constructor::Vars_iter p = s->var_begin(), e = s->var_end();
385  bool needs_comma = false;
386  while (p != e) {
387  if((*p)->send_p()){
388  if((*p)->is_simple_type())
389  strm << (needs_comma?", ":"") << (*p)->FQN();
390  else if ((*p)->type() == dods_structure_c)
391  print_structure_header(static_cast<Structure*>((*p)), strm);
392  else if ((*p)->type() == dods_sequence_c)
393  print_sequence_header(static_cast<D4Sequence*>((*p)), strm);
394  else
395  throw InternalErr(__FILE__, __LINE__, "Unknown or unsupported type.");
396 
397  needs_comma = true;
398  }
399  ++p;
400  }
401 }
402 
403 
404 static void print_values_as_ascii(D4Sequence *v, bool print_name, ostream &strm, Crc32 &checksum)
405 {
406  if (print_name) {
407  print_sequence_header(v, strm);
408  strm << endl;
409  }
410 
411  print_val_by_rows(v, strm, checksum);
412 }
413 
414 static void print_values_as_ascii(D4Opaque *v, bool print_name, ostream &strm, Crc32 &/*checksum*/)
415 {
416  if (print_name)
417  strm << v->FQN() << ", ";
418  strm << v->value().size() << " bytes" << endl;
419 }
420 
421 static void print_values_as_ascii(D4Group *group, bool print_name, ostream &strm, Crc32 &checksum)
422 {
423  for (D4Group::groupsIter g = group->grp_begin(), e = group->grp_end(); g != e; ++g)
424  print_values_as_ascii(*g, print_name, strm, checksum);
425 
426  // Specialize how the top-level variables in any Group are sent; include
427  // a checksum for them. A subset operation might make an interior set of
428  // variables, but the parent structure will still be present and the checksum
429  // will be computed for that structure. In other words, DAP4 does not try
430  // to sort out which variables are the 'real' top-level variables and instead
431  // simply computes the CRC for whatever appears as a variable in the root
432  // group.
433  for (Constructor::Vars_iter i = group->var_begin(), e = group->var_end(); i != e; ++i) {
434  // Only send the stuff in the current subset.
435  if ((*i)->send_p()) {
436  (*i)->intern_data();
437 
438  // print the data
439  print_values_as_ascii((*i), print_name, strm, checksum);
440  strm << endl;
441  }
442  }
443 }
444 
454 static void print_values_as_ascii(BaseType *btp, bool print_name, ostream &strm, Crc32 &checksum)
455 {
456  switch (btp->type()) {
457  case dods_null_c:
458  throw InternalErr(__FILE__, __LINE__, "Unknown type");
459 
460  case dods_byte_c:
461  case dods_char_c:
462 
463  case dods_int8_c:
464  case dods_uint8_c:
465 
466  case dods_int16_c:
467  case dods_uint16_c:
468  case dods_int32_c:
469  case dods_uint32_c:
470 
471  case dods_int64_c:
472  case dods_uint64_c:
473 
474  case dods_float32_c:
475  case dods_float64_c:
476  case dods_str_c:
477  case dods_url_c:
478  case dods_enum_c:
479  if (print_name) strm << btp->FQN() << ", ";
480  btp->print_val(strm, "" /*leading space*/, false /*print dap2 decl*/);
481  break;
482 
483  case dods_opaque_c:
484  print_values_as_ascii(static_cast<D4Opaque*>(btp), print_name, strm, checksum);
485  break;
486 
487  case dods_array_c:
488  print_values_as_ascii(static_cast<Array*>(btp), print_name, strm, checksum);
489  break;
490 
491  case dods_structure_c:
492  print_values_as_ascii(static_cast<Structure*>(btp), print_name, strm, checksum);
493  break;
494 
495  case dods_sequence_c:
496  print_values_as_ascii(static_cast<D4Sequence*>(btp), print_name, strm, checksum);
497  break;
498 
499  case dods_group_c:
500  print_values_as_ascii(static_cast<D4Group*>(btp), print_name, strm, checksum);
501  break;
502 
503  case dods_grid_c:
504  default:
505  throw InternalErr(__FILE__, __LINE__, "Unsupported type");
506  }
507 }
508 
516 void print_values_as_ascii(DMR *dmr, ostream &strm)
517 {
518  Crc32 checksum;
519 
520  strm << "Dataset: " << dmr->name() << endl;
521 
522  print_values_as_ascii(dmr->root(), true /*print_name*/, strm, checksum);
523 }
524 
525 } // namespace dap_asciival
libdap
Definition: BESDapFunctionResponseCache.h:35