bes Updated for version 3.20.13
sds.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 1996, 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//
40// $RCSfile: sds.cc,v $ - input stream class for HDF SDS
41//
43
44#include "config_hdf.h"
45
46#include <mfhdf.h>
47
48#ifdef __POWERPC__
49#undef isascii
50#endif
51
52#include <string>
53#include <vector>
54#include <algorithm>
55#include <functional>
56#include <cerrno>
57
58#include <hcstream.h>
59#include <hdfclass.h>
60
61#include <BESDebug.h>
62
63using std::cerr;
64using std::endl;
65
66// minimum function
67inline int min(int t1, int t2)
68{
69 return (t1 < t2 ? t1 : t2);
70}
71
72// static initializations
73const string hdfistream_sds::long_name = "long_name";
74const string hdfistream_sds::units = "units";
75const string hdfistream_sds::format = "format";
76
77//
78// protected member functions
79//
80
81// initialize an hdfistream_sds, opening file if given
82void hdfistream_sds::_init(void)
83{
84 _sds_id = _attr_index = _dim_index = _nsds = _rank = _nattrs =
85 _nfattrs = 0;
86 _index = -1; // set BOS
87 _meta = _slab.set = false;
88 _map_ce_set = false;
89 return;
90}
91
92// retrieve descriptive information about file containing SDS
93void hdfistream_sds::_get_fileinfo(void)
94{
95 if (SDfileinfo(_file_id, &_nsds, &_nfattrs) < 0)
96 THROW(hcerr_sdsinfo);
97 return;
98}
99
100// retrieve descriptive information about currently open SDS
101void hdfistream_sds::_get_sdsinfo(void)
102{
103 char junk0[hdfclass::MAXSTR];
104 int32 junk1[hdfclass::MAXDIMS];
105 int32 junk2;
106
107 // all we care about is rank and number of attributes
108 if (SDgetinfo(_sds_id, junk0, &_rank, junk1, &junk2, &_nattrs) < 0)
109 THROW(hcerr_sdsinfo);
110
111 if (_rank > hdfclass::MAXDIMS) // too many dimensions
112 THROW(hcerr_maxdim);
113 return;
114}
115
116// end access to currently open SDS
117void hdfistream_sds::_close_sds(void)
118{
119 if (_sds_id != 0) {
120 (void) SDendaccess(_sds_id);
121 _sds_id = _attr_index = _dim_index = _rank = _nattrs = 0;
122 _index = -1;
123 }
124 return;
125}
126
127// find the next SDS array (not necessarily the next SDS) in the file
128void hdfistream_sds::_seek_next_arr(void)
129{
130 if (_sds_id != 0) {
131 BESDEBUG("h4", "hdfistream_sds::_seek_next_arr called with an open sds: "
132 << _sds_id << endl);
133 SDendaccess(_sds_id);
134 _sds_id = 0;
135 }
136
137 for (_index++, _dim_index = _attr_index = 0; _index < _nsds; ++_index) {
138 if (_sds_id != 0) {
139 BESDEBUG("h4", "hdfistream_sds::_seek_next_arr inside for-loop with an open sds: "
140 << _sds_id << endl);
141 }
142 if ((_sds_id = SDselect(_file_id, _index)) < 0)
143 THROW(hcerr_sdsopen);
144 if (!SDiscoordvar(_sds_id))
145 break;
146 SDendaccess(_sds_id);
147 _sds_id = 0;
148 }
149}
150
151// find the arr_index'th SDS array in the file (don't count non-array SDS's)
152void hdfistream_sds::_seek_arr(int arr_index)
153{
154 int arr_count = 0;
155 for (_rewind(); _index < _nsds && arr_count <= arr_index;
156 _seek_next_arr(), arr_count++);
157}
158
159// find the SDS array with specified name
160void hdfistream_sds::_seek_arr(const string & name)
161{
162 if (_sds_id != 0) {
163 BESDEBUG("h4", "hdfistream_sds::_seek_arr called with an open sds: "
164 << _sds_id << endl);
165 _close_sds();
166 }
167
168 int index;
169 const char *nm = name.c_str();
170 if ((index = SDnametoindex(_file_id, (char *) nm)) < 0)
171 THROW(hcerr_sdsfind);
172 if ((_sds_id = SDselect(_file_id, index)) < 0)
173 THROW(hcerr_sdsopen);
174 bool iscoord = SDiscoordvar(_sds_id);
175 if (iscoord) {
176 SDendaccess(_sds_id);
177 _sds_id = 0;
178 THROW(hcerr_sdsfind);
179 }
180 _index = index;
181 return;
182}
183
184// find the SDS array with specified ref
185void hdfistream_sds::_seek_arr_ref(int ref)
186{
187 if (_sds_id != 0) {
188 BESDEBUG("h4", "hdfistream_sds::_seek_arr_ref called with an open sds: "
189 << _sds_id << endl);
190 _close_sds();
191 }
192
193 int index;
194 if ((index = SDreftoindex(_file_id, ref)) < 0)
195 THROW(hcerr_sdsfind);
196 if ((_sds_id = SDselect(_file_id, index)) < 0)
197 THROW(hcerr_sdsopen);
198 bool iscoord = SDiscoordvar(_sds_id);
199 if (iscoord) {
200 SDendaccess(_sds_id);
201 _sds_id = 0;
202 THROW(hcerr_sdsfind);
203 }
204 _index = index;
205 return;
206}
207
208//
209// public member functions
210//
211
212
213// constructor
214hdfistream_sds::hdfistream_sds(const string filename):
215hdfistream_obj(filename)
216{
217 _init();
218 if (_filename.length() != 0) // if ctor specified a file to open
219 open(_filename.c_str());
220 return;
221}
222
223// check to see if stream has been positioned past last SDS in file
224bool hdfistream_sds::eos(void) const
225{
226 if (_filename.length() == 0) // no file open
227 THROW(hcerr_invstream);
228 if (_nsds == 0) // eos() is always true of there are no SDS's in file
229 return true;
230 else {
231 if (bos()) // eos() is never true if at bos() and there are SDS's
232 return false;
233 else
234 return (_index >= _nsds); // are we indexed past the last SDS?
235 }
236}
237
238// check to see if stream is positioned in front of the first SDS in file
239bool hdfistream_sds::bos(void) const
240{
241 if (_filename.length() == 0) // no file open
242 THROW(hcerr_invstream);
243 if (_nsds == 0)
244 return true; // if there are no SDS's we still want to read file attrs so both eos() and bos() are true
245 if (_index == -1)
246 return true;
247 else
248 return false;
249}
250
251// check to see if stream is positioned past the last attribute in the currently
252// open SDS
253bool hdfistream_sds::eo_attr(void) const
254{
255 if (_filename.length() == 0) // no file open
256 THROW(hcerr_invstream);
257 if (eos() && !bos()) // if eos(), then always eo_attr()
258 return true;
259 else {
260 if (bos()) // are we at BOS and are positioned past last file attributes?
261 return (_attr_index >= _nfattrs);
262 else
263 return (_attr_index >= _nattrs); // or positioned after last SDS attr?
264 }
265}
266
267// check to see if stream is positioned past the last dimension in the currently
268// open SDS
269bool hdfistream_sds::eo_dim(void) const
270{
271 if (_filename.length() == 0) // no file open
272 THROW(hcerr_invstream);
273 if (eos()) // if eos(), then always eo_dim()
274 return true;
275 else {
276 if (bos()) // if at BOS, then never eo_dim()
277 return true;
278 else
279 return (_dim_index >= _rank); // are we positioned after last dim?
280 }
281}
282
283// open a new file
284void hdfistream_sds::open(const char *filename)
285{
286 if (filename == 0) // no filename given
287 THROW(hcerr_openfile);
288 BESDEBUG("h4", "sds opening file " << filename << endl);
289 if (_file_id != 0) // close any currently open file
290 close();
291 if ((_file_id = SDstart((char *) filename, DFACC_READ)) < 0)
292 {
293 THROW(hcerr_openfile);
294 }
295
296 BESDEBUG("h4", "sds file opened: id=" << _file_id << endl);
297
298 _filename = filename; // assign filename
299 _get_fileinfo(); // get file information
300 rewind(); // position at BOS to start
301 return;
302}
303
304// close currently open file (if any)
305void hdfistream_sds::close(void)
306{ // close file
307 BESDEBUG("h4", "sds file closed: id=" << _file_id << ", this: " << this<< endl);
308
309 _close_sds(); // close any currently open SDS
310 if (_file_id != 0) // if open file, then close it
311 (void) SDend(_file_id);
312 _file_id = _nsds = _nfattrs = 0; // zero file info
313 return;
314}
315
316// position SDS array index to index'th SDS array (not necessarily index'th SDS)
317void hdfistream_sds::seek(int index)
318{
319 if (_filename.length() == 0) // no file open
320 THROW(hcerr_invstream);
321 _close_sds(); // close any currently open SDS
322 _seek_arr(index); // seek to index'th SDS array
323 if (!eos() && !bos()) // if not BOS or EOS, get SDS information
324 _get_sdsinfo();
325}
326
327// position SDS array index to SDS array with name "name"
328void hdfistream_sds::seek(const char *name)
329{
330 if (_filename.length() == 0) // no file open
331 THROW(hcerr_invstream);
332 _close_sds(); // close any currently open SDS
333 _seek_arr(string(name)); // seek to index'th SDS array
334 if (!eos() && !bos()) // if not BOS or EOS, get SDS information
335 _get_sdsinfo();
336}
337
338// position SDS array index in front of first SDS array
339void hdfistream_sds::rewind(void)
340{
341 if (_filename.length() == 0) // no file open
342 THROW(hcerr_invstream);
343 _close_sds(); // close any already open SDS
344 _rewind(); // seek to BOS
345}
346
347// position to next SDS array in file
348void hdfistream_sds::seek_next(void)
349{
350 if (_filename.length() == 0) // no file open
351 THROW(hcerr_invstream);
352 _seek_next_arr(); // seek to next SDS array
353 if (!eos()) // if not EOS, get SDS information
354 _get_sdsinfo();
355}
356
357// position to SDS array by ref
358void hdfistream_sds::seek_ref(int ref)
359{
360 if (_filename.length() == 0) // no file open
361 THROW(hcerr_invstream);
362 _close_sds(); // close any currently open SDS
363 _seek_arr_ref(ref); // seek to SDS array by reference
364 if (!eos() && !bos()) // if not BOS or EOS, get SDS information
365 _get_sdsinfo();
366}
367
368// set slab parameters
369void hdfistream_sds::setslab(vector < int >start, vector < int >edge,
370 vector < int >stride, bool reduce_rank)
371{
372 // check validity of input
373 if (start.size() != edge.size() || edge.size() != stride.size()
374 || start.size() == 0)
375 THROW(hcerr_invslab);
376
377 int i;
378 for (i = 0; i < (int) start.size() && i < hdfclass::MAXDIMS; ++i) {
379 if (start[i] < 0)
380 THROW(hcerr_invslab);
381 if (edge[i] <= 0)
382 THROW(hcerr_invslab);
383 if (stride[i] <= 0)
384 THROW(hcerr_invslab);
385 _slab.start[i] = start[i];
386 _slab.edge[i] = edge[i];
387 _slab.stride[i] = stride[i];
388 }
389 _slab.set = true;
390 _slab.reduce_rank = reduce_rank;
391}
392
393// This function, when compiled with gcc 2.8 and -O2, causes a virtual
394// memory exceeded error. 2/25/98 jhrg
395// load currently open SDS into an hdf_sds object
396hdfistream_sds & hdfistream_sds::operator>>(hdf_sds & hs)
397{
398
399 // delete any previous data in hs
400 hs.dims = vector < hdf_dim > ();
401 hs.attrs = vector < hdf_attr > ();
402 hs.data = hdf_genvec();
403 hs.name = string();
404
405 if (_filename.length() == 0) // no file open
406 THROW(hcerr_invstream);
407 if (bos()) // if at BOS, advance to first SDS array
408 seek(0);
409 if (eos()) // if at EOS, do nothing
410 return *this;
411
412 // get basic info about SDS
413 char name[hdfclass::MAXSTR];
414 int32 rank;
415 int32 dim_sizes[hdfclass::MAXDIMS];
416 int32 number_type;
417 int32 nattrs;
418 if (SDgetinfo(_sds_id, name, &rank, dim_sizes, &number_type, &nattrs) <
419 0)
420 THROW(hcerr_sdsinfo);
421
422 // assign SDS index
423 hs.ref = SDidtoref(_sds_id);
424 // load dimensions and attributes into the appropriate objects
425 *this >> hs.dims;
426 *this >> hs.attrs;
427 hs.name = name; // assign SDS name
428 char *data = 0;
429 int nelts = 1;
430 if (_meta) // if _meta is set, just load type information
431 hs.data.import(number_type);
432 else {
433 if (_slab.set) { // load a slab of SDS array data
434 for (int i = 0; i < rank; ++i)
435 nelts *= _slab.edge[i];
436
437 // allocate a temporary C array to hold the data from SDreaddata()
438 int datasize = nelts * DFKNTsize(number_type);
439 data = new char[datasize];
440 if (data == 0)
441 THROW(hcerr_nomemory);
442 BESDEBUG("h4", "SDreaddata() on line 387. _sds_id: " << _sds_id
443 << endl);
444 if (SDreaddata(_sds_id, _slab.start, _slab.stride, _slab.edge,
445 data) < 0) {
446 delete[]data; // problem: clean up and throw an exception
447 THROW(hcerr_sdsread);
448 }
449 } else { // load entire SDS array
450 // prepare for SDreaddata(): make an array of zeroes and calculate
451 // number of elements of array data
452 int32 zero[hdfclass::MAXDIMS];
453 for (int i = 0; i < rank && i < hdfclass::MAXDIMS; ++i) {
454 zero[i] = 0;
455 nelts *= dim_sizes[i];
456 }
457
458 // allocate a temporary C array to hold the data from SDreaddata()
459 int datasize = nelts * DFKNTsize(number_type);
460 data = new char[datasize];
461 if (data == 0)
462 THROW(hcerr_nomemory);
463
464 // read the data and store it in an hdf_genvec
465 if (SDreaddata(_sds_id, zero, 0, dim_sizes, data) < 0) {
466 delete[]data; // problem: clean up and throw an exception
467 THROW(hcerr_sdsread);
468 }
469 }
470
471 hs.data.import(number_type, data, nelts);
472 delete[]data; // deallocate temporary C array
473 }
474
475 seek_next(); // position to next SDS array
476 return *this;
477}
478
479// Functor to help look for a particular map's ce in the vector of array_ce
480// objects.
481class ce_name_match:public std::unary_function < array_ce, bool > {
482 string name;
483 public:
484 ce_name_match(const string & n):name(n) {
485 } bool operator() (const array_ce & a_ce) {
486 return name == a_ce.name;
487 }
488};
489
490// load dimension currently positioned at
491hdfistream_sds & hdfistream_sds::operator>>(hdf_dim & hd)
492{
493
494 // delete any previous data in hd
495 hd.name = hd.label = hd.unit = hd.format = string();
496 hd.count = 0;
497 hd.scale = hdf_genvec();
498 hd.attrs = vector < hdf_attr > ();
499
500 if (_filename.length() == 0) // no file open
501 THROW(hcerr_invstream);
502 if (bos()) // if at BOS, advance to first SDS array
503 seek(0);
504
505 // This code looks like an optimization to avoid reading unneeded
506 // dimensions. If we're here because we're reading the whole Grid, it
507 // needs to be run, If we're here because the client has asked only for
508 // the Grid's maps, then it's harmless since the Grid's array's
509 // constraint is the default (the whole array) and so there'll be no
510 // reduction in rank. 2/5/2002 jhrg
511 //
512 // if reduce_rank is true, hyperslab dimensions of length 1 will be
513 // eliminated from the dimension object, thus reducing the rank of the
514 // hyperslab
515 while (_slab.set && _slab.reduce_rank && !eo_dim() &&
516 _slab.edge[_dim_index] == 1)
517 ++_dim_index;
518
519 // if positioned past last dimension, do nothing
520 if (eo_dim())
521 return *this;
522
523 // open dimension currently positioned at and increment dim index
524 int32 dim_id;
525 if ((dim_id = SDgetdimid(_sds_id, _dim_index)) < 0)
526 THROW(hcerr_sdsinfo);
527
528 // get dimension information
529
530 char name[hdfclass::MAXSTR];
531 int32 count, number_type, nattrs;
532 if (SDdiminfo(dim_id, name, &count, &number_type, &nattrs) < 0)
533 THROW(hcerr_sdsinfo);
534 else
535 hd.name = name; // assign dim name
536
537 // Grab the current slab, save its value, and set _slab using map_ce. To
538 // choose the correct constraint scan the vector of array_ce objects
539 // looking for the one with the same name as this dimension. Doing this
540 // assures us that the constraint that's used when data is extracted from
541 // the hdf_genvec is done according to the constraint on this map. If we
542 // used _slab as it's set on entry to this method we would be using the
543 // constraint associated with the Grid's array. If the client asked only
544 // for maps, that constraint would default to the whole array and hence
545 // we'd be returning the whole map vector and ignoring the actual
546 // constraint sent by the client. 2/5/2002 jhrg
547 slab s = _slab;
548 if (is_map_ce_set()) { // Only go here if the map_ce_vec has been
549 // set. The is_map_ce_set() predicate is
550 // false by default.
551#if 0
552 cerr << "dim name: " << name << endl;
553 cerr << "slab set: " << _slab.set << endl;
554 cerr << "dim index: " << _dim_index << endl;
555 cerr << "slab start: " << _slab.start[_dim_index] << endl;
556 cerr << "slab edge: " << _slab.edge[_dim_index] << endl;
557#endif
558
559 vector < array_ce > ce = get_map_ce();
560 vector < array_ce >::iterator ce_iter =
561 find_if(ce.begin(), ce.end(), ce_name_match(string(name)));
562#if 0
563 cerr << "ce name: " << ce_iter->name << endl;
564 cerr << "ce set: " << (ce_iter->start != 0 || ce_iter->edge != 0
565 || ce_iter->stride != 0) << endl;
566 cerr << "ce start: " << ce_iter->start << endl;
567 cerr << "ce edge: " << ce_iter->edge << endl << endl;
568#endif
569
570 // KY: coverity: may dereference ce.end(), which is not in the iterator
571 if(ce_iter!=ce.end()) {
572 _slab.set = ce_iter->start != 0 || ce_iter->edge != 0
573 || ce_iter->stride != 0;
574 _slab.reduce_rank = false; // hard to reduce the rank of a vector...
575 _slab.start[_dim_index] = ce_iter->start;
576 _slab.edge[_dim_index] = ce_iter->edge;
577 _slab.stride[_dim_index] = ce_iter->stride;
578 }
579 else
580 THROW(hcerr_sdsinfo);
581 }
582 // Catch any throws and reset _slab.
583 try {
584 char label[hdfclass::MAXSTR];
585 char unit[hdfclass::MAXSTR];
586 char cformat[hdfclass::MAXSTR];
587 if (SDgetdimstrs(dim_id, label, unit, cformat, hdfclass::MAXSTR) ==
588 0) {
589 hd.label = label; // assign dim label
590 hd.unit = unit; // assign dim unit
591 hd.format = cformat; // assign dim format
592 }
593 // if we are dealing with a dimension of size unlimited, then call
594 // SDgetinfo to get the current size of the dimension
595 if (count == 0) { // unlimited dimension
596 if (_dim_index != 0)
597 THROW(hcerr_sdsinfo); // only first dim can be unlimited
598 char junk[hdfclass::MAXSTR];
599 int32 junk2, junk3, junk4;
600 int32 dim_sizes[hdfclass::MAXDIMS];
601 if (SDgetinfo(_sds_id, junk, &junk2, dim_sizes, &junk3, &junk4)
602 < 0)
603 THROW(hcerr_sdsinfo);
604 count = dim_sizes[0];
605 }
606 // load user-defined attributes for the dimension
607 // TBD! Not supported at present
608
609 // load dimension scale if there is one
610
611 if (number_type != 0) { // found a dimension scale
612
613 /*
614 * Currently, this server cannot support dimension scales
615 * that are stored as character arrays. See bugs 748 and 756.
616 */
617 if (number_type != DFNT_CHAR) {
618 // allocate a temporary C array to hold data from
619 // SDgetdimscale()
620 char *data = new char[count * DFKNTsize(number_type)];
621
622 if (data == 0)
623 THROW(hcerr_nomemory);
624
625 // read the scale data and store it in an hdf_genvec
626 if (SDgetdimscale(dim_id, data) < 0) {
627 delete[]data; // problem: clean up and throw an exception
628 THROW(hcerr_sdsinfo);
629 }
630
631 if (_slab.set) {
632 void *datastart = (char *) data +
633 _slab.start[_dim_index] * DFKNTsize(number_type);
634 hd.scale = hdf_genvec(number_type, datastart, 0,
635 _slab.edge[_dim_index] *
636 _slab.stride[_dim_index] - 1,
637 _slab.stride[_dim_index]);
638 } else
639 hd.scale = hdf_genvec(number_type, data, count);
640
641 delete[]data; // deallocate temporary C array
642 }
643 }
644 // assign dim size; if slabbing is set, assigned calculated size,
645 // otherwise assign size from SDdiminfo()
646 if (_slab.set)
647 hd.count = _slab.edge[_dim_index];
648 else
649 hd.count = count;
650 _dim_index++;
651 }
652 catch(...) {
653 _slab = s;
654 throw;
655 }
656
657 _slab = s; // reset _slab
658
659 return *this;
660}
661
662// load attribute currently positioned at
663hdfistream_sds & hdfistream_sds::operator>>(hdf_attr & ha)
664{
665
666 // delete any previous data in ha
667 ha.name = string();
668 ha.values = hdf_genvec();
669
670 if (_filename.length() == 0) // no file open
671 THROW(hcerr_invstream);
672 if (eo_attr()) // if positioned past last attribute, do nothing
673 return *this;
674
675 // prepare to read attribute information: set nattrs, id depending on whether
676 // reading file attributes or SDS attributes
677 int32 id;
678 //int nattrs;
679 if (bos()) { // if at BOS, then read file attributes
680 //nattrs = _nfattrs;
681 id = _file_id;
682 } else { // else read SDS attributes
683 //nattrs = _nattrs;
684 id = _sds_id;
685 }
686 char name[hdfclass::MAXSTR];
687 int32 number_type, count;
688 if (SDattrinfo(id, _attr_index, name, &number_type, &count) < 0)
689 THROW(hcerr_sdsinfo);
690
691 // allowcate a temporary C array to hold data from SDreadattr()
692 char *data;
693 data = new char[count * DFKNTsize(number_type)];
694 if (data == 0)
695 THROW(hcerr_nomemory);
696
697 // read attribute values and store them in an hdf_genvec
698 if (SDreadattr(id, _attr_index, data) < 0) {
699 delete[]data; // problem: clean up and throw an exception
700 THROW(hcerr_sdsinfo);
701 }
702 // eliminate trailing null characters from the data string;
703 // they cause GNU's String class problems
704 // NOTE: removed because count=0 if initial char is '\0' and we're not
705 // using GNU String anymore
706#if 0
707 if (number_type == DFNT_CHAR)
708 count = (int32) min((int) count, (int) strlen((char *) data));
709#endif
710
711 // try { // try to allocate an hdf_genvec
712 if (count > 0) {
713 ha.values = hdf_genvec(number_type, data, count);
714 // }
715 // catch(...) { // problem allocating hdf_genvec: clean up and rethrow
716 // delete []data;
717 // throw;
718 // }
719 }
720 delete[]data; // deallocate temporary C array
721
722 // increment attribute index to next attribute
723 ++_attr_index;
724 ha.name = name; // assign attribute name
725 return *this;
726}
727
728// This function, when compiled with gcc 2.8 and -O2, causes a virtual
729// Memory exceeded error. 2/25/98 jhrg
730// read in all the SDS arrays in a file
731hdfistream_sds & hdfistream_sds::operator>>(vector < hdf_sds > &hsv)
732{
733 // hsv = vector<hdf_sds>0; // reset vector
734 for (hdf_sds sds; !eos();) {
735 *this >> sds;
736 hsv.push_back(sds);
737 }
738 return *this;
739}
740
741// read in all of the SDS attributes for currently open SDS
742hdfistream_sds & hdfistream_sds::operator>>(vector < hdf_attr > &hav)
743{
744 // hav = vector<hdf_attr>0; // reset vector
745 for (hdf_attr att; !eo_attr();) {
746 *this >> att;
747 hav.push_back(att);
748 }
749 return *this;
750}
751
752// read in all of the SDS dimensions for currently open SDS
753hdfistream_sds & hdfistream_sds::operator>>(vector < hdf_dim > &hdv)
754{
755 // hdv = vector<hdf_dim>0; // reset vector
756 for (hdf_dim dim; !eo_dim();) {
757 *this >> dim;
758 hdv.push_back(dim);
759 }
760 return *this;
761}
762
763// Check to see if this hdf_sds has a dim scale: if all of the dimensions have
764// scale sizes = to their size, it does
765bool hdf_sds::has_scale(void) const
766{
767 bool has_scale;
768 if (!_ok(&has_scale)) {
769 THROW(hcerr_sdsscale);
770 return false;
771 } else
772 return has_scale;
773}
774
775// Verify that the hdf_sds is in an OK state (i.e., that it is initialized
776// correctly) if user has passed a ptr to a bool then set that to whether
777// there is a dimension scale for at least one of the dimensions
778//
779// Added `if (*has_scale)...' because `has_scale' defaults to null and
780// dereferencing it causes segmentation faults, etc.
781
782bool hdf_sds::_ok(bool * has_scale) const
783{
784
785 if (has_scale)
786 *has_scale = false;
787
788 // Check to see that for each SDS dimension scale, that the length of the
789 // scale matches the size of the dimension.
790 for (int i = 0; i < (int) dims.size(); ++i)
791 if (dims[i].scale.size() != 0) {
792 if (has_scale)
793 *has_scale = true;
794 if (dims[i].scale.size() != dims[i].count)
795 return false;
796 }
797
798 return true;
799}