OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
get_ascii_dap4.cc
Go to the documentation of this file.
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  int end = a->dimension_size(a->dim_begin(), true) - 1;
74 
75  for (int i = 0; i < end; ++i) {
76  a->var(i)->print_val(strm, "", false /*print_decl*/);
77  strm << ", ";
78  }
79  a->var(end)->print_val(strm, "", false /*print_decl*/);
80 }
81 
93 static int print_array_row(Array *a, ostream &strm, int index, int number)
94 {
95  for (int i = 0; i < number; ++i) {
96  a->var(index++)->print_val(strm, "", false /*print_decl*/);
97  strm << ", ";
98  }
99 
100  a->var(index++)->print_val(strm, "", false /*print_decl*/);
101  return index;
102 }
103 
104 // This code implements simple modulo arithmetic. The vector shape contains
105 // This code implements simple modulo arithmetic. The vector shape contains
106 // the maximum count value for each dimension, state contains the current
107 // state. For example, if shape holds 10, 20 then when state holds 0, 20
108 // calling this method will increment state to 1, 0. For this example,
109 // calling the method with state equal to 10, 20 will reset state to 0, 0 and
110 // the return value will be false.
111 static bool increment_state(vector<int> *state, const vector<int> &shape)
112 {
113  vector < int >::reverse_iterator state_riter;
114  vector < int >::const_reverse_iterator shape_riter;
115  for (state_riter = state->rbegin(), shape_riter = shape.rbegin();
116  state_riter < state->rend(); state_riter++, shape_riter++) {
117  if (*state_riter == *shape_riter - 1) {
118  *state_riter = 0;
119  }
120  else {
121  *state_riter = *state_riter + 1;
122  return true;
123  }
124  }
125 
126  return false;
127 }
128 
129 static vector <int> get_shape_vector(Array *a, size_t n)
130 {
131  if (n < 1 || n > a->dimensions(true)) {
132  ostringstream oss;
133  oss << "Attempt to get " << n << " dimensions from " << a->name() << " which has " << a->dimensions(true) << " dimensions";
134  throw InternalErr(__FILE__, __LINE__, oss.str());
135  }
136 
137  vector <int>shape;
138  Array::Dim_iter p = a->dim_begin();
139  for (unsigned i = 0; i < n && p != a->dim_end(); ++i, ++p) {
140  shape.push_back(a->dimension_size(p, true));
141  }
142 
143  return shape;
144 }
145 
149 static int get_nth_dim_size(Array *a, size_t n)
150 {
151  if (n > a->dimensions(true) - 1) {
152  ostringstream oss;
153  oss << "Attempt to get dimension " << n << " from " << a->name() << " which has " << a->dimensions(true) << " dimensions";
154  throw InternalErr(__FILE__, __LINE__, oss.str());
155  }
156 
157  return a->dimension_size(a->dim_begin() + n, true);
158 }
159 
160 static void print_ndim_array(Array *a, ostream &strm, bool /*print_name */ )
161 {
162 
163  int dims = a->dimensions(true);
164  if (dims <= 1)
165  throw InternalErr(__FILE__, __LINE__, "Dimension count is <= 1 while printing multidimensional array.");
166 
167  // shape holds the maximum index value of all but the last dimension of
168  // the array (not the size; each value is one less than the size).
169  vector<int> shape = get_shape_vector(a, dims - 1);
170  int rightmost_dim_size = get_nth_dim_size(a, dims - 1);
171 
172  // state holds the indexes of the current row being printed. For an N-dim
173  // array, there are N-1 dims that are iterated over when printing (the
174  // Nth dim is not printed explicitly. Instead it's the number of values
175  // on the row.
176  vector<int> state(dims - 1, 0);
177 
178  bool more_indices;
179  int index = 0;
180  do {
181  // Print indices for all dimensions except the last one.
182  strm << a->FQN();
183 
184  for (int i = 0; i < dims - 1; ++i) {
185  strm << "[" << state[i] << "]" ;
186  }
187  strm << ", " ;
188 
189  index = print_array_row(a, strm, index, rightmost_dim_size - 1);
190  more_indices = increment_state(&state, shape);
191  if (more_indices)
192  strm << endl ;
193 
194  } while (more_indices);
195 }
196 
197 static int get_index(Array *a, vector<int> indices)
198 {
199  if (indices.size() != a->dimensions(true))
200  throw InternalErr(__FILE__, __LINE__, "Index vector is the wrong size!");
201 
202  // suppose shape is [3][4][5][6] for x,y,z,t. The index is
203  // t + z(6) + y(5 * 6) + x(4 * 5 *6).
204  // Assume that indices[0] holds x, indices[1] holds y, ...
205 
206  vector < int >shape = get_shape_vector(a, indices.size());
207 
208  // We want to work from the rightmost index to the left
209  reverse(indices.begin(), indices.end());
210  reverse(shape.begin(), shape.end());
211 
212  vector<int>::iterator indices_iter = indices.begin();
213  vector<int>::iterator shape_iter = shape.begin();
214 
215  int index = *indices_iter++; // in the ex. above, this adds `t'
216  int multiplier = 1;
217  while (indices_iter != indices.end()) {
218  multiplier *= *shape_iter++;
219  index += multiplier * *indices_iter++;
220  }
221 
222  return index;
223 }
224 
234 static void print_complex_array(Array *a, ostream &strm, bool print_name, Crc32 &checksum)
235 {
236  int dims = a->dimensions(true);
237  if (dims < 1)
238  throw InternalErr(__FILE__, __LINE__, "Dimension count is <= 1 while printing multidimensional array.");
239 
240  // shape holds the maximum index value of all but the last dimension of
241  // the array (not the size; each value is one less that the size).
242  vector<int> shape = get_shape_vector(a, dims);
243 
244  vector<int> state(dims, 0);
245 
246  bool more_indices;
247  do {
248  // Print indices for all dimensions except the last one.
249  strm << a->FQN();
250 
251  for (int i = 0; i < dims; ++i) {
252  strm << "[" << state[i] << "]" ;
253  }
254  strm << endl;
255 
256  print_values_as_ascii(a->var(get_index(a, state)), print_name, strm, checksum);
257 
258  more_indices = increment_state(&state, shape);
259 
260  if (more_indices)
261  strm << endl;
262 
263  } while (more_indices);
264 }
265 
275 static void print_values_as_ascii(Array *a, bool print_name, ostream &strm, Crc32 &checksum)
276 {
277  if (a->var()->is_simple_type()) {
278  if (a->dimensions(true) > 1) {
279  print_ndim_array(a, strm, print_name);
280  }
281  else {
282  print_array_vector(a, strm, print_name);
283  }
284  }
285  else {
286  print_complex_array(a, strm, print_name, checksum);
287  }
288 }
289 
290 static void print_structure_header(Structure *s, ostream &strm)
291 {
292  Constructor::Vars_iter p = s->var_begin(), e = s->var_end();
293  while (p != e) {
294  if ((*p)->is_simple_type())
295  strm << (*p)->FQN();
296  else if ((*p)->type() == dods_structure_c)
297  print_structure_header(static_cast<Structure*>(*p), strm);
298  else if ((*p)->type() == dods_sequence_c)
299  print_sequence_header(static_cast<D4Sequence*>(*p), strm);
300  else
301  throw InternalErr(__FILE__, __LINE__, "Unknown or unsupported type.");
302  if (++p != e) strm << ", ";
303  }
304 }
305 
306 static void print_structure_ascii(Structure *s, ostream &strm, bool print_name, Crc32 &checksum)
307 {
308  if (s->is_linear()) {
309  if (print_name) {
310  print_structure_header(s, strm);
311  strm << endl;
312  }
313 
314  Constructor::Vars_iter p = s->var_begin(), e = s->var_end();
315  while (p !=e) {
316  // bug: print_name should be false, but will be true because it's not a param here
317  if ((*p)->send_p()) print_values_as_ascii(*p, false /*print_name*/, strm, checksum);
318 
319  if (++p != e) strm << ", ";
320  }
321  }
322  else {
323  for (Constructor::Vars_iter p = s->var_begin(), e = s->var_end(); p != e; ++p) {
324  if ((*p)->send_p()) {
325  print_values_as_ascii(*p, print_name, strm, checksum);
326  // This line outputs an extra endl when print_ascii is called for
327  // nested structures because an endl is written for each member
328  // and then once for the structure itself. 9/14/2001 jhrg
329  strm << endl;
330  }
331  }
332  }
333 }
334 
335 static void print_values_as_ascii(Structure *v, bool print_name, ostream &strm, Crc32 &checksum)
336 {
337  print_structure_ascii(v, strm, print_name, checksum);
338 }
339 
340 static void print_one_row(D4Sequence *seq, ostream &strm, Crc32 &checksum, int row)
341 {
342  int elements = seq->element_count();
343  int j = 0;
344  BaseType *btp = 0;
345  bool first_val = true;
346 
347  while (j < elements) {
348  btp = seq->var_value(row, j++);
349  if (btp) { // data
350  if (!first_val)
351  strm << ", ";
352  first_val = false;
353  if (btp->type() == dods_sequence_c)
354  print_val_by_rows(static_cast<D4Sequence*>(btp), strm, checksum);
355  else
356  print_values_as_ascii(btp, false, strm, checksum);
357  }
358  }
359 }
360 
361 static void print_val_by_rows(D4Sequence *seq, ostream &strm, Crc32 &checksum)
362 {
363  if (seq->length() != 0) {
364  int rows = seq->length() /*- 1*/; // -1 because the last row is treated specially
365  for (int i = 0; i < rows; ++i) {
366  print_one_row(seq, strm, checksum, i);
367  strm << endl;
368  }
369  }
370 }
371 
372 static void print_sequence_header(D4Sequence *s, ostream &strm)
373 {
374  Constructor::Vars_iter p = s->var_begin(), e = s->var_end();
375  while (p != e) {
376  if ((*p)->is_simple_type())
377  strm << (*p)->FQN();
378  else if ((*p)->type() == dods_structure_c)
379  print_structure_header(static_cast<Structure*>(*p), strm);
380  else if ((*p)->type() == dods_sequence_c)
381  print_sequence_header(static_cast<D4Sequence*>(*p), strm);
382  else
383  throw InternalErr(__FILE__, __LINE__, "Unknown or unsupported type.");
384  if (++p != e) strm << ", ";
385  }
386 }
387 
388 
389 static void print_values_as_ascii(D4Sequence *v, bool print_name, ostream &strm, Crc32 &checksum)
390 {
391  if (print_name) {
392  print_sequence_header(v, strm);
393  strm << endl;
394  }
395 
396  print_val_by_rows(v, strm, checksum);
397 }
398 
399 static void print_values_as_ascii(D4Opaque *v, bool print_name, ostream &strm, Crc32 &/*checksum*/)
400 {
401  if (print_name)
402  strm << v->FQN() << ", ";
403  strm << v->value().size() << " bytes" << endl;
404 }
405 
406 static void print_values_as_ascii(D4Group *group, bool print_name, ostream &strm, Crc32 &checksum)
407 {
408  for (D4Group::groupsIter g = group->grp_begin(), e = group->grp_end(); g != e; ++g)
409  print_values_as_ascii(*g, print_name, strm, checksum);
410 
411  // Specialize how the top-level variables in any Group are sent; include
412  // a checksum for them. A subset operation might make an interior set of
413  // variables, but the parent structure will still be present and the checksum
414  // will be computed for that structure. In other words, DAP4 does not try
415  // to sort out which variables are the 'real' top-level variables and instead
416  // simply computes the CRC for whatever appears as a variable in the root
417  // group.
418  for (Constructor::Vars_iter i = group->var_begin(), e = group->var_end(); i != e; ++i) {
419  // Only send the stuff in the current subset.
420  if ((*i)->send_p()) {
421  checksum.Reset();
422 
423  (*i)->intern_data(checksum);
424 
425  // print the data
426  print_values_as_ascii((*i), print_name, strm, checksum);
427  strm << endl;
428 
429  // Print the checksum: name():DAP4_Checksum_CRC32, checksum value
430  ostringstream oss;
431  oss.setf(ios::hex, ios::basefield);
432  oss << setfill('0') << setw(8) << checksum.GetCrc32();
433  strm << (*i)->FQN() << ":DAP4_Checksum_CRC32, " << oss.str() << endl;
434  }
435  }
436 }
437 
447 static void print_values_as_ascii(BaseType *btp, bool print_name, ostream &strm, Crc32 &checksum)
448 {
449  switch (btp->type()) {
450  case dods_null_c:
451  throw InternalErr(__FILE__, __LINE__, "Unknown type");
452 
453  case dods_byte_c:
454  case dods_char_c:
455 
456  case dods_int8_c:
457  case dods_uint8_c:
458 
459  case dods_int16_c:
460  case dods_uint16_c:
461  case dods_int32_c:
462  case dods_uint32_c:
463 
464  case dods_int64_c:
465  case dods_uint64_c:
466 
467  case dods_float32_c:
468  case dods_float64_c:
469  case dods_str_c:
470  case dods_url_c:
471  case dods_enum_c:
472  if (print_name) strm << btp->FQN() << ", ";
473  btp->print_val(strm, "" /*leading space*/, false /*print dap2 decl*/);
474  break;
475 
476  case dods_opaque_c:
477  print_values_as_ascii(static_cast<D4Opaque*>(btp), print_name, strm, checksum);
478  break;
479 
480  case dods_array_c:
481  print_values_as_ascii(static_cast<Array*>(btp), print_name, strm, checksum);
482  break;
483 
484  case dods_structure_c:
485  print_values_as_ascii(static_cast<Structure*>(btp), print_name, strm, checksum);
486  break;
487 
488  case dods_sequence_c:
489  print_values_as_ascii(static_cast<D4Sequence*>(btp), print_name, strm, checksum);
490  break;
491 
492  case dods_group_c:
493  print_values_as_ascii(static_cast<D4Group*>(btp), print_name, strm, checksum);
494  break;
495 
496  case dods_grid_c:
497  default:
498  throw InternalErr(__FILE__, __LINE__, "Unsupported type");
499  }
500 }
501 
509 void print_values_as_ascii(DMR *dmr, ostream &strm)
510 {
511  Crc32 checksum;
512 
513  strm << "Dataset: " << dmr->name() << endl;
514 
515  print_values_as_ascii(dmr->root(), true /*print_name*/, strm, checksum);
516 }
517 
518 } // namespace dap_asciival
STL namespace.
static class NCMLUtil overview