OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
hc2dap.cc
Go to the documentation of this file.
1 // This file is part of the hdf4 data handler for the OPeNDAP data server.
9 
10 // Copyright (c) 2008-2012 The HDF Group
11 // Author: Hyo-Kyung Lee <hyoklee@hdfgroup.org>
12 //
13 // Copyright (c) 2005 OPeNDAP, Inc.
14 // Author: James Gallagher <jgallagher@opendap.org>
15 //
16 // This is free software; you can redistribute it and/or modify it under the
17 // terms of the GNU Lesser General Public License as published by the Free
18 // Software Foundation; either version 2.1 of the License, or (at your
19 // option) any later version.
20 //
21 // This software is distributed in the hope that it will be useful, but
22 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24 // License for more details.
25 //
26 // You should have received a copy of the GNU Lesser General Public License
27 // along with this software; if not, write to the Free Software Foundation,
28 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 //
30 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
31 
33 // Copyright 1996, by the California Institute of Technology.
34 // ALL RIGHTS RESERVED. United States Government Sponsorship
35 // acknowledged. Any commercial use must be negotiated with the
36 // Office of Technology Transfer at the California Institute of
37 // Technology. This software may be subject to U.S. export control
38 // laws and regulations. By accepting this software, the user
39 // agrees to comply with all applicable U.S. export laws and
40 // regulations. User has the responsibility to obtain export
41 // licenses, or other export authority as may be required before
42 // exporting such information to foreign countries or providing
43 // access to foreign persons.
44 
45 // Author: Todd Karakashian, NASA/Jet Propulsion Laboratory
46 // Todd.K.Karakashian@jpl.nasa.gov
47 //
49 
50 
51 #include "config_hdf.h"
52 
53 // STL includes
54 #include <fstream>
55 #include <sstream>
56 #include <string>
57 #include <vector>
58 #include <algorithm>
59 #include <iostream>
60 #include <BESDebug.h>
61 #include <debug.h>
62 
63 
64 using namespace std;
65 // HDF and HDFClass includes
66 // Include this on linux to suppres an annoying warning about multiple
67 // definitions of MIN and MAX.
68 #ifdef HAVE_SYS_PARAM_H
69 #include <sys/param.h>
70 #endif
71 #include <mfhdf.h>
72 #include <hdfclass.h>
73 #include <hcstream.h>
74 
75 // DODS/HDF includes
76 #include "escaping.h"
77 #include "HDFInt32.h"
78 #include "HDFInt16.h"
79 #include "HDFUInt32.h"
80 #include "HDFUInt16.h"
81 #include "HDFFloat64.h"
82 #include "HDFFloat32.h"
83 #include "HDFByte.h"
84 #include "HDFStr.h"
85 #include "HDFArray.h"
86 #include "HDFGrid.h"
87 #include "HDFSequence.h"
88 #include "HDFStructure.h"
89 #include "hdfutil.h"
90 #include "dhdferr.h"
91 #include "hdf-maps.h"
92 #include "debug.h"
93 
94 
95 // Undefine the following to send signed bytes using unsigned bytes. 1/13/98
96 // jhrg.
97 #define SIGNED_BYTE_TO_INT32 1
98 
99 BaseType *NewDAPVar(const string &varname,
100  const string &dataset,
101  int32 hdf_type);
102 void LoadStructureFromField(HDFStructure * stru, hdf_field & f, int row);
103 
104 // STL predicate comparing equality of hdf_field objects based on their names
105 class fieldeq {
106 public:
107  fieldeq(const string & s) {
108  _val = s;
109  }
110 
111  bool operator() (const hdf_field & f) const {
112  return (f.name == _val);
113  }
114 
115 private:
116  string _val;
117 };
118 
119 // Create a DAP HDFSequence from an hdf_vdata.
120 HDFSequence *NewSequenceFromVdata(const hdf_vdata &vd, const string &dataset)
121 {
122  // check to make sure hdf_vdata object is set up properly
123  // Vdata must have a name
124  if (!vd || vd.fields.size() == 0 || vd.name.empty())
125  return 0;
126 
127  // construct HDFSequence
128  HDFSequence *seq = new HDFSequence(vd.name, dataset);
129 
130  // step through each field and create a variable in the DAP Sequence
131  for (int i = 0; i < (int) vd.fields.size(); ++i) {
132  if (!vd.fields[i] || vd.fields[i].vals.size() < 1 ||
133  vd.fields[i].name.empty()) {
134  delete seq; // problem with the field
135  return 0;
136  }
137  HDFStructure *st = 0;
138  try {
139  st = new HDFStructure(vd.fields[i].name, dataset);
140 
141  // for each subfield add the subfield to st
142  if (vd.fields[i].vals[0].number_type() == DFNT_CHAR8
143  || vd.fields[i].vals[0].number_type() == DFNT_UCHAR8) {
144 
145  // collapse char subfields into one string
146  string subname = vd.fields[i].name + "__0";
147  BaseType *bt = new HDFStr(subname, dataset);
148  st->add_var(bt); // *st now manages *bt
149  delete bt;
150  }
151  else {
152  // create a DODS variable for each subfield
153  for (int j = 0; j < (int) vd.fields[i].vals.size(); ++j) {
154  ostringstream strm;
155  strm << vd.fields[i].name << "__" << j;
156  BaseType *bt =
157  NewDAPVar(strm.str(), dataset,
158  vd.fields[i].vals[j].number_type());
159  st->add_var(bt); // *st now manages *bt
160  delete bt;
161  }
162  }
163  seq->add_var(st); // *seq now manages *st
164  delete st;
165  }
166  catch (...) {
167  delete seq;
168  delete st;
169  throw;
170  }
171  }
172 
173  return seq;
174 }
175 
176 // Create a DAP HDFStructure from an hdf_vgroup.
178  sds_map &sdmap, vd_map &vdmap,
179  gr_map &grmap, const string &dataset)
180 {
181  // check to make sure hdf_vgroup object is set up properly
182  if (vg.name.length() == 0) // Vgroup must have a name
183  return 0;
184  if (!vg) // Vgroup must have some tagrefs
185  return 0;
186 
187  // construct HDFStructure
188  HDFStructure *str = new HDFStructure(vg.name, dataset);
189  bool nonempty = false;
190  BaseType *bt = 0;
191  try {
192  // step through each tagref and copy its contents to DAP
193  for (int i = 0; i < (int) vg.tags.size(); ++i) {
194  int32 tag = vg.tags[i];
195  int32 ref = vg.refs[i];
196 
197  switch (tag) {
198  case DFTAG_VH:
199  bt = NewSequenceFromVdata(vdmap[ref].vdata, dataset);
200  break;
201  case DFTAG_NDG:
202  if (sdmap[ref].sds.has_scale()) {
203  bt = NewGridFromSDS(sdmap[ref].sds, dataset);
204  } else {
205  bt = NewArrayFromSDS(sdmap[ref].sds, dataset);
206  }
207  break;
208  case DFTAG_VG:
209  // GR's are also stored as Vgroups
210  if (grmap.find(ref) != grmap.end()){
211  bt = NewArrayFromGR(grmap[ref].gri, dataset);
212  }
213  else
214  bt = NewStructureFromVgroup(vgmap[ref].vgroup, vgmap,
215  sdmap, vdmap, grmap, dataset);
216  break;
217  default:
218  break;
219  }
220  if (bt) {
221  str->add_var(bt); // *st now manages *bt
222  delete bt;
223  nonempty = true;
224  }
225  }
226  }
227  catch(...) {
228  delete str;
229  delete bt;
230  throw;
231  }
232 
233  if (nonempty) {
234  return str;
235  } else {
236  delete str;
237  return 0;
238  }
239 }
240 
241 // Create a DAP HDFArray out of the primary array in an hdf_sds
242 HDFArray *NewArrayFromSDS(const hdf_sds & sds, const string &dataset)
243 {
244  if (sds.name.length() == 0) // SDS must have a name
245  return 0;
246  if (sds.dims.size() == 0) // SDS must have rank > 0
247  return 0;
248 
249  // construct HDFArray, assign data type
250  BaseType *bt = NewDAPVar(sds.name, dataset, sds.data.number_type());
251  if (bt == 0) { // something is not right with SDS number type?
252  return 0;
253  }
254  try {
255  HDFArray *ar = 0;
256  ar = new HDFArray(sds.name,dataset,bt);
257  delete bt;
258 
259  // add dimension info to HDFArray
260  for (int i = 0; i < (int) sds.dims.size(); ++i)
261  ar->append_dim(sds.dims[i].count, sds.dims[i].name);
262 
263  return ar;
264  }
265  catch (...) {
266  delete bt;
267  throw;
268  }
269 }
270 
271 // Create a DAP HDFArray out of a general raster
272 HDFArray *NewArrayFromGR(const hdf_gri & gr, const string &dataset)
273 {
274  if (gr.name.length() == 0) // GR must have a name
275  return 0;
276 
277  // construct HDFArray, assign data type
278  BaseType *bt = NewDAPVar(gr.name, dataset, gr.image.number_type());
279  if (bt == 0) { // something is not right with GR number type?
280  return 0;
281  }
282 
283  try {
284  HDFArray *ar = 0;
285  ar = new HDFArray(gr.name, dataset, bt);
286 
287  // Array duplicates the base type passed, so delete here
288  delete bt;
289 
290  // add dimension info to HDFArray
291  if (gr.num_comp > 1)
292  ar->append_dim(gr.num_comp, gr.name + "__comps");
293  ar->append_dim(gr.dims[1], gr.name + "__Y");
294  ar->append_dim(gr.dims[0], gr.name + "__X");
295  return ar;
296  }
297  catch (...) {
298  delete bt;
299  throw;
300  }
301 }
302 
303 // Create a DAP HDFGrid out of the primary array and dim scale in an hdf_sds
304 HDFGrid *NewGridFromSDS(const hdf_sds & sds, const string &dataset)
305 {
306  BESDEBUG("h4", "NewGridFromSDS" << endl);
307  if (!sds.has_scale()) // we need a dim scale to make a Grid
308  return 0;
309 
310  // Create the HDFGrid and the primary array. Add the primary array to
311  // the HDFGrid.
312  HDFArray *ar = NewArrayFromSDS(sds, dataset);
313  if (ar == 0)
314  return 0;
315 
316  HDFGrid *gr = 0;
317  HDFArray *dmar = 0;
318  BaseType *dsbt = 0;
319  try {
320  gr = new HDFGrid(sds.name, dataset);
321  gr->add_var(ar, array); // note: gr now manages ar
322  delete ar;
323 
324  // create dimension scale HDFArrays (i.e., maps) and
325  // add them to the HDFGrid
326  string mapname;
327  for (int i = 0; i < (int) sds.dims.size(); ++i) {
328  if (sds.dims[i].name.length() == 0) { // the dim must be named
329  delete gr;
330  return 0;
331  }
332  mapname = sds.dims[i].name;
333  if ((dsbt = NewDAPVar(mapname, dataset,
334  sds.dims[i].scale.number_type())) == 0) {
335  delete gr; // note: ~HDFGrid() cleans up the attached ar
336  return 0;
337  }
338  dmar = new HDFArray(mapname, dataset, dsbt);
339  delete dsbt;
340  dmar->append_dim(sds.dims[i].count); // set dimension size
341  gr->add_var(dmar, maps); // add dimension map to grid;
342  delete dmar;
343  }
344  return gr;
345  }
346  catch (...) {
347  delete dmar;
348  delete dsbt;
349  delete gr;
350  delete ar;
351  throw;
352  }
353 }
354 
355 // Return a ptr to DAP atomic data object corresponding to an HDF Type, or
356 // return 0 if the HDF Type is invalid or not supported.
357 BaseType *NewDAPVar(const string &varname,
358  const string &dataset,
359  int32 hdf_type)
360 {
361  switch (hdf_type) {
362  case DFNT_FLOAT32:
363  return new HDFFloat32(varname, dataset);
364 
365  case DFNT_FLOAT64:
366  return new HDFFloat64(varname, dataset);
367 
368  case DFNT_INT16:
369  return new HDFInt16(varname, dataset);
370 
371 #ifdef SIGNED_BYTE_TO_INT32
372  case DFNT_INT8:
373 #endif
374  case DFNT_INT32:
375  return new HDFInt32(varname, dataset);
376 
377  case DFNT_UINT16:
378  return new HDFUInt16(varname, dataset);
379 
380  case DFNT_UINT32:
381  return new HDFUInt32(varname, dataset);
382 
383  // INT8 and UINT8 *should* be grouped under Int32 and UInt32, but
384  // that breaks too many programs. jhrg 12/30/97
385 #ifndef SIGNED_BYTE_TO_INT32
386  case DFNT_INT8:
387 #endif
388  case DFNT_UINT8:
389  case DFNT_UCHAR8:
390  case DFNT_CHAR8:
391  return new HDFByte(varname, dataset);
392 
393  default:
394  return 0;
395  }
396 }
397 
398 // Return the DAP type name that corresponds to an HDF data type
399 string DAPTypeName(int32 hdf_type)
400 {
401  switch (hdf_type) {
402  case DFNT_FLOAT32:
403  return string("Float32");
404 
405  case DFNT_FLOAT64:
406  return string("Float64");
407 
408  case DFNT_INT16:
409  return string("Int16");
410 
411 #ifdef SIGNED_BYTE_TO_INT32
412  case DFNT_INT8:
413 #endif
414  case DFNT_INT32:
415  return string("Int32");
416 
417  case DFNT_UINT16:
418  return string("UInt16");
419 
420  case DFNT_UINT32:
421  return string("UInt32");
422 
423  // See the note above about INT8 and UINT8. jhrg 12/30/97.
424 #ifndef SIGNED_BYTE_TO_INT32
425  case DFNT_INT8:
426 #endif
427  case DFNT_UINT8:
428  return string("Byte");
429 
430  case DFNT_CHAR8:
431  case DFNT_UCHAR8:
432  // note: DFNT_CHAR8 is Byte in DDS but String in DAS
433  return string("String");
434 
435  default:
436  return string("");
437  }
438 }
439 
440 // load an HDFArray from an SDS
441 void LoadArrayFromSDS(HDFArray * ar, const hdf_sds & sds)
442 {
443 #ifdef SIGNED_BYTE_TO_INT32
444  switch (sds.data.number_type()) {
445  case DFNT_INT8:{
446  char *data = static_cast < char *>(ExportDataForDODS(sds.data));
447  ar->val2buf(data);
448  delete[]data;
449  break;
450  }
451  default:
452  ar->val2buf(const_cast < char *>(sds.data.data()));
453  }
454 #else
455  ar->val2buf(const_cast < char *>(sds.data.data()));
456 #endif
457  return;
458 }
459 
460 // load an HDFArray from a GR image
461 void LoadArrayFromGR(HDFArray * ar, const hdf_gri & gr)
462 {
463 #ifdef SIGNED_BYTE_TO_INT32
464  switch (gr.image.number_type()) {
465  case DFNT_INT8:{
466  char *data = static_cast < char *>(ExportDataForDODS(gr.image));
467  ar->val2buf(data);
468  delete[]data;
469  break;
470  }
471 
472  default:
473  ar->val2buf(const_cast < char *>(gr.image.data()));
474  }
475 #else
476  ar->val2buf(const_cast < char *>(gr.image.data()));
477 #endif
478  return;
479 }
480 
481 // load an HDFGrid from an SDS
482 // I modified Todd's code so that only the parts of a Grid that are marked as
483 // to be sent will be read. 1/29/2002 jhrg
484 void LoadGridFromSDS(HDFGrid * gr, const hdf_sds & sds)
485 {
486 
487  // load data into primary array
488  HDFArray & primary_array = static_cast < HDFArray & >(*gr->array_var());
489  if (primary_array.send_p()) {
490  LoadArrayFromSDS(&primary_array, sds);
491  primary_array.set_read_p(true);
492  }
493  // load data into maps
494  if (primary_array.dimensions() != sds.dims.size())
495  THROW(dhdferr_consist); // # of dims of SDS and HDFGrid should agree!
496 
497  Grid::Map_iter p = gr->map_begin();
498  for (unsigned int i = 0;
499  i < sds.dims.size() && p != gr->map_end(); ++i, ++p) {
500  if ((*p)->send_p()) {
501 #ifdef SIGNED_BYTE_TO_INT32
502  switch (sds.dims[i].scale.number_type()) {
503  case DFNT_INT8:{
504  char *data = static_cast < char *>(ExportDataForDODS(sds.dims[i].scale));
505  (*p)->val2buf(data);
506  delete[]data;
507  break;
508  }
509  default:
510  (*p)->val2buf(const_cast < char *>
511  (sds.dims[i].scale.data()));
512  }
513 #else
514  (*p)->val2buf(const_cast < char *>(sds.dims[i].scale.data()));
515 #endif
516  (*p)->set_read_p(true);
517  }
518  }
519  return;
520 }
521 
522 // load an HDFSequence from a row of an hdf_vdata
523 void LoadSequenceFromVdata(HDFSequence * seq, hdf_vdata & vd, int row)
524 {
525  Constructor::Vars_iter p;
526  for (p = seq->var_begin(); p != seq->var_end(); ++p) {
527  HDFStructure & stru = static_cast < HDFStructure & >(**p);
528 
529  // find corresponding field in vd
530  vector < hdf_field >::iterator vf =
531  find_if(vd.fields.begin(), vd.fields.end(),
532  fieldeq(stru.name()));
533  if (vf == vd.fields.end())
535 
536  // for each field component of field, extract the proper data element
537  // for the current row being requested and load into the Structure
538  // variable
539  LoadStructureFromField(&stru, *vf, row);
540  stru.set_read_p(true);
541  }
542 }
543 
544 // Load an HDFStructure with the components of a row of an hdf_field. If the
545 // field is made of char8 components, collapse these into one String component
547 {
548 
549  if (row < 0 || f.vals.size() <= 0 || row > (int) f.vals[0].size())
551 
552  BaseType *firstp = *stru->var_begin();
553  if (firstp->type() == dods_str_c) {
554  // If the Structure contains a String, then that is all it will
555  // contain. In that case, concatenate the different char8
556  // components of the field and load the DODS String with the value.
557  string str = "";
558  for (unsigned int i = 0; i < f.vals.size(); ++i) {
559  //DBG(cerr << i << ": " << f.vals[i].elt_char8(row) << endl);
560  str += f.vals[i].elt_char8(row);
561  }
562 
563  firstp->val2buf(static_cast < void *>(&str)); // data);
564  firstp->set_read_p(true);
565  } else {
566  // for each component of the field, load the corresponding component
567  // of the DODS Structure.
568  int i = 0;
569  Constructor::Vars_iter q;
570  for (q = stru->var_begin(); q != stru->var_end(); ++q, ++i) {
571  char *val = static_cast <char *>(ExportDataForDODS(f.vals[i], row));
572  (*q)->val2buf(val);
573 #if 0
574  delete[] val;
575 #endif
576  delete val;
577  (*q)->set_read_p(true);
578  }
579 
580  }
581  return;
582 }
583 
584 // Load an HDFStructure with the contents of a vgroup.
586  const string & hdf_file)
587 {
588  int i = 0;
589  int err = 0;
590  Constructor::Vars_iter q;
591  for (q = str->var_begin(); err == 0 && q != str->var_end(); ++q, ++i) {
592  BaseType *p = *q;
593  BESDEBUG("h4", "Reading within LoadStructureFromVgroup: " << p->name()
594  << ", send_p: " << p->send_p() << ", vg.names[" << i << "]: "
595  << vg.vnames[i] << endl);
596  if (p && p->send_p() && p->name() == vg.vnames[i]) {
597  (dynamic_cast < ReadTagRef & >(*p)).read_tagref(vg.tags[i],
598  vg.refs[i],
599  err);
600  }
601  }
602 }
int32 num_comp
Definition: hdfclass.h:250
HDFArray * NewArrayFromGR(const hdf_gri &gr, const string &dataset)
Definition: hc2dap.cc:272
hdf_genvec image
Definition: hdfclass.h:252
bool has_scale(void) const
Definition: sds.cc:760
vector< hdf_dim > dims
Definition: hdfclass.h:186
map< int32, vd_info, less< int32 > > vd_map
Definition: hdf-maps.h:66
HDFGrid * NewGridFromSDS(const hdf_sds &sds, const string &dataset)
Definition: hc2dap.cc:304
const char * data(void) const
Definition: hdfclass.h:86
vector< hdf_genvec > vals
Definition: hdfclass.h:199
STL namespace.
HDFSequence * NewSequenceFromVdata(const hdf_vdata &vd, const string &dataset)
Definition: hc2dap.cc:120
void LoadSequenceFromVdata(HDFSequence *seq, hdf_vdata &vd, int row)
Definition: hc2dap.cc:523
vector< hdf_field > fields
Definition: hdfclass.h:211
string name
Definition: hdfclass.h:185
string DAPTypeName(int32 hdf_type)
Definition: hc2dap.cc:399
map< int32, gr_info, less< int32 > > gr_map
Definition: hdf-maps.h:67
string name
Definition: hdfclass.h:246
void LoadArrayFromSDS(HDFArray *ar, const hdf_sds &sds)
Definition: hc2dap.cc:441
string name
Definition: hdfclass.h:198
int32 number_type(void) const
Definition: hdfclass.h:82
hdf_genvec data
Definition: hdfclass.h:187
void LoadStructureFromField(HDFStructure *stru, hdf_field &f, int row)
Definition: hc2dap.cc:546
HDFArray * NewArrayFromSDS(const hdf_sds &sds, const string &dataset)
Definition: hc2dap.cc:242
void LoadGridFromSDS(HDFGrid *gr, const hdf_sds &sds)
Definition: hc2dap.cc:484
void LoadArrayFromGR(HDFArray *ar, const hdf_gri &gr)
Definition: hc2dap.cc:461
vector< int32 > tags
Definition: hdfclass.h:225
virtual void set_read_p(bool state)
Definition: HDFStructure.cc:74
vector< int32 > refs
Definition: hdfclass.h:226
void * ExportDataForDODS(const hdf_genvec &v)
Definition: hdfutil.cc:50
#define THROW(x)
Definition: dhdferr.h:51
vector< string > vnames
Definition: hdfclass.h:227
HDFStructure * NewStructureFromVgroup(const hdf_vgroup &vg, vg_map &vgmap, sds_map &sdmap, vd_map &vdmap, gr_map &grmap, const string &dataset)
Definition: hc2dap.cc:177
string name
Definition: hdfclass.h:223
string name
Definition: hdfclass.h:209
void LoadStructureFromVgroup(HDFStructure *str, const hdf_vgroup &vg, const string &hdf_file)
Definition: hc2dap.cc:585
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
int32 dims[2]
Definition: hdfclass.h:249
map< int32, sds_info, less< int32 > > sds_map
Definition: hdf-maps.h:65
BaseType * NewDAPVar(const string &varname, const string &dataset, int32 hdf_type)
Definition: hc2dap.cc:357
map< int32, vg_info, less< int32 > > vg_map
Definition: hdf-maps.h:68
Definition: HDFStr.h:52