bes Updated for version 3.20.13
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
58using std::vector;
59using std::set;
60using std::less;
61
62#include <hcstream.h>
63#include <hdfclass.h>
64
65#include <BESDebug.h>
66
67using std::endl; // Added when I removed 'using' from BESDebug.h
68
69static bool IsInternalVgroup(int32 fid, int32 ref);
70static bool IsInternalVdata(int32 fid,int32 ref);
71
72//
73// hdfistream_vgroup -- protected member functions
74//
75
76// initialize hdfistream_vgroup
77void hdfistream_vgroup::_init(void)
78{
79 _vgroup_id = _index = _attr_index = _nattrs = 0;
80 _meta = false;
81 _vgroup_refs.clear();
82 _recs.set = false;
83 return;
84}
85
86void hdfistream_vgroup::_get_fileinfo(void)
87{
88
89 // build list ref numbers of all Vgroup's in the file
90 int32 ref = -1;
91 while ((ref = Vgetid(_file_id, ref)) != -1) {
92 if (!IsInternalVgroup(_file_id, ref))
93 _vgroup_refs.push_back(ref);
94 }
95
96 return;
97}
98
99void hdfistream_vgroup::_seek_next(void)
100{
101 _index++;
102 if (!eos())
103 _seek(_vgroup_refs[_index]);
104 return;
105}
106
107void hdfistream_vgroup::_seek(const char *name)
108{
109 int32 ref = Vfind(_file_id, name);
110 if (ref < 0)
111 THROW(hcerr_vgroupfind);
112 else
113 _seek(ref);
114
115 return;
116}
117
118void hdfistream_vgroup::_seek(int32 ref)
119{
120 if (_vgroup_id != 0)
121 Vdetach(_vgroup_id);
122 vector < int32 >::iterator r =
123 find(_vgroup_refs.begin(), _vgroup_refs.end(), ref);
124 if (r == _vgroup_refs.end())
125 THROW(hcerr_vgroupfind);
126 _index = r - _vgroup_refs.begin();
127 if ((_vgroup_id = Vattach(_file_id, ref, "r")) < 0) {
128 _vgroup_id = 0;
129 THROW(hcerr_vgroupopen);
130 }
131 _attr_index = 0;
132 _nattrs = Vnattrs(_vgroup_id);
133 return;
134}
135
136string hdfistream_vgroup::_memberName(int32 ref)
137{
138 char mName[hdfclass::MAXSTR];
139 int member_id;
140
141 if ((member_id = Vattach(_file_id, ref, "r")) >= 0) {
142 if (Vgetname(member_id, mName) < 0) {
143 Vdetach(member_id);
144 THROW(hcerr_vgroupopen);
145 }
146 Vdetach(member_id);
147 return mName;
148 }
149
150 return "";
151}
152
153
154//
155// hdfistream_vgroup -- public member functions
156//
157
158hdfistream_vgroup::hdfistream_vgroup(const string filename):hdfistream_obj
159 (filename)
160{
161 _init();
162 if (_filename.length() != 0) // if ctor specified a null filename
163 open(_filename.c_str());
164 return;
165}
166
167void hdfistream_vgroup::open(const string & filename)
168{
169 open(filename.c_str());
170 return;
171}
172
173void hdfistream_vgroup::open(const char *filename)
174{
175 if (_file_id != 0)
176 close();
177 if ((_file_id = Hopen(filename, DFACC_RDONLY, 0)) < 0)
178 THROW(hcerr_openfile);
179 if (Vstart(_file_id) < 0)
180 THROW(hcerr_openfile);
181
182 BESDEBUG("h4", "vgroup file opened: id=" << _file_id << endl);
183
184 _filename = filename;
185 _get_fileinfo();
186 rewind();
187 return;
188}
189
190void hdfistream_vgroup::close(void)
191{
192 BESDEBUG("h4", "vgroup file closed: id=" << _file_id << ", this: " << this << endl);
193
194 int status;
195
196 if (_vgroup_id != 0) {
197 status = Vdetach(_vgroup_id);
198 BESDEBUG("h4", "vgroup Vdetach status: " << status << ", this: " << this << endl);
199 }
200
201 if (_file_id != 0) {
202 status = Vend(_file_id);
203 BESDEBUG("h4", "vgroup vend status: " << status << ", this: " << this << endl);
204
205 status = Hclose(_file_id);
206 BESDEBUG("h4", "vgroup HClose status: " << status << ", this: " << this << endl);
207 BESDEBUG("h4", "Error: " << HEstring((hdf_err_code_t)HEvalue(1)) << endl);
208 }
209 _vgroup_id = _file_id = _index = _attr_index = _nattrs = 0;
210 _vgroup_refs = vector < int32 > (); // clear refs
211 _recs.set = false;
212 return;
213}
214
215void hdfistream_vgroup::seek(int index)
216{
217 if (index < 0 || index >= (int) _vgroup_refs.size())
218 THROW(hcerr_range);
219 _seek(_vgroup_refs[index]);
220 _index = index;
221 return;
222}
223
224void hdfistream_vgroup::seek_ref(int ref)
225{
226 _seek(ref); // _seek() sets _index
227 return;
228}
229
230void hdfistream_vgroup::seek(const string & name)
231{
232 seek(name.c_str());
233}
234
235void hdfistream_vgroup::seek(const char *name)
236{
237 _seek(name);
238 return;
239}
240
241string hdfistream_vgroup::memberName(int32 ref)
242{
243 string mName = _memberName(ref);
244 return mName;
245}
246
247
248// read all Vgroup's in the stream
249hdfistream_vgroup & hdfistream_vgroup::operator>>(vector < hdf_vgroup >
250 &hvv)
251{
252 for (hdf_vgroup hv; !eos();) {
253 *this >> hv;
254 hvv.push_back(hv);
255 }
256 return *this;
257}
258
259// read a Vgroup from the stream
260hdfistream_vgroup & hdfistream_vgroup::operator>>(hdf_vgroup & hv)
261{
262
263 // delete any previous data in hv
264 hv.tags.clear();
265 hv.refs.clear();
266 hv.vnames.clear();
267 hv.vclass = hv.name = string();
268
269 if (_vgroup_id == 0)
270 THROW(hcerr_invstream); // no vgroup open!
271 if (eos())
272 return *this;
273
274 // assign Vgroup ref
275 hv.ref = _vgroup_refs[_index];
276 // retrieve Vgroup attributes
277 *this >> hv.attrs;
278 // retrieve Vgroup name, class, number of entries
279 char name[hdfclass::MAXSTR];
280 char vclass[hdfclass::MAXSTR];
281 int32 nentries;
282 if (Vinquire(_vgroup_id, &nentries, name) < 0)
283 THROW(hcerr_vgroupinfo);
284 hv.name = string(name);
285 if (Vgetclass(_vgroup_id, vclass) < 0)
286 THROW(hcerr_vgroupinfo);
287 hv.vclass = string(vclass);
288
289 // retrieve entry tags and refs
290 int32 npairs = Vntagrefs(_vgroup_id);
291#if 0
292 hdfistream_vdata vdin(_filename);
293#endif
294
295 for (int i = 0; i < npairs; ++i) {
296 int32 tag, ref;
297 string vname;
298 if (Vgettagref(_vgroup_id, i, &tag, &ref) < 0)
299 THROW(hcerr_vgroupread);
300 switch (tag) {
301 case DFTAG_VH:
302 // Somehow isInternalVdata causes memory leaking with the
303 // check in the vdata class. Need to check them in this group.
304#if 0
305 if (!vdin.isInternalVdata(ref)) {
306#endif
307 if (!IsInternalVdata(_file_id,ref)) {
308 hv.tags.push_back(tag);
309 hv.refs.push_back(ref);
310 hv.vnames.push_back(memberName(ref));
311 }
312 break;
313 default:
314 hv.tags.push_back(tag);
315 hv.refs.push_back(ref);
316 hv.vnames.push_back(memberName(ref));
317 }
318 }
319#if 0
320 vdin.close();
321#endif
322 _seek_next();
323 return *this;
324}
325
326//
327// hdf_vgroup related member functions
328//
329
330bool hdf_vgroup::_ok(void) const
331{
332
333 // make sure there are tags stored in this vgroup
334 if (tags.size() == 0)
335 return false;
336
337 // make sure there are refs stored in this vgroup
338 if (refs.size() == 0)
339 return false;
340
341 return true; // passed all the tests
342}
343
344bool IsInternalVgroup(int32 fid, int32 ref)
345{
346 // block vgroups used internally
347 set < string, less < string > >reserved_names;
348 reserved_names.insert("RIATTR0.0N");
349 reserved_names.insert("RIG0.0");
350
351 set < string, less < string > >reserved_classes;
352 reserved_classes.insert("Attr0.0");
353 reserved_classes.insert("RIATTR0.0C");
354 reserved_classes.insert("DimVal0.0");
355 reserved_classes.insert("DimVal0.1");
356 reserved_classes.insert("CDF0.0");
357 reserved_classes.insert("Var0.0");
358 reserved_classes.insert("Dim0.0");
359 reserved_classes.insert("UDim0.0");
360 reserved_classes.insert("Data0.0");
361 reserved_classes.insert("RI0.0");
362
363 // get name, class of vgroup
364 int vid;
365 if ((vid = Vattach(fid, ref, "r")) < 0) {
366 THROW(hcerr_vgroupopen);
367 }
368
369 char name[hdfclass::MAXSTR];
370 char vclass[hdfclass::MAXSTR];
371 if (Vgetname(vid, name) < 0) {
372 Vdetach(vid);
373 THROW(hcerr_vgroupinfo);
374 }
375 if (reserved_names.find(string(name)) != reserved_names.end()) {
376 Vdetach(vid);
377 return true;
378 }
379
380 if (Vgetclass(vid, vclass) < 0) {
381 Vdetach(vid);
382 THROW(hcerr_vgroupinfo);
383 }
384
385 Vdetach(vid);
386
387 if (reserved_classes.find(string(vclass)) != reserved_classes.end())
388 return true;
389
390 return false;
391}
392
393bool IsInternalVdata(int32 fid, int32 ref) {
394 set<string, less<string> > reserved_names;
395 reserved_names.insert("RIATTR0.0N");
396
397 set<string, less<string> > reserved_classes;
398 reserved_classes.insert("Attr0.0");
399 reserved_classes.insert("RIATTR0.0C");
400 reserved_classes.insert("DimVal0.0");
401 reserved_classes.insert("DimVal0.1");
402 reserved_classes.insert("_HDF_CHK_TBL_0");
403
404 // get name, class of vdata
405 int vid;
406 if ((vid = VSattach(fid, ref, "r")) < 0) {
407 THROW(hcerr_vdataopen);
408 }
409 char name[hdfclass::MAXSTR];
410 char vclass[hdfclass::MAXSTR];
411 if (VSgetname(vid, name) < 0) {
412 VSdetach(vid);
413 THROW(hcerr_vdatainfo);
414 }
415 if (reserved_names.find(string(name)) != reserved_names.end()) {
416 VSdetach(vid);
417 return true;
418 }
419
420 if (VSgetclass(vid, vclass) < 0) {
421 VSdetach(vid);
422 THROW(hcerr_vdatainfo);
423 }
424
425 VSdetach(vid);
426
427 if (reserved_classes.find(string(vclass)) != reserved_classes.end())
428 return true;
429
430 return false;
431}
432
433
434// check to see if stream is positioned past the last attribute in the
435// currently open Vgroup
436bool hdfistream_vgroup::eo_attr(void) const
437{
438 if (_filename.length() == 0) // no file open
439 THROW(hcerr_invstream);
440 if (eos() && !bos()) // if eos(), then always eo_attr()
441 return true;
442 else {
443 return (_attr_index >= _nattrs); // or positioned after last Vgroup attr?
444 }
445}
446
447// Read all attributes in the stream
448hdfistream_vgroup & hdfistream_vgroup::operator>>(vector < hdf_attr > &hav)
449{
450// hav = vector<hdf_attr>0; // reset vector
451 for (hdf_attr att; !eo_attr();) {
452 *this >> att;
453 hav.push_back(att);
454 }
455 return *this;
456}
457
458// read an attribute from the stream
459hdfistream_vgroup & hdfistream_vgroup::operator>>(hdf_attr & ha)
460{
461 // delete any previous data in ha
462 ha.name = string();
463 ha.values = hdf_genvec();
464
465 if (_filename.length() == 0) // no file open
466 THROW(hcerr_invstream);
467 if (eo_attr()) // if positioned past last attr, do nothing
468 return *this;
469
470 char name[hdfclass::MAXSTR];
471 int32 number_type, count, size;
472 if (Vattrinfo
473 (_vgroup_id, _attr_index, name, &number_type, &count, &size) < 0)
474 THROW(hcerr_vgroupinfo);
475
476 // allocate a temporary C array to hold data from VSgetattr()
477 char *data;
478 data = new char[count * DFKNTsize(number_type)];
479 if (data == 0)
480 THROW(hcerr_nomemory);
481
482 // read attribute values and store them in an hdf_genvec
483 if (Vgetattr(_vgroup_id, _attr_index, data) < 0) {
484 delete[]data; // problem: clean up and throw an exception
485 THROW(hcerr_vgroupinfo);
486 }
487 // try { // try to allocate an hdf_genvec
488 if (count > 0) {
489 ha.values = hdf_genvec(number_type, data, count);
490 // }
491 // catch(...) { // problem allocating hdf_genvec: clean up and rethrow
492 // delete []data;
493 // throw;
494 // }
495 }
496 delete[]data; // deallocate temporary C array
497
498 // increment attribute index to next attribute
499 ++_attr_index;
500 ha.name = name; // assign attribute name
501 return *this;
502}
503