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