bes  Updated for version 3.20.5
vgroup.cc
1 // This file is part of the hdf4 data handler for the OPeNDAP data server.
2 
3 // Copyright (c) 2005 OPeNDAP, Inc.
4 // Author: James Gallagher <jgallagher@opendap.org>
5 //
6 // This is free software; you can redistribute it and/or modify it under the
7 // terms of the GNU Lesser General Public License as published by the Free
8 // Software Foundation; either version 2.1 of the License, or (at your
9 // option) any later version.
10 //
11 // This software is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 // License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public License
17 // along with this software; if not, write to the Free Software Foundation,
18 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
21 
23 // Copyright 1998, by the California Institute of Technology.
24 // ALL RIGHTS RESERVED. United States Government Sponsorship
25 // acknowledged. Any commercial use must be negotiated with the
26 // Office of Technology Transfer at the California Institute of
27 // Technology. This software may be subject to U.S. export control
28 // laws and regulations. By accepting this software, the user
29 // agrees to comply with all applicable U.S. export laws and
30 // regulations. User has the responsibility to obtain export
31 // licenses, or other export authority as may be required before
32 // exporting such information to foreign countries or providing
33 // access to foreign persons.
34 //
35 // U.S. Government Sponsorship under NASA Contract
36 // NAS7-1260 is acknowledged.
37 //
38 // Author: Todd.K.Karakashian@jpl.nasa.gov
39 // Jake.Hamby@jpl.nasa.gov
40 //
41 // $RCSfile: vgroup.cc,v $ - classes for HDF VGROUP
42 //
44 
45 #include "config_hdf.h"
46 
47 #include <mfhdf.h>
48 
49 #ifdef __POWERPC__
50 #undef isascii
51 #endif
52 
53 #include <string>
54 #include <vector>
55 #include <set>
56 #include <algorithm>
57 
58 using std::vector;
59 using std::set;
60 using std::less;
61 
62 #include <hcstream.h>
63 #include <hdfclass.h>
64 
65 #include <BESDebug.h>
66 
67 using std::endl; // Added when I removed 'using' from BESDebug.h
68 
69 static bool IsInternalVgroup(int32 fid, int32 ref);
70 
71 //
72 // hdfistream_vgroup -- protected member functions
73 //
74 
75 // initialize hdfistream_vgroup
76 void hdfistream_vgroup::_init(void)
77 {
78  _vgroup_id = _index = _attr_index = _nattrs = 0;
79  _meta = false;
80  _vgroup_refs.clear();
81  _recs.set = false;
82  return;
83 }
84 
85 void hdfistream_vgroup::_get_fileinfo(void)
86 {
87 
88  // build list ref numbers of all Vgroup's in the file
89  int32 ref = -1;
90  while ((ref = Vgetid(_file_id, ref)) != -1) {
91  if (!IsInternalVgroup(_file_id, ref))
92  _vgroup_refs.push_back(ref);
93  }
94 
95  return;
96 }
97 
98 void hdfistream_vgroup::_seek_next(void)
99 {
100  _index++;
101  if (!eos())
102  _seek(_vgroup_refs[_index]);
103  return;
104 }
105 
106 void hdfistream_vgroup::_seek(const char *name)
107 {
108  int32 ref = Vfind(_file_id, name);
109  if (ref < 0)
110  THROW(hcerr_vgroupfind);
111  else
112  _seek(ref);
113 
114  return;
115 }
116 
117 void hdfistream_vgroup::_seek(int32 ref)
118 {
119  if (_vgroup_id != 0)
120  Vdetach(_vgroup_id);
121  vector < int32 >::iterator r =
122  find(_vgroup_refs.begin(), _vgroup_refs.end(), ref);
123  if (r == _vgroup_refs.end())
124  THROW(hcerr_vgroupfind);
125  _index = r - _vgroup_refs.begin();
126  if ((_vgroup_id = Vattach(_file_id, ref, "r")) < 0) {
127  _vgroup_id = 0;
128  THROW(hcerr_vgroupopen);
129  }
130  _attr_index = 0;
131  _nattrs = Vnattrs(_vgroup_id);
132  return;
133 }
134 
135 string hdfistream_vgroup::_memberName(int32 ref)
136 {
137  char mName[hdfclass::MAXSTR];
138  int member_id;
139 
140  if ((member_id = Vattach(_file_id, ref, "r")) >= 0) {
141  if (Vgetname(member_id, mName) < 0) {
142  Vdetach(member_id);
143  THROW(hcerr_vgroupopen);
144  }
145  Vdetach(member_id);
146  return mName;
147  }
148 
149  return "";
150 }
151 
152 
153 //
154 // hdfistream_vgroup -- public member functions
155 //
156 
157 hdfistream_vgroup::hdfistream_vgroup(const string filename):hdfistream_obj
158  (filename)
159 {
160  _init();
161  if (_filename.length() != 0) // if ctor specified a null filename
162  open(_filename.c_str());
163  return;
164 }
165 
166 void hdfistream_vgroup::open(const string & filename)
167 {
168  open(filename.c_str());
169  return;
170 }
171 
172 void hdfistream_vgroup::open(const char *filename)
173 {
174  if (_file_id != 0)
175  close();
176  if ((_file_id = Hopen(filename, DFACC_RDONLY, 0)) < 0)
177  THROW(hcerr_openfile);
178  if (Vstart(_file_id) < 0)
179  THROW(hcerr_openfile);
180 
181  BESDEBUG("h4", "vgroup file opened: id=" << _file_id << endl);
182 
183  _filename = filename;
184  _get_fileinfo();
185  rewind();
186  return;
187 }
188 
189 void hdfistream_vgroup::close(void)
190 {
191  BESDEBUG("h4", "vgroup file closed: id=" << _file_id << ", this: " << this << endl);
192 
193  int status;
194 
195  if (_vgroup_id != 0) {
196  status = Vdetach(_vgroup_id);
197  BESDEBUG("h4", "vgroup Vdetach status: " << status << ", this: " << this << endl);
198  }
199 
200  if (_file_id != 0) {
201  status = Vend(_file_id);
202  BESDEBUG("h4", "vgroup vend status: " << status << ", this: " << this << endl);
203 
204  status = Hclose(_file_id);
205  BESDEBUG("h4", "vgroup HClose status: " << status << ", this: " << this << endl);
206  BESDEBUG("h4", "Error: " << HEstring((hdf_err_code_t)HEvalue(1)) << endl);
207  }
208  _vgroup_id = _file_id = _index = _attr_index = _nattrs = 0;
209  _vgroup_refs = vector < int32 > (); // clear refs
210  _recs.set = false;
211  return;
212 }
213 
214 void hdfistream_vgroup::seek(int index)
215 {
216  if (index < 0 || index >= (int) _vgroup_refs.size())
217  THROW(hcerr_range);
218  _seek(_vgroup_refs[index]);
219  _index = index;
220  return;
221 }
222 
223 void hdfistream_vgroup::seek_ref(int ref)
224 {
225  _seek(ref); // _seek() sets _index
226  return;
227 }
228 
229 void hdfistream_vgroup::seek(const string & name)
230 {
231  seek(name.c_str());
232 }
233 
234 void hdfistream_vgroup::seek(const char *name)
235 {
236  _seek(name);
237  return;
238 }
239 
240 string hdfistream_vgroup::memberName(int32 ref)
241 {
242  string mName = _memberName(ref);
243  return mName;
244 }
245 
246 
247 // read all Vgroup's in the stream
248 hdfistream_vgroup & hdfistream_vgroup::operator>>(vector < hdf_vgroup >
249  &hvv)
250 {
251  for (hdf_vgroup hv; !eos();) {
252  *this >> hv;
253  hvv.push_back(hv);
254  }
255  return *this;
256 }
257 
258 // read a Vgroup from the stream
259 hdfistream_vgroup & hdfistream_vgroup::operator>>(hdf_vgroup & hv)
260 {
261 
262  // delete any previous data in hv
263  hv.tags.clear();
264  hv.refs.clear();
265  hv.vnames.clear();
266  hv.vclass = hv.name = string();
267 
268  if (_vgroup_id == 0)
269  THROW(hcerr_invstream); // no vgroup open!
270  if (eos())
271  return *this;
272 
273  // assign Vgroup ref
274  hv.ref = _vgroup_refs[_index];
275  // retrieve Vgroup attributes
276  *this >> hv.attrs;
277  // retrieve Vgroup name, class, number of entries
278  char name[hdfclass::MAXSTR];
279  char vclass[hdfclass::MAXSTR];
280  int32 nentries;
281  if (Vinquire(_vgroup_id, &nentries, name) < 0)
282  THROW(hcerr_vgroupinfo);
283  hv.name = string(name);
284  if (Vgetclass(_vgroup_id, vclass) < 0)
285  THROW(hcerr_vgroupinfo);
286  hv.vclass = string(vclass);
287 
288  // retrieve entry tags and refs
289  int32 npairs = Vntagrefs(_vgroup_id);
290  hdfistream_vdata vdin(_filename);
291 
292  for (int i = 0; i < npairs; ++i) {
293  int32 tag, ref;
294  string vname;
295  if (Vgettagref(_vgroup_id, i, &tag, &ref) < 0)
296  THROW(hcerr_vgroupread);
297  switch (tag) {
298  case DFTAG_VH:
299  // Somehow isInternalVdata causes memory leaking because
300  // of VSattach.
301  // However, after some checking, the VSdetach is called.
302  if (!vdin.isInternalVdata(ref)) {
303  hv.tags.push_back(tag);
304  hv.refs.push_back(ref);
305  hv.vnames.push_back(memberName(ref));
306  }
307  break;
308  default:
309  hv.tags.push_back(tag);
310  hv.refs.push_back(ref);
311  hv.vnames.push_back(memberName(ref));
312  }
313  }
314  vdin.close();
315  _seek_next();
316  return *this;
317 }
318 
319 //
320 // hdf_vgroup related member functions
321 //
322 
323 bool hdf_vgroup::_ok(void) const
324 {
325 
326  // make sure there are tags stored in this vgroup
327  if (tags.size() == 0)
328  return false;
329 
330  // make sure there are refs stored in this vgroup
331  if (refs.size() == 0)
332  return false;
333 
334  return true; // passed all the tests
335 }
336 
337 bool IsInternalVgroup(int32 fid, int32 ref)
338 {
339  // block vgroups used internally
340  set < string, less < string > >reserved_names;
341  reserved_names.insert("RIATTR0.0N");
342  reserved_names.insert("RIG0.0");
343 
344  set < string, less < string > >reserved_classes;
345  reserved_classes.insert("Attr0.0");
346  reserved_classes.insert("RIATTR0.0C");
347  reserved_classes.insert("DimVal0.0");
348  reserved_classes.insert("DimVal0.1");
349  reserved_classes.insert("CDF0.0");
350  reserved_classes.insert("Var0.0");
351  reserved_classes.insert("Dim0.0");
352  reserved_classes.insert("UDim0.0");
353  reserved_classes.insert("Data0.0");
354  reserved_classes.insert("RI0.0");
355 
356  // get name, class of vgroup
357  int vid;
358  if ((vid = Vattach(fid, ref, "r")) < 0) {
359  THROW(hcerr_vgroupopen);
360  }
361 
362  char name[hdfclass::MAXSTR];
363  char vclass[hdfclass::MAXSTR];
364  if (Vgetname(vid, name) < 0) {
365  Vdetach(vid);
366  THROW(hcerr_vgroupinfo);
367  }
368  if (reserved_names.find(string(name)) != reserved_names.end()) {
369  Vdetach(vid);
370  return true;
371  }
372 
373  if (Vgetclass(vid, vclass) < 0) {
374  Vdetach(vid);
375  THROW(hcerr_vgroupinfo);
376  }
377 
378  Vdetach(vid);
379 
380  if (reserved_classes.find(string(vclass)) != reserved_classes.end())
381  return true;
382 
383  return false;
384 }
385 
386 // check to see if stream is positioned past the last attribute in the
387 // currently open Vgroup
388 bool hdfistream_vgroup::eo_attr(void) const
389 {
390  if (_filename.length() == 0) // no file open
391  THROW(hcerr_invstream);
392  if (eos() && !bos()) // if eos(), then always eo_attr()
393  return true;
394  else {
395  return (_attr_index >= _nattrs); // or positioned after last Vgroup attr?
396  }
397 }
398 
399 // Read all attributes in the stream
400 hdfistream_vgroup & hdfistream_vgroup::operator>>(vector < hdf_attr > &hav)
401 {
402 // hav = vector<hdf_attr>0; // reset vector
403  for (hdf_attr att; !eo_attr();) {
404  *this >> att;
405  hav.push_back(att);
406  }
407  return *this;
408 }
409 
410 // read an attribute from the stream
411 hdfistream_vgroup & hdfistream_vgroup::operator>>(hdf_attr & ha)
412 {
413  // delete any previous data in ha
414  ha.name = string();
415  ha.values = hdf_genvec();
416 
417  if (_filename.length() == 0) // no file open
418  THROW(hcerr_invstream);
419  if (eo_attr()) // if positioned past last attr, do nothing
420  return *this;
421 
422  char name[hdfclass::MAXSTR];
423  int32 number_type, count, size;
424  if (Vattrinfo
425  (_vgroup_id, _attr_index, name, &number_type, &count, &size) < 0)
426  THROW(hcerr_vgroupinfo);
427 
428  // allocate a temporary C array to hold data from VSgetattr()
429  char *data;
430  data = new char[count * DFKNTsize(number_type)];
431  if (data == 0)
432  THROW(hcerr_nomemory);
433 
434  // read attribute values and store them in an hdf_genvec
435  if (Vgetattr(_vgroup_id, _attr_index, data) < 0) {
436  delete[]data; // problem: clean up and throw an exception
437  THROW(hcerr_vgroupinfo);
438  }
439  // try { // try to allocate an hdf_genvec
440  if (count > 0) {
441  ha.values = hdf_genvec(number_type, data, count);
442  // }
443  // catch(...) { // problem allocating hdf_genvec: clean up and rethrow
444  // delete []data;
445  // throw;
446  // }
447  }
448  delete[]data; // deallocate temporary C array
449 
450  // increment attribute index to next attribute
451  ++_attr_index;
452  ha.name = name; // assign attribute name
453  return *this;
454 }
455