bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
gri.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: Isaac.C.Henry@jpl.nasa.gov
39//
40// $RCSfile: gri.cc,v $ - input stream class for HDF GR
41//
43
44#include "config_hdf.h"
45
46#include <mfhdf.h>
47#include <mfgr.h>
48
49#ifdef __POWERPC__
50#undef isascii
51#endif
52
53#include <string>
54#include <cstring>
55#include <vector>
56
57#include <hcstream.h>
58#include <hdfclass.h>
59#include <hcerr.h>
60
61// minimum function
62inline int min(int t1, int t2)
63{
64 return (t1 < t2 ? t1 : t2);
65}
66
67// initialize a hdfistream_gri
68void hdfistream_gri::_init(void)
69{
70 _ri_id = _attr_index = _pal_index = 0;
71 _npals = _nri = _nattrs = _nfattrs = _gr_id = _file_id = 0;
72 _index = _interlace_mode = -1;
73 _meta = _slab.set = false;
74 return;
75}
76
77// retrieve descriptive information about the file containing RI
78void hdfistream_gri::_get_fileinfo(void)
79{
80 if (GRfileinfo(_gr_id, &_nri, &_nfattrs) < 0)
81 THROW(hcerr_griinfo);
82 return;
83}
84
85// retrieve information about open raster image
86void hdfistream_gri::_get_iminfo(void)
87{
88 char junk0[hdfclass::MAXSTR];
89 int32 junk1, junk2, junk3, junk4[2];
90 if (GRgetiminfo(_ri_id, junk0, &junk1, &junk2, &junk3, junk4, &_nattrs)
91 < 0)
92 THROW(hcerr_griinfo);
93 else { // find out how many palettes are associated with the image
94 GRgetlutinfo(GRgetlutid(_ri_id, 0), &junk1, &junk2, &junk3,
95 &junk1);
96 if (junk2 == 0)
97 _npals = 0;
98 else
99 _npals = 1;
100 }
101 return;
102}
103
104// end access to open raster image
105void hdfistream_gri::_close_ri(void)
106{
107 if (_ri_id != 0) {
108 GRendaccess(_ri_id);
109 _ri_id = _attr_index = _pal_index = _nattrs = 0;
110 _index = -1;
111 }
112 return;
113}
114
115// constructor
116hdfistream_gri::hdfistream_gri(const string& filename):hdfistream_obj
117 (filename)
118{
119 _init();
120 if (_filename.size() != 0)
121 hdfistream_gri::open(_filename.c_str());
122 return;
123}
124
125// open the GRI input stream
126void hdfistream_gri::open(const char *filename)
127{
128 if (filename == nullptr) // no filename given
129 THROW(hcerr_openfile);
130 if (_file_id != 0) // close any currently open file
131 close();
132 if ((_file_id = Hopen((char *) filename, DFACC_RDONLY, 0)) < 0)
133 THROW(hcerr_openfile);
134 _filename = filename; // assign filename
135 if ((_gr_id = GRstart(_file_id)) < 0)
136 THROW(hcerr_openfile);
137 _get_fileinfo(); // get file information
138 rewind(); // position at BOS to start
139 return;
140}
141
142// close the stream, by ending the GRI interface and closing the file
143void hdfistream_gri::close(void)
144{
145 _close_ri();
146 if (_gr_id != 0)
147 GRend(_gr_id);
148 if (_file_id != 0)
149 Hclose(_file_id);
150 _file_id = _gr_id = 0;
151 _nri = _nfattrs = 0;
152 return;
153}
154
155// position to the stream to the index'th image
156void hdfistream_gri::seek(int index)
157{
158 if (_filename.size() == 0) // no file open
159 THROW(hcerr_invstream);
160 _close_ri();
161 _index = index;
162 _ri_id = GRselect(_gr_id, _index);
163 if (!eos() && !bos())
164 _get_iminfo();
165}
166
167// position GRI stream to RI with name "name"
168void hdfistream_gri::seek(const char *name)
169{
170 if (_filename.size() == 0) // no open file
171 THROW(hcerr_invstream);
172 int32 index = GRnametoindex(_gr_id, (char *) name);
173 seek(index);
174}
175
176// position GRI stream to RI with reference "ref"
177void hdfistream_gri::seek_ref(int ref)
178{
179 if (_filename.size() == 0) // no open file
180 THROW(hcerr_invstream);
181 int32 index = GRreftoindex(_gr_id, (uint16)ref);
182 seek(index);
183}
184
185// position GRI index in front of first RI
186void hdfistream_gri::rewind(void)
187{
188 if (_filename.size() == 0) // no file open
189 THROW(hcerr_invstream);
190 _close_ri(); // close any already open RI's
191 _rewind(); // seek to BOS
192}
193
194// check to see if stream is positioned in front of
195// the first RI in the file
196bool hdfistream_gri::bos(void) const
197{
198 if (_filename.size() == 0) // no file open
199 THROW(hcerr_invstream);
200 if (_nri == 0)
201 return false;
202 if (_index == -1)
203 return true;
204 else
205 return false;
206}
207
208// check to see if stream has been positioned
209// past the last RI in the file
210bool hdfistream_gri::eos(void) const
211{
212 if (_filename.size() == 0) // no file open
213 THROW(hcerr_invstream);
214 if (_nri == 0)
215 return true;
216 else {
217 if (bos())
218 return false;
219 else
220 return (_index >= _nri);
221 }
222}
223
224// Check to see if stream is positioned past the last
225// attribute in the currently open RI
226bool hdfistream_gri::eo_attr(void) const
227{
228 if (_filename.size() == 0)
229 THROW(hcerr_invstream);
230 if (eos())
231 return true;
232 else {
233 if (bos())
234 return (_attr_index >= _nfattrs);
235 else
236 return (_attr_index >= _nattrs);
237 }
238}
239
240// Set interlace type for read into memory
241void hdfistream_gri::setinterlace(int32 interlace_mode)
242{
243 if (interlace_mode == MFGR_INTERLACE_PIXEL ||
244 interlace_mode == MFGR_INTERLACE_COMPONENT ||
245 interlace_mode == MFGR_INTERLACE_LINE)
246 _interlace_mode = interlace_mode;
247 else
248 THROW(hcerr_interlace);
249}
250
251// check to see if stream is positioned past the last palette
252// in the currently open RI
253bool hdfistream_gri::eo_pal(void) const
254{
255 if (_filename.size() == 0)
256 THROW(hcerr_invstream);
257 if (eos())
258 return true;
259 else {
260 if (bos())
261 return true;
262 else
263 return (_pal_index >= _npals);
264 }
265}
266
267// set slab parameters
268void hdfistream_gri::setslab(vector < int >start, vector < int >edge,
269 vector < int >stride, bool reduce_rank)
270{
271 // check validity of input
272 if (start.size() != edge.size() || edge.size() != stride.size() ||
273 start.size() == 0)
274 THROW(hcerr_invslab);
275
276 if (start.size() == 3) {
277 // erase # of components, if present: only X and Y subsetting allowed
278 start.erase(start.begin());
279 edge.erase(edge.begin());
280 stride.erase(stride.begin());
281 }
282
283 for (int i = 0; i < 2; ++i) {
284 if (start[i] < 0)
285 THROW(hcerr_invslab);
286 if (edge[i] <= 0)
287 THROW(hcerr_invslab);
288 if (stride[i] <= 0)
289 THROW(hcerr_invslab);
290 // swap the X and Y dimensions because DODS prints data in [y][x] form
291 // but HDF wants dimensions in [x][y]
292 _slab.start[1 - i] = start[i];
293 _slab.edge[1 - i] = edge[i];
294 _slab.stride[1 - i] = stride[i];
295 }
296 _slab.set = true;
297 _slab.reduce_rank = reduce_rank;
298}
299
300// read a single RI
301hdfistream_gri & hdfistream_gri::operator>>(hdf_gri & hr)
302{
303 if (_filename.size() == 0) // no file open
304 THROW(hcerr_invstream); // is this the right thing to throw?
305 // delete any prevous data in hr
306 hr.palettes = vector < hdf_palette > ();
307 hr.attrs = vector < hdf_attr > ();
308 hr.image = hdf_genvec();
309 hr.name = string();
310 if (bos())
311 seek(0);
312 if (eos())
313 return *this;
314 // get basic info about RI
315 char name[hdfclass::MAXSTR];
316 int32 ncomp;
317 int32 data_type;
318 int32 il;
319 int32 dim_sizes[2];
320 int32 nattrs;
321 if (GRgetiminfo
322 (_ri_id, name, &ncomp, &data_type, &il, dim_sizes, &nattrs) < 0)
323 THROW(hcerr_griinfo);
324 hr.ref = GRidtoref(_ri_id);
325 hr.name = name;
326 hr.dims[0] = dim_sizes[0];
327 hr.dims[1] = dim_sizes[1];
328 hr.num_comp = ncomp;
329 if (_interlace_mode == -1) {
330 setinterlace(il);
331 hr.interlace = il;
332 }
333 /* read in palettes */
334 *this >> hr.palettes;
335 *this >> hr.attrs;
336 if (_meta)
337 hr.image.import_vec(data_type);
338 else {
339 int32 nelts;
340 char *image;
341 if (_slab.set) {
342 nelts = _slab.edge[0] * _slab.edge[1] * ncomp;
343 // allocate a temporary C array to hold the data from GRreadimage()
344 int imagesize = nelts * DFKNTsize(data_type);
345 image = new char[imagesize];
346 if (image == nullptr)
347 THROW(hcerr_nomemory);
348 // read the image and store it in a hdf_genvec
349 GRreqimageil(_ri_id, _interlace_mode);
350#if 0
351 cerr << "ncomp: " << ncomp << " imagesize: " << imagesize <<
352 endl;
353 cerr << "_slab.start = " << _slab.start[0] << "," << _slab.
354 start[1] << " _slab.edge = " << _slab.
355 edge[0] << "," << _slab.
356 edge[1] << " _slab.stride = " << _slab.
357 stride[0] << "," << _slab.stride[1] << endl;
358#endif
359 if (GRreadimage
360 (_ri_id, _slab.start, _slab.stride, _slab.edge,
361 image) < 0) {
362 delete[]image; // problem: clean up and throw an exception
363 THROW(hcerr_griread);
364 }
365 } else {
366 int32 zero[2];
367 zero[0] = zero[1] = 0;
368 nelts = dim_sizes[0] * dim_sizes[1] * ncomp;
369 // allocate a temporary C array to hold the data from GRreadimage()
370 int imagesize = nelts * DFKNTsize(data_type);
371 image = new char[imagesize];
372 if (image == nullptr)
373 THROW(hcerr_nomemory);
374 // read the image and store it in a hdf_genvec
375 GRreqimageil(_ri_id, _interlace_mode);
376#if 0
377 cerr << "dim_sizes[0] = " << dim_sizes[0] << " dim_sizes[1] = "
378 << dim_sizes[1] << endl;
379#endif
380 if (GRreadimage(_ri_id, zero, nullptr, dim_sizes, image) < 0) {
381 delete[]image; // problem: clean up and throw an exception
382 THROW(hcerr_griread);
383 }
384 }
385 hr.image.import_vec(data_type, image, nelts);
386 delete[]image; // deallocate temporary C array
387 }
388 seek_next(); // position to next RI
389 return *this;
390}
391
392// read in all the RI's in a file
393hdfistream_gri & hdfistream_gri::operator>>(vector < hdf_gri > &hrv)
394{
395 for (hdf_gri gri; !eos();) {
396 *this >> gri;
397 hrv.push_back(gri);
398 }
399 return *this;
400}
401
402// load attribute currently positioned at
403hdfistream_gri & hdfistream_gri::operator>>(hdf_attr & ha)
404{
405 if (_filename.size() == 0)
406 THROW(hcerr_invstream);
407 if (eo_attr())
408 return *this;
409 // prepare to read attribute information: set nattrs depending on whether
410 // reading file attributes or GRI attributes
411 int32 id;
412 //int nattrs;
413 if (bos()) {
414 id = _gr_id;
415 } else {
416 id = _ri_id;
417 }
418 char name[hdfclass::MAXSTR];
419 int32 number_type;
420 int32 count;
421 if (GRattrinfo(id, _attr_index, name, &number_type, &count) < 0)
422 THROW(hcerr_griinfo);
423 // allocate a temporary C array to hold data from GRgetattr()
424 char *data;
425 data = new char[count * DFKNTsize(number_type)];
426 if (data == nullptr)
427 THROW(hcerr_nomemory);
428 // read attribute values and store them in an hdf_genvec
429 if (GRgetattr(id, _attr_index, data) < 0) {
430 delete[]data; // problem: clean up
431 THROW(hcerr_griinfo);
432 }
433 // eliminate trailing null characters from the data string
434 // they cause GNU's string class problems
435 if (number_type == DFNT_CHAR)
436 count = (int32) min((int) count, (int) strlen((char *) data));
437 if (count > 0) {
438 ha.values.import_vec(number_type, data, count);
439 }
440 delete[]data;
441 ++_attr_index;
442 ha.name = name;
443 return *this;
444}
445
446// read in all of the GRI attributes for currently open RI
447hdfistream_gri & hdfistream_gri::operator>>(vector < hdf_attr > &hav)
448{
449 for (hdf_attr att; !eo_attr();) {
450 *this >> att;
451 hav.push_back(att);
452 }
453 _attr_index = 0;
454 return *this;
455}
456
457hdfistream_gri & hdfistream_gri::operator>>(hdf_palette & hp)
458{
459 if (_filename.size() == 0) // no file open
460 THROW(hcerr_invstream);
461 if (eo_pal()) // if positioned past last dimension, do nothing
462 return *this;
463 // open palette currently positioned at and increment pal index
464 int32 pal_id;
465 if ((pal_id = GRgetlutid(_ri_id, _pal_index)) < 0)
466 THROW(hcerr_griinfo);
467 // get palette information;
468 int32 ncomp = 0, number_type = 0, num_entries = 0, junk0;
469 if (GRgetlutinfo(pal_id, &ncomp, &number_type, &junk0, &num_entries) <
470 0)
471 THROW(hcerr_griinfo);
472 else {
473 hp.ncomp = ncomp;
474 hp.num_entries = num_entries;
475 }
476 // Note: due to a bug in the HDF library, the palette number type is returned
477 // as DFNT_UCHAR8 instead of DFNT_UINT8. We correct that here because
478 // the current mapping for DFNT_UCHAR8 is string instead of Byte
479 if (number_type == DFNT_UCHAR8)
480 number_type = DFNT_UINT8;
481
482 int32 count = ncomp * num_entries;
483 if (number_type != 0) { // found a palette
484 char *pal_data;
485 pal_data = new char[count * DFKNTsize(number_type)];
486 if (pal_data == nullptr)
487 THROW(hcerr_nomemory);
488 // read the palette data and store it in an hdf_genvec
489 GRreqlutil(pal_id, MFGR_INTERLACE_PIXEL);
490 if (GRreadlut(pal_id, pal_data) < 0) {
491 delete[]pal_data; // problem: clean up and
492 THROW(hcerr_griinfo); // throw an exception
493 }
494 hp.table.import_vec(number_type, pal_data, count);
495 delete[]pal_data; // deallocating temporary C array
496 }
497 ++_pal_index;
498 return *this;
499}
500
501// read in all of the RI palettes for the currently open RI
502hdfistream_gri & hdfistream_gri::operator>>(vector < hdf_palette > &hpv)
503{
504 for (hdf_palette pal; !eo_pal();) {
505 *this >> pal;
506 hpv.push_back(pal);
507 }
508 return *this;
509}
510
511// Verify that the hdf_gri is in an OK state (i.e., that it is initialized correctly)
512// if user has passed a ptr to a bool then set that to whether there is a dimension
513// scale
514bool hdf_gri::_ok() const
515{
516 // The image should have the same number of components as indicated
517 // by the number of dimensions and number of componets
518 bool ok = (dims[0] * dims[1] * num_comp == image.size());
519 if (!ok)
520 return ok;
521 if (has_palette())
522 for (int i = 0; i < int (palettes.size()) && ok; i++)
523 ok = (palettes[i].ncomp * palettes[i].num_entries ==
524 palettes[i].table.size());
525 return ok;
526}
527
528// $Log: gri.cc,v $
529// Revision 1.9.4.1.2.1 2004/02/23 02:08:03 rmorris
530// There is some incompatibility between the use of isascii() in the hdf library
531// and its use on OS X. Here we force in the #undef of isascii in the osx case.
532//
533// Revision 1.9.4.1 2003/05/21 16:26:58 edavis
534// Updated/corrected copyright statements.
535//
536// Revision 1.9 2003/01/31 02:08:37 jimg
537// Merged with release-3-2-7.
538//
539// Revision 1.8.4.2 2002/12/18 23:32:50 pwest
540// gcc3.2 compile corrections, mainly regarding the using statement. Also,
541// missing semicolon in .y file
542//
543// Revision 1.8.4.1 2001/10/30 06:36:35 jimg
544// Added genvec::append(...) method.
545// Fixed up some comments in genvec.
546// Changed genvec's data member from void * to char * to quell warnings
547// about void * being passed to delete.
548//
549// Revision 1.8 2000/10/09 19:46:19 jimg
550// Moved the CVS Log entries to the end of each file.
551// Added code to catch Error objects thrown by the dap library.
552// Changed the read() method's definition to match the dap library.
553//
554// Revision 1.7 2000/03/31 16:56:05 jimg
555// Merged with release 3.1.4
556//
557// Revision 1.6.8.1 2000/03/20 23:26:07 jimg
558// Removed debugging output
559//
560// Revision 1.6 1999/05/06 03:23:33 jimg
561// Merged changes from no-gnu branch
562//
563// Revision 1.5 1999/05/05 23:33:43 jimg
564// String --> string conversion
565//
566// Revision 1.4.6.1 1999/05/06 00:35:45 jimg
567// Jakes String --> string changes
568//
569// Revision 1.4 1998/09/10 21:50:22 jehamby
570// Fix subsetting for multi-component GR (Note: due to an HDF library bug,
571// you can't actually subset a GR with >1 component, but at least retrieving
572// the entire image works). Also, remove debugging output and work around
573// another HDF bug so palettes output as Byte instead of string.
574//
575// Revision 1.3 1998/07/13 20:26:35 jimg
576// Fixes from the final test of the new build process
577//
578// Revision 1.2.4.1 1998/05/22 19:50:51 jimg
579// Patch from Jake Hamby to support subsetting raster images
580//
581// Revision 1.2 1998/04/03 18:34:17 jimg
582// Fixes for vgroups and Sequences from Jake Hamby
583//
584// Revision 1.1 1996/10/31 18:42:58 jimg
585// Added.
586//
587// Revision 1.10 1996/09/20 20:25:48 ike
588// Changed meta behavior for rasters. Palletes are now read when meta is true.
589//
590// Revision 1.9 1996/09/20 18:28:40 ike
591// Fixed GR reading to read images in there native interace by default.
592//
593// Revision 1.8 1996/09/20 17:49:55 ike
594// Added setinterlace() to set the interlace type for reading images.
595// Used GRreqlutil to for palletes to be read in pixel interlace.
596//
597// Revision 1.7 1996/08/22 20:56:36 todd
598// Corrected bug in destructor. Cleaned up initializations.
599//
600// Revision 1.6 1996/07/22 17:15:09 todd
601// Const-corrected hdfistream_gri::seek() routine.
602//
603// Revision 1.5 1996/06/18 22:06:19 ike
604// Removed default argument values from argument lists.
605//
606// Revision 1.4 1996/06/18 01:13:20 ike
607// Fixed infinite loop caused by problem incrementing _nattrs, _nfattrs.
608// Added _ok(), !operator, and has_palette to hdf_gri.
609//
610// Revision 1.3 1996/06/18 00:57:13 todd
611// Added hcerr.h include at top of module.
612//
613// Revision 1.2 1996/06/14 21:58:45 ike
614// fixed operator>> to overwrite non vectors objects.
615//
616// Revision 1.1 1996/06/14 21:53:09 ike
617// Initial revision
618//