bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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.size() != 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.size() == 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.size() == 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.size() == 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.size() == 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 == nullptr) // 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.size() == 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.size() == 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.size() == 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.size() == 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.size() == 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 for (int i = 0; i < (int) start.size() && i < hdfclass::MAXDIMS; ++i) {
378 if (start[i] < 0)
379 THROW(hcerr_invslab);
380 if (edge[i] <= 0)
381 THROW(hcerr_invslab);
382 if (stride[i] <= 0)
383 THROW(hcerr_invslab);
384 _slab.start[i] = start[i];
385 _slab.edge[i] = edge[i];
386 _slab.stride[i] = stride[i];
387 }
388 _slab.set = true;
389 _slab.reduce_rank = reduce_rank;
390}
391
392// This function, when compiled with gcc 2.8 and -O2, causes a virtual
393// memory exceeded error. 2/25/98 jhrg
394// load currently open SDS into an hdf_sds object
395hdfistream_sds & hdfistream_sds::operator>>(hdf_sds & hs)
396{
397
398 // delete any previous data in hs
399 hs.dims = vector < hdf_dim > ();
400 hs.attrs = vector < hdf_attr > ();
401 hs.data = hdf_genvec();
402 hs.name = string();
403
404 if (_filename.size() == 0) // no file open
405 THROW(hcerr_invstream);
406 if (bos()) // if at BOS, advance to first SDS array
407 seek(0);
408 if (eos()) // if at EOS, do nothing
409 return *this;
410
411 // get basic info about SDS
412 char name[hdfclass::MAXSTR];
413 int32 rank;
414 int32 dim_sizes[hdfclass::MAXDIMS];
415 int32 number_type;
416 int32 nattrs;
417 if (SDgetinfo(_sds_id, name, &rank, dim_sizes, &number_type, &nattrs) <
418 0)
419 THROW(hcerr_sdsinfo);
420
421 // assign SDS index
422 hs.ref = SDidtoref(_sds_id);
423 // load dimensions and attributes into the appropriate objects
424 *this >> hs.dims;
425 *this >> hs.attrs;
426 hs.name = name; // assign SDS name
427 char *data = nullptr;
428 int nelts = 1;
429 if (_meta) // if _meta is set, just load type information
430 hs.data.import_vec(number_type);
431 else {
432 if (_slab.set) { // load a slab of SDS array data
433 for (int i = 0; i < rank; ++i)
434 nelts *= _slab.edge[i];
435
436 // allocate a temporary C array to hold the data from SDreaddata()
437 int datasize = nelts * DFKNTsize(number_type);
438 data = new char[datasize];
439 if (data == nullptr)
440 THROW(hcerr_nomemory);
441 BESDEBUG("h4", "SDreaddata() on line 387. _sds_id: " << _sds_id
442 << endl);
443 if (SDreaddata(_sds_id, _slab.start, _slab.stride, _slab.edge,
444 data) < 0) {
445 delete[]data; // problem: clean up and throw an exception
446 THROW(hcerr_sdsread);
447 }
448 } else { // load entire SDS array
449 // prepare for SDreaddata(): make an array of zeroes and calculate
450 // number of elements of array data
451 int32 zero[hdfclass::MAXDIMS];
452 for (int i = 0; i < rank && i < hdfclass::MAXDIMS; ++i) {
453 zero[i] = 0;
454 nelts *= dim_sizes[i];
455 }
456
457 // allocate a temporary C array to hold the data from SDreaddata()
458 int datasize = nelts * DFKNTsize(number_type);
459 data = new char[datasize];
460 if (data == nullptr)
461 THROW(hcerr_nomemory);
462
463 // read the data and store it in an hdf_genvec
464 if (SDreaddata(_sds_id, zero, nullptr, dim_sizes, data) < 0) {
465 delete[]data; // problem: clean up and throw an exception
466 THROW(hcerr_sdsread);
467 }
468 }
469
470 hs.data.import_vec(number_type, data, nelts);
471 delete[]data; // deallocate temporary C array
472 }
473
474 seek_next(); // position to next SDS array
475 return *this;
476}
477
478// Functor to help look for a particular map's ce in the vector of array_ce
479// objects.
480class ce_name_match:public std::unary_function < array_ce, bool > {
481 string name;
482 public:
483 explicit ce_name_match(const string & n):name(n) {
484 }
485 bool operator() (const array_ce & a_ce) const {
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.size() == 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;
532 int32 number_type;
533 int32 nattrs;
534 if (SDdiminfo(dim_id, name, &count, &number_type, &nattrs) < 0)
535 THROW(hcerr_sdsinfo);
536 else
537 hd.name = name; // assign dim name
538
539 // Grab the current slab, save its value, and set _slab using map_ce. To
540 // choose the correct constraint scan the vector of array_ce objects
541 // looking for the one with the same name as this dimension. Doing this
542 // assures us that the constraint that's used when data is extracted from
543 // the hdf_genvec is done according to the constraint on this map. If we
544 // used _slab as it's set on entry to this method we would be using the
545 // constraint associated with the Grid's array. If the client asked only
546 // for maps, that constraint would default to the whole array and hence
547 // we'd be returning the whole map vector and ignoring the actual
548 // constraint sent by the client. 2/5/2002 jhrg
549 slab s = _slab;
550 if (is_map_ce_set()) { // Only go here if the map_ce_vec has been
551 // set. The is_map_ce_set() predicate is
552 // false by default.
553#if 0
554 cerr << "dim name: " << name << endl;
555 cerr << "slab set: " << _slab.set << endl;
556 cerr << "dim index: " << _dim_index << endl;
557 cerr << "slab start: " << _slab.start[_dim_index] << endl;
558 cerr << "slab edge: " << _slab.edge[_dim_index] << endl;
559#endif
560
561 vector < array_ce > ce = get_map_ce();
562 auto ce_iter = find_if(ce.begin(), ce.end(), ce_name_match(string(name)));
563#if 0
564 cerr << "ce name: " << ce_iter->name << endl;
565 cerr << "ce set: " << (ce_iter->start != 0 || ce_iter->edge != 0
566 || ce_iter->stride != 0) << endl;
567 cerr << "ce start: " << ce_iter->start << endl;
568 cerr << "ce edge: " << ce_iter->edge << endl << endl;
569#endif
570
571 // KY: coverity: may dereference ce.end(), which is not in the iterator
572 if(ce_iter!=ce.end()) {
573 _slab.set = ce_iter->start != 0 || ce_iter->edge != 0
574 || ce_iter->stride != 0;
575 _slab.reduce_rank = false; // hard to reduce the rank of a vector...
576 _slab.start[_dim_index] = ce_iter->start;
577 _slab.edge[_dim_index] = ce_iter->edge;
578 _slab.stride[_dim_index] = ce_iter->stride;
579 }
580 else
581 THROW(hcerr_sdsinfo);
582 }
583 // Catch any throws and reset _slab.
584 try {
585 char label[hdfclass::MAXSTR];
586 char unit[hdfclass::MAXSTR];
587 char cformat[hdfclass::MAXSTR];
588 if (SDgetdimstrs(dim_id, label, unit, cformat, hdfclass::MAXSTR) ==
589 0) {
590 hd.label = label; // assign dim label
591 hd.unit = unit; // assign dim unit
592 hd.format = cformat; // assign dim format
593 }
594 // if we are dealing with a dimension of size unlimited, then call
595 // SDgetinfo to get the current size of the dimension
596 if (count == 0) { // unlimited dimension
597 if (_dim_index != 0)
598 THROW(hcerr_sdsinfo); // only first dim can be unlimited
599 char junk[hdfclass::MAXSTR];
600 int32 junk2, junk3, junk4;
601 int32 dim_sizes[hdfclass::MAXDIMS];
602 if (SDgetinfo(_sds_id, junk, &junk2, dim_sizes, &junk3, &junk4)
603 < 0)
604 THROW(hcerr_sdsinfo);
605 count = dim_sizes[0];
606 }
607 // load user-defined attributes for the dimension
608 // TBD! Not supported at present
609
610 // load dimension scale if there is one
611
612 if (number_type != 0) { // found a dimension scale
613
614 /*
615 * Currently, this server cannot support dimension scales
616 * that are stored as character arrays. See bugs 748 and 756.
617 */
618 if (number_type != DFNT_CHAR) {
619 // allocate a temporary C array to hold data from
620 // SDgetdimscale()
621 auto data = new char[count * DFKNTsize(number_type)];
622
623 if (data == nullptr)
624 THROW(hcerr_nomemory);
625
626 // read the scale data and store it in an hdf_genvec
627 if (SDgetdimscale(dim_id, data) < 0) {
628 delete[]data; // problem: clean up and throw an exception
629 THROW(hcerr_sdsinfo);
630 }
631
632 if (_slab.set) {
633 void *datastart = data +
634 _slab.start[_dim_index] * DFKNTsize(number_type);
635 hd.scale = hdf_genvec(number_type, datastart, 0,
636 _slab.edge[_dim_index] *
637 _slab.stride[_dim_index] - 1,
638 _slab.stride[_dim_index]);
639 } else
640 hd.scale = hdf_genvec(number_type, data, count);
641
642 delete[]data; // deallocate temporary C array
643 }
644 }
645 // assign dim size; if slabbing is set, assigned calculated size,
646 // otherwise assign size from SDdiminfo()
647 if (_slab.set)
648 hd.count = _slab.edge[_dim_index];
649 else
650 hd.count = count;
651 _dim_index++;
652 }
653 catch(...) {
654 _slab = s;
655 throw;
656 }
657
658 _slab = s; // reset _slab
659
660 return *this;
661}
662
663// load attribute currently positioned at
664hdfistream_sds & hdfistream_sds::operator>>(hdf_attr & ha)
665{
666
667 // delete any previous data in ha
668 ha.name = string();
669 ha.values = hdf_genvec();
670
671 if (_filename.size() == 0) // no file open
672 THROW(hcerr_invstream);
673 if (eo_attr()) // if positioned past last attribute, do nothing
674 return *this;
675
676 // prepare to read attribute information: set nattrs, id depending on whether
677 // reading file attributes or SDS attributes
678 int32 id;
679 if (bos()) { // if at BOS, then read file attributes
680 id = _file_id;
681 } else { // else read SDS attributes
682 id = _sds_id;
683 }
684 char name[hdfclass::MAXSTR];
685 int32 number_type;
686 int32 count;
687
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 auto data = new char[count * DFKNTsize(number_type)];
693 if (data == nullptr)
694 THROW(hcerr_nomemory);
695
696 // read attribute values and store them in an hdf_genvec
697 if (SDreadattr(id, _attr_index, data) < 0) {
698 delete[]data; // problem: clean up and throw an exception
699 THROW(hcerr_sdsinfo);
700 }
701 // eliminate trailing null characters from the data string;
702 // they cause GNU's String class problems
703 // NOTE: removed because count=0 if initial char is '\0' and we're not
704 // using GNU String anymore
705#if 0
706 if (number_type == DFNT_CHAR)
707 count = (int32) min((int) count, (int) strlen((char *) data));
708#endif
709
710 if (count > 0) {
711 ha.values = hdf_genvec(number_type, data, count);
712 }
713 delete[]data; // deallocate temporary C array
714
715 // increment attribute index to next attribute
716 ++_attr_index;
717 ha.name = name; // assign attribute name
718 return *this;
719}
720
721// This function, when compiled with gcc 2.8 and -O2, causes a virtual
722// Memory exceeded error. 2/25/98 jhrg
723// read in all the SDS arrays in a file
724hdfistream_sds & hdfistream_sds::operator>>(vector < hdf_sds > &hsv)
725{
726 // hsv = vector<hdf_sds>0; // reset vector
727 for (hdf_sds sds; !eos();) {
728 *this >> sds;
729 hsv.push_back(sds);
730 }
731 return *this;
732}
733
734// read in all of the SDS attributes for currently open SDS
735hdfistream_sds & hdfistream_sds::operator>>(vector < hdf_attr > &hav)
736{
737 // hav = vector<hdf_attr>0; // reset vector
738 for (hdf_attr att; !eo_attr();) {
739 *this >> att;
740 hav.push_back(att);
741 }
742 return *this;
743}
744
745// read in all of the SDS dimensions for currently open SDS
746hdfistream_sds & hdfistream_sds::operator>>(vector < hdf_dim > &hdv)
747{
748 // hdv = vector<hdf_dim>0; // reset vector
749 for (hdf_dim dim; !eo_dim();) {
750 *this >> dim;
751 hdv.push_back(dim);
752 }
753 return *this;
754}
755
756// Check to see if this hdf_sds has a dim scale: if all of the dimensions have
757// scale sizes = to their size, it does
758bool hdf_sds::has_scale(void) const
759{
760 bool has_scale;
761 if (!_ok(&has_scale)) {
762 THROW(hcerr_sdsscale);
763 return false;
764 } else
765 return has_scale;
766}
767
768// Verify that the hdf_sds is in an OK state (i.e., that it is initialized
769// correctly) if user has passed a ptr to a bool then set that to whether
770// there is a dimension scale for at least one of the dimensions
771//
772// Added `if (*has_scale)...' because `has_scale' defaults to null and
773// dereferencing it causes segmentation faults, etc.
774
775bool hdf_sds::_ok(bool * has_scale) const
776{
777
778 if (has_scale)
779 *has_scale = false;
780
781 // Check to see that for each SDS dimension scale, that the length of the
782 // scale matches the size of the dimension.
783 for (const auto & dim:dims)
784 if (dim.scale.size() != 0) {
785 if (has_scale)
786 *has_scale = true;
787 if (dim.scale.size() != dim.count)
788 return false;
789 }
790
791 return true;
792}